├── config.cmake.in ├── include ├── myarray.h ├── dbShell.h ├── database.h ├── bprinter │ ├── impl │ │ └── table_printer.tpp.h │ └── table_printer.h └── dbCore.h ├── sql.l ├── table_printer.cpp ├── CMakeLists.txt ├── test.cpp ├── dbShell.cpp ├── README.md ├── sql.y └── dbCore.cpp /config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | set_and_check(BPRINTER_INCLUDE_DIR "@PACKAGE_BP_INCLUDE_INSTALL_DIR@") 3 | set_and_check(BPRINTER_LIBRARY_DIR "@PACKAGE_BP_LIB_INSTALL_DIR@") 4 | -------------------------------------------------------------------------------- /include/myarray.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 93773 on 2019/5/9. 3 | // 4 | 5 | #ifndef MYSQL_ARRAY_H 6 | 7 | #include 8 | #include 9 | #define MYSQL_ARRAY_H 10 | using namespace std; 11 | struct arrayNode{ 12 | enum type{ 13 | INTNODE, 14 | CHNODE 15 | } type; 16 | string val; 17 | }; 18 | 19 | class myarray { 20 | vector nodes; 21 | public: 22 | void push(char* val); 23 | void push(int val); 24 | myarray operator+(const myarray&); 25 | vector get(); 26 | void print(); 27 | }; 28 | 29 | 30 | #endif //MYSQL_ARRAY_H 31 | -------------------------------------------------------------------------------- /include/dbShell.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 93773 on 2019/5/14. 3 | // 4 | 5 | #ifndef MYSQL_DBSHELL_H 6 | #define MYSQL_DBSHELL_H 7 | 8 | #include 9 | 10 | 11 | class dbShell { 12 | public: 13 | void CreateDatabase(char * DatabaseName); 14 | void ShowDatabases(); 15 | void ShowTables(); 16 | void dropTable(char * tableName); 17 | void DropDatabases(char * DatabaseName); 18 | void UseDatabase(char * DatabaseName); 19 | void CreateTable(char * tableName, table_field_node * tfn); 20 | 21 | void sqlInsert(insert_node * insertNode); 22 | void select(select_node * selectNode); 23 | 24 | void sqldelete(select_node * selectNode); 25 | void sqlupdate(update_node * updateNode); 26 | dbShell(); 27 | ~dbShell(); 28 | 29 | private: 30 | Core core; 31 | }; 32 | 33 | 34 | #endif //MYSQL_DBSHELL_H 35 | -------------------------------------------------------------------------------- /include/database.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 93773 on 2019/5/7. 3 | // 4 | 5 | #ifndef MYSQL_DATABASE_H 6 | #define MYSQL_DATABASE_H 7 | 8 | #endif //MYSQL_DATABASE_H 9 | #include 10 | #include 11 | #include 12 | #include 13 | using namespace std; 14 | 15 | class column { 16 | public: 17 | string columnName; 18 | int columnType; 19 | int columnSize; 20 | }; 21 | 22 | struct recordNode { 23 | int nodeType; 24 | string charval; 25 | int intval; 26 | }; 27 | 28 | class Table { 29 | private: 30 | vector> result; 31 | public: 32 | string name; 33 | vector columns; 34 | vector> records; 35 | }; 36 | 37 | class Database { 38 | private: 39 | map tables; 40 | vector columnsNow; 41 | public: 42 | string name; 43 | void createTable(char * tableName); 44 | void addColumn(char* columnName, int columnType, int size = 0); 45 | void showTables(); 46 | void droptable(char * tableName); 47 | 48 | }; 49 | 50 | class DBDriver { 51 | map databases; 52 | Database * databaseInUse; 53 | public: 54 | DBDriver(){ 55 | cout << "======================" << endl; 56 | cout << " my mini mysql " << endl; 57 | cout << "======================" << endl; 58 | createDatabase("default"); 59 | useDB("default"); 60 | } 61 | void createDatabase(char * databaseName); 62 | void useDB(char * databaseName); 63 | Database * getDB(); 64 | void showDatabases(); 65 | void dropDatabase(char * databaseName); 66 | 67 | 68 | 69 | 70 | 71 | }; -------------------------------------------------------------------------------- /sql.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include 4 | #include "dbCore.h" 5 | #include "sql.tab.h" 6 | #include 7 | int cur_line = 1; 8 | %} 9 | 10 | CREATE CREATE|create 11 | SHOW SHOW|show 12 | DROP DROP|drop 13 | USE USE|use 14 | DATABASE DATABASE|database 15 | DATABASES DATABASES|databases 16 | TABLE TABLE|table 17 | TABLES TABLES|tables 18 | CHAR CHAR|char 19 | INT INT|int 20 | FROM from|FROM 21 | SELECT SELECT|select 22 | WHERE WHERE|where 23 | AND AND|and 24 | OR OR|or 25 | INSERT INSERT|insert 26 | INTO INTO|into 27 | VALUES VALUES|VALUES 28 | DELETE DELETE|delete 29 | UPDATE UPDATE|update 30 | SET SET|set 31 | ID [a-zA-Z][a-zA-Z_0-9]* 32 | NUMBER [-+]?[0-9][0-9]* 33 | STRING '.*' 34 | 35 | %% 36 | {CHAR} {yylval.typeval = CHAR; return CHAR; } 37 | {INT} {yylval.typeval = INT; return INT;} 38 | 39 | {CREATE} { return CREATE;} 40 | {SHOW} {return SHOW; } 41 | {DROP} {return DROP; } 42 | {USE} {return USE;} 43 | {TABLE} {return TABLE;} 44 | {TABLES} { return TABLES;} 45 | {DATABASE} { return DATABASE;} 46 | {DATABASES} { return DATABASES;} 47 | 48 | 49 | {SELECT} {return SELECT;} 50 | {FROM} {return FROM;} 51 | {WHERE} {return WHERE;} 52 | {AND} {return AND;} 53 | {OR} {return OR;} 54 | 55 | {INSERT} {return INSERT;} 56 | {INTO} {return INTO;} 57 | {VALUES} {return VALUES;} 58 | 59 | {DELETE} {return DELETE;} 60 | {UPDATE} {return UPDATE;} 61 | {SET} {return SET;} 62 | 63 | 64 | {ID} { yylval.chval = strdup(yytext); return ID;} 65 | {NUMBER} {yylval.intval = atoi(yytext); return NUMBER;} 66 | "(" { return '('; } 67 | ")" { return ')'; } 68 | ";" { return ';'; } 69 | "," { return ','; } 70 | "*" { return '*'; } 71 | "." { return '.'; } 72 | "<" { return '<'; } 73 | ">" { return '>'; } 74 | "=" { return '='; } 75 | "!" { return '!'; } 76 | 77 | \n { cur_line++; } 78 | {STRING} {*(yytext+strlen(yytext)-1) = '\0'; yylval.chval = strdup(yytext+1); return STRING;} 79 | [ \t]+ /* ignore whitespace */; 80 | "//".* { /* DO NOTHING */ } 81 | %% 82 | 83 | int yywrap()//此函数必须由用户提供 84 | { 85 | return 1; 86 | } -------------------------------------------------------------------------------- /include/bprinter/impl/table_printer.tpp.h: -------------------------------------------------------------------------------- 1 | #if defined(USE_BOOST_KARMA) 2 | #include 3 | namespace karma = boost::spirit::karma; 4 | #endif 5 | 6 | namespace bprinter{ 7 | #if defined(USE_BOOST_KARMA) 8 | template void TablePrinter::OutputDecimalNumber(T input){ 9 | *out_stream_ << karma::format( 10 | karma::maxwidth(column_widths_.at(j_))[ 11 | karma::right_align(column_widths_.at(j_))[ 12 | karma::double_ 13 | ] 14 | ], input 15 | ); 16 | 17 | if (j_ == get_num_columns()-1){ 18 | *out_stream_ << "|\n"; 19 | i_ = i_ + 1; 20 | j_ = 0; 21 | } else { 22 | *out_stream_ << separator_; 23 | j_ = j_ + 1; 24 | } 25 | } 26 | #else 27 | template void TablePrinter::OutputDecimalNumber(T input){ 28 | // If we cannot handle this number, indicate so 29 | if (input < 10*(column_widths_.at(j_)-1) || input > 10*column_widths_.at(j_)){ 30 | std::stringstream string_out; 31 | string_out << std::setiosflags(std::ios::fixed) 32 | << std::setprecision(column_widths_.at(j_)) 33 | << std::setw(column_widths_.at(j_)) 34 | << input; 35 | 36 | std::string string_rep_of_number = string_out.str(); 37 | 38 | string_rep_of_number[column_widths_.at(j_)-1] = '*'; 39 | std::string string_to_print = string_rep_of_number.substr(0, column_widths_.at(j_)); 40 | *out_stream_ << string_to_print; 41 | } else { 42 | 43 | // determine what precision we need 44 | int precision = column_widths_.at(j_) - 1; // leave room for the decimal point 45 | if (input < 0) 46 | --precision; // leave room for the minus sign 47 | 48 | // leave room for digits before the decimal? 49 | if (input < -1 || input > 1){ 50 | int num_digits_before_decimal = 1 + (int)log10(std::abs(input)); 51 | precision -= num_digits_before_decimal; 52 | } 53 | else 54 | precision --; // e.g. 0.12345 or -0.1234 55 | 56 | if (precision < 0) 57 | precision = 0; // don't go negative with precision 58 | 59 | *out_stream_ << std::setiosflags(std::ios::fixed) 60 | << std::setprecision(precision) 61 | << std::setw(column_widths_.at(j_)) 62 | << input; 63 | } 64 | 65 | if (j_ == get_num_columns()-1){ 66 | *out_stream_ << "|\n"; 67 | i_ = i_ + 1; 68 | j_ = 0; 69 | } else { 70 | *out_stream_ << separator_; 71 | j_ = j_ + 1; 72 | } 73 | } 74 | #endif //USE_BOOST_KARMA 75 | } 76 | -------------------------------------------------------------------------------- /table_printer.cpp: -------------------------------------------------------------------------------- 1 | #include "include/bprinter/table_printer.h" 2 | #include 3 | #include 4 | #include 5 | 6 | namespace bprinter { 7 | TablePrinter::TablePrinter(std::ostream * output, const std::string & separator){ 8 | out_stream_ = output; 9 | i_ = 0; 10 | j_ = 0; 11 | separator_ = separator; 12 | table_width_ = 0; 13 | flush_left_ = false; 14 | } 15 | 16 | TablePrinter::~TablePrinter(){ 17 | 18 | } 19 | 20 | int TablePrinter::get_num_columns() const { 21 | return column_headers_.size(); 22 | } 23 | 24 | int TablePrinter::get_table_width() const { 25 | return table_width_; 26 | } 27 | 28 | void TablePrinter::set_separator(const std::string &separator){ 29 | separator_ = separator; 30 | } 31 | 32 | void TablePrinter::set_flush_left(){ 33 | flush_left_ = true; 34 | } 35 | 36 | void TablePrinter::set_flush_right(){ 37 | flush_left_ = false; 38 | } 39 | 40 | /** \brief Add a column to our table 41 | ** 42 | ** \param header_name Name to be print for the header 43 | ** \param column_width the width of the column (has to be >=5) 44 | ** */ 45 | void TablePrinter::AddColumn(const std::string & header_name, int column_width){ 46 | if (column_width < 4){ 47 | throw std::invalid_argument("Column size has to be >= 4"); 48 | } 49 | 50 | column_headers_.push_back(header_name); 51 | column_widths_.push_back(column_width); 52 | table_width_ += column_width + separator_.size(); // for the separator 53 | } 54 | 55 | void TablePrinter::PrintHorizontalLine() { 56 | *out_stream_ << "+"; // the left bar 57 | 58 | for (int i=0; i(input); 92 | return *this; 93 | } 94 | 95 | TablePrinter& TablePrinter::operator<<(double input){ 96 | OutputDecimalNumber(input); 97 | return *this; 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | project(mysql VERSION 1.0.0) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | # Boost Karma (part of Boost Spirir) has ability to handle output 7 | option(USE_BOOST_KARMA "Use Boost Karma for output instead of doing it ourselves?" ON) 8 | if(USE_BOOST_KARMA) 9 | find_package(Boost) 10 | if (Boost_FOUND) 11 | add_definitions("-DUSE_BOOST_KARMA") 12 | endif (Boost_FOUND) 13 | endif(USE_BOOST_KARMA) 14 | include_directories(${PROJECT_SOURCE_DIR}/include) 15 | add_library(bprinter STATIC 16 | include/bprinter/table_printer.h 17 | include/bprinter/impl/table_printer.tpp.h 18 | table_printer.cpp 19 | include/database.h 20 | ) 21 | add_executable(mysql database.cpp include/database.h sql.tab.cpp sql.tab.h myarray.cpp include/myarray.h dbCore.cpp include/dbCore.h test.cpp dbShell.cpp include/dbShell.h) 22 | add_custom_command(OUTPUT sql.tab.cpp 23 | COMMAND bison -t ${PROJECT_SOURCE_DIR}/sql.y 24 | COMMAND flex ${PROJECT_SOURCE_DIR}/sql.l 25 | COMMAND move ${CMAKE_BINARY_DIR}\\sql.tab.c ${CMAKE_BINARY_DIR}\\sql.tab.cpp) 26 | target_link_libraries(mysql bprinter) 27 | add_custom_command(TARGET mysql 28 | POST_BUILD 29 | COMMAND move ${CMAKE_BINARY_DIR}\\sql.tab.cpp ${CMAKE_BINARY_DIR}\\sql.tab.c) 30 | 31 | set(BP_TARGET_NAME ${PROJECT_NAME}) 32 | set(BP_PACKAGE_NAME ${BP_TARGET_NAME}) 33 | set(BP_CONFIG_IN_FILENAME "config.cmake.in") 34 | set(BP_CONFIG_FILENAME "${BP_PACKAGE_NAME}Config.cmake") 35 | set(BP_CONFIGVERSION_FILENAME "${BP_PACKAGE_NAME}ConfigVersion.cmake") 36 | set(BP_CONFIG_DESTINATION "cmake") 37 | set(BP_INCLUDE_INSTALL_DIR "include/bprinter") 38 | set(BP_LIB_INSTALL_DIR lib) 39 | 40 | include(CMakePackageConfigHelpers) 41 | configure_package_config_file(${BP_CONFIG_IN_FILENAME} ${CMAKE_CURRENT_BINARY_DIR}/${BP_CONFIG_FILENAME} 42 | INSTALL_DESTINATION ${BP_CONFIG_DESTINATION} 43 | PATH_VARS BP_INCLUDE_INSTALL_DIR BP_LIB_INSTALL_DIR) 44 | write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${BP_CONFIGVERSION_FILENAME} 45 | VERSION ${PROJECT_VERSION} 46 | COMPATIBILITY SameMajorVersion) 47 | 48 | INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${BP_CONFIG_FILENAME} ${CMAKE_CURRENT_BINARY_DIR}/${BP_CONFIGVERSION_FILENAME} 49 | DESTINATION ${BP_CONFIG_DESTINATION}) 50 | 51 | INSTALL(TARGETS bprinter 52 | DESTINATION ${BP_LIB_INSTALL_DIR} 53 | PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) 54 | 55 | INSTALL(FILES include/bprinter/table_printer.h 56 | DESTINATION ${BP_INCLUDE_INSTALL_DIR} 57 | PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) 58 | 59 | INSTALL(FILES include/bprinter/impl/table_printer.tpp.h 60 | DESTINATION ${BP_INCLUDE_INSTALL_DIR}/impl 61 | PERMISSIONS OWNER_READ GROUP_READ WORLD_READ) 62 | -------------------------------------------------------------------------------- /include/bprinter/table_printer.h: -------------------------------------------------------------------------------- 1 | #ifndef BPRINTER_TABLE_PRINTER_H_ 2 | #define BPRINTER_TABLE_PRINTER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace bprinter { 12 | class endl{}; 13 | /** \class TablePrinter 14 | 15 | Print a pretty table into your output of choice. 16 | 17 | Usage: 18 | TablePrinter tp(&std::cout); 19 | tp.AddColumn("Name", 25); 20 | tp.AddColumn("Age", 3); 21 | tp.AddColumn("Position", 30); 22 | 23 | tp.PrintHeader(); 24 | tp << "Dat Chu" << 25 << "Research Assistant"; 25 | tp << "John Doe" << 26 << "Professional Anonymity"; 26 | tp << "Jane Doe" << tp.SkipToNextLine(); 27 | tp << "Tom Doe" << 7 << "Student"; 28 | tp.PrintFooter(); 29 | 30 | \todo Add support for padding in each table cell 31 | */ 32 | class TablePrinter{ 33 | public: 34 | TablePrinter(std::ostream * output, const std::string & separator = "|"); 35 | ~TablePrinter(); 36 | 37 | int get_num_columns() const; 38 | int get_table_width() const; 39 | void set_separator(const std::string & separator); 40 | void set_flush_left(); 41 | void set_flush_right(); 42 | 43 | void AddColumn(const std::string & header_name, int column_width); 44 | void PrintHeader(); 45 | void PrintFooter(); 46 | 47 | TablePrinter& operator<<(endl input){ 48 | while (j_ != 0){ 49 | *this << ""; 50 | } 51 | return *this; 52 | } 53 | 54 | // Can we merge these? 55 | TablePrinter& operator<<(float input); 56 | TablePrinter& operator<<(double input); 57 | 58 | template TablePrinter& operator<<(T input){ 59 | if (j_ == 0) 60 | *out_stream_ << "|"; 61 | 62 | if(flush_left_) 63 | *out_stream_ << std::left; 64 | else 65 | *out_stream_ << std::right; 66 | 67 | // Leave 3 extra space: One for negative sign, one for zero, one for decimal 68 | *out_stream_ << std::setw(column_widths_.at(j_)) 69 | << input; 70 | 71 | if (j_ == get_num_columns()-1){ 72 | *out_stream_ << "|\n"; 73 | i_ = i_ + 1; 74 | j_ = 0; 75 | } else { 76 | *out_stream_ << separator_; 77 | j_ = j_ + 1; 78 | } 79 | 80 | return *this; 81 | } 82 | 83 | private: 84 | void PrintHorizontalLine(); 85 | 86 | template void OutputDecimalNumber(T input); 87 | 88 | std::ostream * out_stream_; 89 | std::vector column_headers_; 90 | std::vector column_widths_; 91 | std::string separator_; 92 | 93 | int i_; // index of current row 94 | int j_; // index of current column 95 | 96 | int table_width_; 97 | bool flush_left_; 98 | }; 99 | 100 | } 101 | 102 | #include "impl/table_printer.tpp.h" 103 | #endif 104 | -------------------------------------------------------------------------------- /include/dbCore.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 93773 on 2019/5/14. 3 | // 4 | 5 | #ifndef MYSQL_DBCORE_H 6 | #define MYSQL_DBCORE_H 7 | 8 | #pragma once 9 | #include 10 | #include 11 | #include 12 | #define PAGE_SIZE 2*1024 13 | using namespace std; 14 | 15 | 16 | struct table_field_node { 17 | char * field_name; 18 | enum type { 19 | INT, STRING 20 | }type; 21 | int len; 22 | int offset; 23 | table_field_node * next = nullptr; 24 | }; 25 | 26 | struct table_node { 27 | table_field_node * field = nullptr; 28 | char * tableName; 29 | int beginPage; 30 | table_node * next = nullptr; 31 | }; 32 | 33 | 34 | struct condexp_node { 35 | condexp_node * left = nullptr; 36 | enum op { 37 | AND, OR, EQ, G, B, NOT 38 | }op; 39 | condexp_node * right = nullptr; 40 | enum type { 41 | INT, STRING, COLUM, LOGIC 42 | }type; 43 | int intval; 44 | char * chval; 45 | }; 46 | 47 | 48 | struct select_node { 49 | table_field_node * field = nullptr; 50 | table_node * table = nullptr; 51 | condexp_node * cons = nullptr; 52 | }; 53 | 54 | struct values_node { 55 | enum type { 56 | INT, STRING 57 | }type; 58 | int intval; 59 | char * chval; 60 | values_node * next = nullptr; 61 | }; 62 | struct insert_node { 63 | table_node * table = nullptr; 64 | table_field_node * field = nullptr; 65 | values_node * values = nullptr; 66 | }; 67 | 68 | struct set_value { 69 | char * field_name; 70 | int intval; 71 | char * chval; 72 | set_value * next; 73 | }; 74 | struct update_node { 75 | table_node * table = nullptr; 76 | condexp_node * cons = nullptr; 77 | set_value * setval = nullptr; 78 | }; 79 | 80 | 81 | char * _S(const char * string); 82 | 83 | class Core 84 | { 85 | public: 86 | Core(); 87 | ~Core(); 88 | void addPage(fstream& f); 89 | int createDatabase(const char * databaseName); 90 | int deleteDatabase(char * databaseName); 91 | int useDatabase(const char * databaseName); 92 | int createTable(const char * tableName, table_field_node* tfn); 93 | int deleteTable(const char * tableName); 94 | /* 95 | 获取当前数据库中某个表所有的列 96 | */ 97 | vector getColumn(char * tableName); 98 | 99 | int insert(insert_node * insertNode); 100 | 101 | pair, vector>> 102 | select_single(select_node * selectNode); 103 | 104 | 105 | pair, vector>> 106 | select_mult(select_node * selectNode); 107 | 108 | int sqldelete(select_node * deleteNode); 109 | int sqlupdate(update_node * updateNode); 110 | 111 | 112 | void SysdbInit(); 113 | vector getTables(); 114 | vector getDatabases(); 115 | char * InUseDBName; 116 | 117 | 118 | 119 | private: 120 | static int TEMP[10]; 121 | static char DATPAGE[PAGE_SIZE]; 122 | static char DBPAGE[PAGE_SIZE]; 123 | static char TMPAGE[PAGE_SIZE]; 124 | fstream *sysdb; 125 | fstream *sysdat; 126 | fstream * InUsedb; 127 | fstream * InUsedat; 128 | 129 | int getNewDatPage(fstream &datfile, int PageNow = 0); 130 | int getNextPageNum(); 131 | int readPage(fstream &filestream, int pageNum, char * page = DATPAGE); 132 | int writePage(fstream &filestream, int pageNum, char * page = DATPAGE); 133 | int getWriteablePageNum(fstream &filestream, int pageNum); 134 | int getWriteablePageNum(fstream &filestream, int pageNum, int rowlen); 135 | int getTableStartDatPage(char * tableName); 136 | bool condVerify(vector head, vector record, condexp_node * cond); 137 | }; 138 | 139 | 140 | #endif //MYSQL_DBCORE_H 141 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 93773 on 2019/5/14. 3 | // 4 | 5 | #include "dbCore.h" 6 | /* 7 | int main() { 8 | Core * core = new Core(); 9 | cout << "start" << endl; 10 | auto rs = core->getTables(); 11 | for (auto r : rs) { 12 | cout << r.tableName << endl; 13 | } 14 | 15 | auto cols = core->getColumn(_S("database")); 16 | for (auto c : cols) { 17 | cout << c.field_name << endl; 18 | } 19 | 20 | // select test 21 | select_node snode; 22 | table_field_node tfnode; 23 | table_node tnode; 24 | tnode.tableName = _S("database"); 25 | tfnode.field_name = _S("*"); 26 | snode.table = &tnode; 27 | snode.field = &tfnode; 28 | auto selectrs = core->select_mult(&snode); 29 | for (auto s : selectrs.second) { 30 | for (auto ss : s) { 31 | cout << ss.chval << '\t'; 32 | } 33 | cout << endl; 34 | } 35 | 36 | table_node tnode2; 37 | tnode2.tableName = _S("database"); 38 | tnode.next = &tnode2; 39 | table_field_node tfnode2; 40 | tfnode2.field_name = _S("datfile"); 41 | tfnode.next = &tfnode2; 42 | snode.table = &tnode; 43 | snode.field = &tfnode; 44 | selectrs = core->select_mult(&snode); 45 | for (auto s : selectrs.second) { 46 | for (auto ss : s) { 47 | cout << ss.chval << '\t'; 48 | } 49 | cout << endl; 50 | } 51 | 52 | core->createDatabase("test3"); 53 | core->useDatabase("test3"); 54 | table_field_node tfn1; 55 | tfn1.field_name = _S("SNAME"); 56 | tfn1.len = 50; 57 | table_field_node tfn2; 58 | tfn2.field_name = _S("SAGE"); 59 | tfn2.len = 0; 60 | table_field_node tfn3; 61 | tfn3.field_name = _S("SEX"); 62 | tfn3.len = 0; 63 | tfn1.next = &tfn2; 64 | tfn2.next = &tfn3; 65 | core->createTable("students", &tfn1); 66 | core->createTable("students22", &tfn1); 67 | 68 | insert_node insetNode; 69 | values_node val1; 70 | val1.type = values_node::STRING; 71 | val1.chval = _S("SincereXIA"); 72 | values_node val2; 73 | val2.type = values_node::INT; 74 | val2.intval = 22; 75 | values_node val3; 76 | val3.type = values_node::INT; 77 | val3.intval = 1; 78 | val1.next = &val2; 79 | val2.next = NULL; 80 | table_node tbn; 81 | tbn.tableName = _S("students"); 82 | insetNode.table = &tbn; 83 | insetNode.values = &val1; 84 | char temp[20]; 85 | val1.chval = temp; 86 | for (int i = 0; i < 100; i++) { 87 | _itoa_s(i, temp, 10); 88 | core->insert(&insetNode); 89 | } 90 | 91 | 92 | tbn.tableName = _S("students22"); 93 | core->insert(&insetNode); 94 | // select test 95 | 96 | tnode.tableName = _S("students"); 97 | tfnode.field_name = _S("*"); 98 | tfnode.next = NULL; 99 | tnode.next = NULL; 100 | snode.table = &tnode; 101 | snode.field = &tfnode; 102 | selectrs = core->select_mult(&snode); 103 | for (auto s : selectrs.second) { 104 | for (auto ss : s) { 105 | if (ss.type == values_node::INT) 106 | cout << ss.intval << '\t'; 107 | else 108 | cout << ss.chval << '\t'; 109 | } 110 | cout << endl; 111 | } 112 | tnode.tableName = _S("students22"); 113 | selectrs = core->select_mult(&snode); 114 | for (auto s : selectrs.second) { 115 | for (auto ss : s) { 116 | if (ss.type == values_node::INT) 117 | cout << ss.intval << '\t'; 118 | else 119 | cout << ss.chval << '\t'; 120 | } 121 | cout << endl; 122 | } 123 | 124 | cout << "cond select test" << endl; 125 | condexp_node cond; 126 | cond.op = cond.EQ; 127 | condexp_node condleft; 128 | condleft.chval = _S("SNAME"); 129 | condexp_node condright; 130 | condright.chval = _S("66"); 131 | condright.type = condright.STRING; 132 | cond.left = &condleft; 133 | cond.right = &condright; 134 | snode.table->tableName = _S("students"); 135 | snode.cons = &cond; 136 | selectrs = core->select_mult(&snode); 137 | for (auto s : selectrs.second) { 138 | for (auto ss : s) { 139 | if (ss.type == values_node::INT) 140 | cout << ss.intval << '\t'; 141 | else 142 | cout << ss.chval << '\t'; 143 | } 144 | cout << endl; 145 | } 146 | 147 | 148 | system("pause"); 149 | } 150 | */ -------------------------------------------------------------------------------- /dbShell.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 93773 on 2019/5/14. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | #include "dbShell.h" 9 | #include "dbCore.h" 10 | #include 11 | 12 | void dbShell::CreateDatabase(char * DatabaseName) { 13 | if (core.createDatabase(DatabaseName)){ 14 | std::cout << "Create Database '" << DatabaseName << "' Success" << endl; 15 | }else { 16 | std::cout << "Create Database '" << DatabaseName << "' Error" << endl; 17 | } 18 | } 19 | 20 | void dbShell::ShowDatabases() { 21 | auto result = core.getDatabases(); 22 | bprinter::TablePrinter tp(&std::cout); 23 | tp.AddColumn("Database", 20); 24 | 25 | tp.PrintHeader(); 26 | for(auto db : result){ 27 | tp << db ; 28 | } 29 | tp.PrintFooter(); 30 | cout << result.size() << " rows in set" << endl; 31 | } 32 | 33 | void dbShell::CreateTable(char *tableName, table_field_node *tfn) { 34 | _strupr_s(tableName, strlen(tableName)+1); 35 | if(core.createTable(tableName, tfn)){ 36 | std::cout << "Create Table '" << tableName << "' Success" << endl; 37 | }else{ 38 | std::cout << "Create Table '" << tableName << "' Failed" << endl; 39 | } 40 | } 41 | 42 | void dbShell::UseDatabase(char *DatabaseName) { 43 | if(core.useDatabase(DatabaseName)){ 44 | cout << "Database Changed " << endl; 45 | } 46 | } 47 | 48 | void dbShell::ShowTables() { 49 | auto tables = core.getTables(); 50 | bprinter::TablePrinter tp(&std::cout); 51 | string head = "Tables_in_"; 52 | head += core.InUseDBName; 53 | tp.AddColumn(head, 20); 54 | 55 | tp.PrintHeader(); 56 | for(auto t : tables){ 57 | tp << t.tableName ; 58 | } 59 | tp.PrintFooter(); 60 | cout << tables.size() << " rows in set" << endl; 61 | } 62 | 63 | void dbShell::DropDatabases(char *DatabaseName) { 64 | if(core.deleteDatabase(DatabaseName)){ 65 | cout << "Delete Database '" << DatabaseName << "' Success" << endl; 66 | } 67 | } 68 | 69 | void dbShell::sqlInsert(insert_node *insertNode) { 70 | _strupr_s(insertNode->table->tableName, strlen(insertNode->table->tableName)+1); 71 | cout << insertNode->table->tableName << endl; 72 | if(core.insert(insertNode)){ 73 | cout << "Query OK, " << 1 << "row affected" << endl; 74 | } 75 | } 76 | 77 | void dbShell::select(select_node * selectNode) { 78 | auto table = selectNode->table; 79 | while (table){ 80 | _strupr_s(table->tableName, strlen(table->tableName)+1); 81 | table = table->next; 82 | } 83 | 84 | auto rs = core.select_mult(selectNode); 85 | vector max_len(rs.first.size(), 5); 86 | for (auto s : rs.second) { 87 | for (int i =0; i< s.size(); i++) { 88 | if (s[i].type == values_node::INT) 89 | max_len[i] = 5; 90 | else 91 | if (max_len[i] < strlen(s[i].chval)){ 92 | max_len[i] = static_cast(strlen(s[i].chval)); 93 | } 94 | } 95 | } 96 | bprinter::TablePrinter tp(&std::cout); 97 | for (int i =0 ; i table; 115 | while (table){ 116 | _strupr_s(table->tableName, strlen(table->tableName)+1); 117 | table = table->next; 118 | } 119 | int num = core.sqldelete(selectNode); 120 | cout << "Query OK, " << num << "rows affected" << endl; 121 | } 122 | 123 | void dbShell::sqlupdate(update_node *updateNode) { 124 | auto table = updateNode->table; 125 | while (table){ 126 | _strupr_s(table->tableName, strlen(table->tableName)+1); 127 | table = table->next; 128 | } 129 | int num = core.sqlupdate(updateNode); 130 | cout << "Query OK, " << num << "rows affected" << endl; 131 | } 132 | 133 | void dbShell::dropTable(char *tableName) { 134 | _strupr_s(tableName, strlen(tableName)+1); 135 | 136 | if(core.deleteTable(tableName)){ 137 | cout << "Drop Table Success" << endl; 138 | }else{ 139 | cout << "Drop Table Failed" << endl; 140 | } 141 | } 142 | 143 | dbShell::dbShell() { 144 | cout << "Welcome to the CPDatabase monitor. Commands end with ;\n" 145 | "Made by SincereXIA 16030199025@XDU. Compilation principle homework\n" 146 | "Database shell init successfully!" << endl; 147 | } 148 | 149 | dbShell::~dbShell() { 150 | cout << "bye" << endl; 151 | } 152 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CPDatabase 2 | 西电编译原理“教学实习”:DBMS 文件数据库 3 | 4 | 5 | ## 题目 6 | 7 | 设计并实现一个DBMS原型系统,可以接受基本的SQL语句,对其进行词法分析、语法分析,然后解释执行SQL语句,完成对数据库文件的相应操作,实现DBMS的基本功能。 8 | 9 | 10 | ## 项目概况 11 | 12 | ### 1.2 完成情况 13 | 14 | 本项目基于 C++ 语言,采用面向对象的编程思路,设计实现了 15 | 16 | `Core` :数据库核心类,负责 SQL 语句的执行,磁盘中数据库文件的更新 17 | 18 | `dbShell`: 数据库界面类, 是用户输入、语法分析与数据库核心的桥梁,用户的输入经过语法分析后到达 dbShell 类,通过 dbShell 访问数据库内核的服务,并将执行结果格式化输出。 19 | 20 | 语法分析模块:基于 Yacc 在 Linux 上的开源实现:bison 生成,编写了 `sql.y` 文件,调用 `yyparse()` 函数,在语法分析构建语法树的过程中,对语义进行处理,调用 dbShell 提供的数据库访问接口。 21 | 22 | 词法分析模块:基于 lex 在 Linux 上的开源实现:flex 生成,编写 `sql.l` 文件,为语法分析过程提供输入记号流。 23 | 24 | - **实现的功能** 25 | 26 | 1. 实现了基本 SQL 语句的词法分析和语法分析。 27 | 2. 实现了 SQL 语法制导翻译 28 | 3. 实现了数据库在本地磁盘上的分页式持久化存储 29 | 4. 实现了数据库前后端分离,查询结果表格化输出 30 | 31 | - **完成适配的 SQL 语句:** 32 | 33 | - 数据库的创建、显示和删除 34 | 35 | > CREATE DATABASE、 SHOW DATABASES、 DROP DATABASE、 USE DATABASE 36 | 37 | - 数据表的创建、显示和删除 38 | 39 | > REATE TABLE SHOW TABLES DROP TABLE 40 | 41 | - SQL 插入指令(指定列或按顺序) 42 | 43 | > INSERT INTO VALUES 44 | 45 | - 数据库单表查询 (WHERE 复合条件判断、选定指定列) 46 | 47 | > SELECT SNAME,SAGE FROM STUDENT WHERE SAGE=21; 48 | 49 | - 数据库多表查询 50 | 51 | > SELECT fields_star FROM tables 52 | 53 | - 记录的删除 54 | 55 | > DELETE FROM table WHERE conditions 56 | 57 | - 记录指定字段更新 58 | 59 | > UPDATE table SET updates WHERE conditions 60 | 61 | 62 | 63 | ## 实验方案——需求分析与测试 64 | 65 | ### 2.1 逻辑结构与物理结构 66 | 67 | #### 数据库物理结构设计 68 | 69 | **数据的基本存储单元为 页,每一页存放格式(每一行的长度,每个字段的偏移量)完全相同的数据项,** 70 | 71 | 每一页的大小为 2K,每一页的最后四个字节,用于标识下一页编号,通过编号*页大小,获取下一页的起始地址,相同类型的页面之间,可以不连续。 72 | 73 | ![](http://media.sumblog.cn/img/20190518195944.png-min_pic) 74 | 75 | 每个数据库采用两个文件进行持久化记录: 76 | 77 | 1. 元数据文件 `*.db` 78 | 79 | 元数据文件中有两种页面类型:表字典页、列字典列; 80 | 81 | - 表字典页:初始编号为 0 82 | 83 | 字典页中记录每个表在基本数据文件 `*.dat` 中的起始页 84 | 85 | 每一条记录长度为 100 字节,其中,表名占 96 字节,表的起始页编号使用 int 型表示,占 4 字节。 86 | 87 | ![](http://media.sumblog.cn/img/20190518200025.png-min_pic) 88 | 89 | - 列字典页:初始编号为 1 90 | 91 | 列字典页记录了每个表的列属性,其中,每一条记录长度为 200 字节,具体结构如下图: 92 | 93 | ![](http://media.sumblog.cn/img/20190518200836.png-min_pic) 94 | 95 | 元数据文件在初始情况下只有两页,后期根据需求,自动向文件后部添加表字典页或列字典页,两个不同类型的页面在元数据文件中交替排布: 96 | 97 | ![](http://media.sumblog.cn/img/20190518201528.png-min_pic) 98 | 99 | 2. 基本数据文件 `*.dat` 100 | 101 | 记录了每个表的具体内容,依据列字典,得到偏移量,进行文件读写。 102 | 103 | 数据库中每一个表对应一种类型的页面,页面之间通过每一页的最后四个字节的下一页编号进行连接。 104 | 105 | ![](http://media.sumblog.cn/img/20190518203812.png-min_pic) 106 | 107 | ### 2.2 语法结构和数据结构 108 | 109 | - CREATE 语句的产生式语法结构: 110 | 111 | `createsql: CREATE TABLE table '(' fieldsdefinition ')' ';'` 112 | 113 | - 非终结符 `fieldsdefinition` 的数据结构 114 | 115 | ```c++ 116 | struct table_field_node { 117 | char * field_name; 118 | enum type { 119 | INT, STRING 120 | }type; 121 | int len; 122 | int offset; 123 | table_field_node * next = nullptr; 124 | }; 125 | ``` 126 | 127 | - INSERT 语句的产生式语法结构 128 | 129 | ``` 130 | insertsql: INSERT INTO table VALUES '(' values ')' ';' 131 | | INSERT INTO table '(' fields ')' VALUES '(' values ')' ';' 132 | ``` 133 | 134 | - 非终结符 `insertsql` 的数据结构 135 | 136 | ```c++ 137 | struct insert_node { 138 | table_node * table = nullptr; 139 | table_field_node * field = nullptr; 140 | values_node * values = nullptr; 141 | }; 142 | ``` 143 | 144 | - 非终结符 `fields` 的数据结构 145 | 146 | ```c++ 147 | struct table_field_node { 148 | char * field_name; 149 | enum type { 150 | INT, STRING 151 | }type; 152 | int len; 153 | int offset; 154 | table_field_node * next = nullptr; 155 | }; 156 | ``` 157 | 158 | - 非终结符 `values` 的数据结构 159 | 160 | ```c++ 161 | struct values_node { 162 | enum type { 163 | INT, STRING 164 | }type; 165 | int intval; 166 | char * chval; 167 | values_node * next = nullptr; 168 | }; 169 | ``` 170 | 171 | - SELECT 语句的产生式语法结构 172 | 173 | ``` 174 | selectsql: SELECT fields_star FROM tables ';' 175 | | SELECT fields_star FROM tables WHERE conditions ';' 176 | ; 177 | ``` 178 | 179 | - 非终结符 `fields_star` 的产生式语法结构 180 | 181 | ``` 182 | fields_star: table_fields { $$ = $1;} 183 | | '*' 184 | ; 185 | ``` 186 | 187 | - 非终结符 fields_star 的数据结构 188 | 189 | ```c++ 190 | struct table_field_node { 191 | char * field_name; 192 | enum type { 193 | INT, STRING 194 | }type; 195 | int len; 196 | int offset; 197 | table_field_node * next = nullptr; 198 | }; 199 | ``` 200 | 201 | - 非终结符 `conditions` 的数据结构 202 | 203 | ```c++ 204 | struct condexp_node { 205 | condexp_node * left = nullptr; 206 | enum op { 207 | AND, OR, EQ, G, B, NOT 208 | }op; 209 | condexp_node * right = nullptr; 210 | enum type { 211 | INT, STRING, COLUM, LOGIC 212 | }type; 213 | int intval; 214 | char * chval; 215 | }; 216 | ``` 217 | 218 | - DELETE 语句产生式语法结构 219 | 220 | ``` 221 | deletesql: DELETE FROM table ';' 222 | | DELETE FROM table WHERE conditions ';' 223 | ``` 224 | 225 | - DELETE 语句数据结构同SELECT 语句 226 | 227 | - UPDATE 语句产生式语法结构 228 | 229 | ``` 230 | updatesql: UPDATE table SET updates WHERE conditions ';' 231 | ``` 232 | 233 | - UPDATE 语句数据结构同 SELECT 语句 234 | 235 | ### 2.3 词法分析 236 | 237 | 编写 `sql.l` 作为词法分析文件 238 | 239 | 在词法分析文件中,需要用到在语法分析中定义的终结符,因此,引入相关的头文件 `sql.tab.h`: 240 | 241 | ``` 242 | %{ 243 | #include 244 | #include 245 | #include "dbCore.h" 246 | #include "sql.tab.h" 247 | #include 248 | int cur_line = 1; 249 | %} 250 | ``` 251 | 252 | 词法分析过程中,需要识别出相应的终结符, 例如 253 | 254 | ``` 255 | CREATE CREATE|create 256 | SHOW SHOW|show 257 | DROP DROP|drop 258 | USE USE|use 259 | DATABASE DATABASE|database 260 | ... 261 | {CREATE} { return CREATE;} 262 | {SHOW} {return SHOW; } 263 | {DROP} {return DROP; } 264 | {USE} {return USE;} 265 | ``` 266 | 267 | 这样,用户输入的文本会被拆分成终结符流,并返回每一个终结符对应的类型。 268 | 269 | 对于特殊的终结符,例如 ID (标识符)、 NUMBER(数字)、STRING(字符串),在进行词法分析的时候,还需要将其字面值存放到 `yylval` 变量中,以供语法分析文件调用。 270 | 271 | ``` 272 | {CHAR} {yylval.typeval = CHAR; return CHAR; } 273 | {INT} {yylval.typeval = INT; return INT;} 274 | ``` 275 | 276 | yylval 为结构体,其在语法分析文件 `sql.y` 中定义。 277 | 278 | ### 2.4 语法分析和语义分析 279 | 280 | 语法分析文件为:`sql.y`,在语法分析文件中,进行了 yylval 结构体的定义,终结符以及终结符和非终结符的类型定义,以及构成每个非终结符的语法规则。 281 | 282 | - **yylval 结构体定义:** 283 | 284 | 由于该项目采用语法制导翻译的方式执行 sql 语句,因此,在语法分析的过程中,就需要对 sql 语句的关键信息进行提取,构建出树状结构。树状结构所需要的节点数据类型,在 %union 中定义: 285 | 286 | ``` 287 | %union { 288 | int intval; 289 | char * chval; 290 | int typeval; 291 | table_field_node * tableField; 292 | table_node * tableNode; 293 | insert_node * insertNode; 294 | values_node * valuesNode; 295 | select_node * selectNode; 296 | condexp_node * condNode; 297 | update_node * updateNode; 298 | set_value * setNode; 299 | } 300 | ``` 301 | 302 | - **终结符和非终结符定义:** 303 | 304 | 非终结符使用 %type 描述其类型,类型确定后便可以用 $$ 符号对其值进行引用 305 | 306 | ## 实现与测试 307 | 308 | - CREATE 测试 309 | 310 | ![](http://media.sumblog.cn/img/20190619202301.png-min_pic) 311 | 312 | - 测试CREATE TABLE SHOW TABLES DROP TABLE 313 | 314 | ![](http://media.sumblog.cn/img/20190619202448.png-min_pic) 315 | 316 | - 测试INSERT INTO VALUES 317 | 318 | ![](http://media.sumblog.cn/img/20190619202519.png-min_pic) 319 | 320 | - 测试单表查询 321 | 322 | ![](http://media.sumblog.cn/img/20190619202551.png-min_pic) 323 | 324 | 、 325 | 326 | - 测试多表查询 327 | 328 | ![](http://media.sumblog.cn/img/20190619202640.png-min_pic) 329 | 330 | - 测试DELETE语句 331 | 332 | ![](http://media.sumblog.cn/img/20190619202731.png-min_pic) 333 | 334 | - 测试 UPDATE 335 | 336 | ![](http://media.sumblog.cn/img/20190619202838.png-min_pic) 337 | 338 | 339 | -------------------------------------------------------------------------------- /sql.y: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include 4 | #include "myarray.h" 5 | #include "lex.yy.c" 6 | #include "dbShell.h" 7 | #include 8 | #define YYDEBUG 1 9 | #define YYERROR_VERBOSE 10 | #include 11 | #include "dbCore.h" 12 | using namespace std; 13 | dbShell shell; 14 | 15 | 16 | extern 17 | void yyerror(char *s) { 18 | // simple error-message 19 | printf("Error '%s'\n", s); 20 | 21 | } 22 | %} 23 | 24 | %union { 25 | int intval; 26 | char * chval; 27 | int typeval; 28 | table_field_node * tableField; 29 | table_node * tableNode; 30 | insert_node * insertNode; 31 | values_node * valuesNode; 32 | select_node * selectNode; 33 | condexp_node * condNode; 34 | update_node * updateNode; 35 | set_value * setNode; 36 | } 37 | %type insertsql 38 | %type table STRING field 39 | %type values value 40 | %type fields fields_star table_fields table_field 41 | %type NUMBER 42 | %type selectsql deletesql 43 | %type tables 44 | %type conditions condition comp_op comp_left comp_right 45 | %type updatesql 46 | %type updates update 47 | %token CREATE 48 | %token DATABASE 49 | %token SHOW 50 | %token DATABASES 51 | %token DROP 52 | %token USE 53 | %token TABLE 54 | %token TABLES 55 | %token INSERT 56 | %token INTO 57 | %token VALUES 58 | %token SELECT 59 | %token FROM 60 | %token WHERE 61 | %token UPDATE 62 | %token SET 63 | %token ID 64 | %token CHAR 65 | %token NUMBER 66 | %token INT 67 | %token STRING 68 | %token DELETE 69 | %left OR 70 | %left AND 71 | 72 | 73 | %% 74 | statements: statements statement {printf("\nmysql>");} 75 | | statement {printf("\nmysql>");} 76 | ; 77 | statement: createsql 78 | | selectsql 79 | | insertsql 80 | | deletesql 81 | | updatesql 82 | | dbsql 83 | ; 84 | // 数据库操作语句 85 | dbsql: CREATE DATABASE database ';'{shell.CreateDatabase($3);} 86 | | SHOW DATABASES ';' {shell.ShowDatabases();} 87 | | SHOW TABLES ';' {shell.ShowTables();} 88 | | DROP DATABASE database ';' {shell.DropDatabases($3);} 89 | | DROP TABLE table ';' {shell.dropTable($3);} 90 | | USE database ';' {shell.UseDatabase($3);} 91 | ; 92 | database: ID 93 | ; 94 | 95 | // 建表语句 96 | createsql: CREATE TABLE table '(' fieldsdefinition ')' ';' {shell.CreateTable($3, $5);} 97 | ; 98 | table: ID {} 99 | ; 100 | fieldsdefinition: field_type {$$ = $1; 101 | } 102 | | field_type ',' fieldsdefinition {$1->next = $3; 103 | $$ = $1;} 104 | ; 105 | field_type: field type {$$ = $2; 106 | $$->field_name = $1;} 107 | ; 108 | field: ID {$$ = $1} 109 | ; 110 | type: CHAR '(' NUMBER ')' {$$ = new table_field_node; 111 | $$->len = $3;} 112 | | INT {$$ = new table_field_node; 113 | $$->len = 0;} 114 | ; 115 | 116 | // 查询语句 117 | selectsql: SELECT fields_star FROM tables ';' {$$ = new select_node; 118 | $$->field = $2; 119 | $$->table = $4; 120 | shell.select($$); 121 | } 122 | | SELECT fields_star FROM tables WHERE conditions ';' {$$ = new select_node; 123 | $$->field = $2; 124 | $$->table = $4; 125 | $$->cons = $6; 126 | shell.select($$); 127 | } 128 | ; 129 | fields_star: table_fields { $$ = $1;} 130 | | '*' {$$ = new table_field_node; 131 | $$->field_name = _S("*"); 132 | } 133 | ; 134 | table_fields: table_field { $$ = $1; } 135 | | table_field ',' table_fields {$$ = $1; 136 | $$->next = $3;} 137 | ; 138 | table_field: field {$$ = new table_field_node; 139 | $$->field_name = $1; 140 | } 141 | | table '.' field 142 | ; 143 | tables: table {$$ = new table_node; 144 | $$->tableName = $1;} 145 | | table ',' tables {$$ = new table_node; 146 | $$->tableName = $1; 147 | $$->next = $3; 148 | } 149 | ; 150 | conditions: condition {$$ = $1;} 151 | | '(' conditions ')' {$$ = $2;} 152 | | conditions AND conditions {$$ = new condexp_node; 153 | $$->left = $1; 154 | $$->right = $3; 155 | $$->op = condexp_node::AND; 156 | $$->type = condexp_node::LOGIC; 157 | } 158 | | conditions OR conditions {$$ = new condexp_node; 159 | $$->left = $1; 160 | $$->right = $3; 161 | $$->op = condexp_node::OR; 162 | $$->type = condexp_node::LOGIC; 163 | } 164 | ; 165 | condition: comp_left comp_op comp_right {$$ = $2; 166 | $$->left = $1; 167 | $$->right = $3; 168 | } 169 | ; 170 | comp_left: table_field {$$ = new condexp_node; 171 | $$->chval = $1->field_name; 172 | } 173 | ; 174 | comp_op: '<' {$$ = new condexp_node; $$->op = condexp_node::B;} 175 | | '>' {$$ = new condexp_node; $$->op = condexp_node::G;} 176 | | '=' {$$ = new condexp_node; $$->op = condexp_node::EQ;} 177 | | '!''=' {$$ = new condexp_node; $$->op = condexp_node::NOT;} 178 | ; 179 | comp_right: table_field {$$ = new condexp_node; 180 | $$->chval = $1->field_name; 181 | $$->type = condexp_node::STRING; 182 | } 183 | | NUMBER {$$ = new condexp_node; 184 | $$->intval = $1; 185 | $$->type = condexp_node::INT; 186 | } 187 | | STRING {$$ = new condexp_node; 188 | $$->chval = $1; 189 | $$->type = condexp_node::STRING; 190 | } 191 | ; 192 | 193 | /// 插入语句 194 | insertsql: INSERT INTO table VALUES '(' values ')' ';' {$$ = new insert_node; 195 | $$->table = new table_node; 196 | $$->table->tableName = $3; 197 | $$->values = $6; 198 | shell.sqlInsert($$); 199 | } 200 | | INSERT INTO table '(' fields ')' VALUES '(' values ')' ';' {$$ = new insert_node; 201 | $$->table = new table_node; 202 | $$->table->tableName = $3; 203 | $$->values = $9; 204 | $$->field = $5; 205 | shell.sqlInsert($$); 206 | } 207 | ; 208 | values: value {$$ = $1} 209 | | value ',' values {$$ = $1; 210 | $$->next = $3; 211 | } 212 | ; 213 | value: STRING { $$ = new values_node; 214 | $$->type = values_node::STRING; 215 | $$->chval = $1; 216 | } 217 | | NUMBER { $$ = new values_node; 218 | $$->type = values_node::INT; 219 | $$->intval = $1; 220 | } 221 | ; 222 | fields: field {$$ = new table_field_node; 223 | $$->field_name = $1; 224 | } 225 | | field ',' fields {$$ = new table_field_node; 226 | $$->field_name = $1; 227 | $$->next = $3; 228 | } 229 | ; 230 | //删除语句 231 | deletesql: DELETE FROM table ';' {$$ = new select_node; 232 | $$->table = new table_node; 233 | $$->table->tableName = $3; 234 | $$->cons = nullptr; 235 | shell.sqldelete($$);} 236 | | DELETE FROM table WHERE conditions ';' {$$ = new select_node; 237 | $$->table = new table_node; 238 | $$->table->tableName = $3; 239 | $$->cons = $5; 240 | shell.sqldelete($$); 241 | } 242 | ; 243 | //更新语句 244 | updatesql: UPDATE table SET updates WHERE conditions ';' {$$ = new update_node; 245 | $$->table = new table_node; 246 | $$->table->tableName = $2; 247 | $$->cons = $6; 248 | $$->setval = $4; 249 | shell.sqlupdate($$); 250 | } ; 251 | 252 | updates: update {$$ = $1 253 | } 254 | | update ',' updates {$$ = $1; 255 | $1->next = $3; 256 | } 257 | ; 258 | 259 | update: comp_left '=' comp_right {$$ = new set_value; 260 | $$->field_name = $1->chval; 261 | $$->intval = $3->intval; 262 | $$->chval = $3->chval; 263 | } 264 | ; 265 | 266 | 267 | 268 | %% 269 | 270 | int main(){ 271 | printf("\nmysql>"); 272 | while(1){ 273 | yyparse(); 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /dbCore.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 93773 on 2019/5/14. 3 | // 4 | 5 | #include "dbCore.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | char *_S(const char *string) { 14 | return _strdup(string); 15 | } 16 | 17 | void Core::addPage(fstream &f) { 18 | f.seekp(0, ios::end); 19 | for (int i = 0; i < PAGE_SIZE; i++) { 20 | f.put('\0'); 21 | } 22 | f.flush(); 23 | f.clear(); 24 | } 25 | 26 | int Core::createDatabase(const char *databaseName) { 27 | 28 | auto databasesNow = getDatabases(); 29 | for (auto db : databasesNow) { 30 | if (strcmp(databaseName, db) == 0) { 31 | cout << "Error: database '" << databaseName << "' already exists" << endl; 32 | return 0; 33 | } 34 | } 35 | 36 | //临时 37 | if (InUsedb && (InUsedb!=sysdb)){ 38 | InUsedb->close(); 39 | InUsedat->close(); 40 | } 41 | InUsedb = sysdb; 42 | InUsedat = sysdat; 43 | insert_node insetNode; 44 | auto val1 = new values_node; 45 | val1->type = values_node::STRING; 46 | val1->chval = _S(databaseName); 47 | auto val2 = new values_node; 48 | val2->type = values_node::STRING; 49 | char dbfileName[40] = {0}; 50 | char datfileName[40] = {0}; 51 | strcat_s(dbfileName, strlen(databaseName) + 1, databaseName); 52 | strcat_s(dbfileName, ".db"); 53 | val2->chval = dbfileName; 54 | auto val3 = new values_node; 55 | val3->type = values_node::STRING; 56 | strcat_s(datfileName, strlen(databaseName) + 1, databaseName); 57 | strcat_s(datfileName, ".dat"); 58 | val3->chval = datfileName; 59 | val1->next = val2; 60 | val2->next = val3; 61 | auto tbn = new table_node; 62 | tbn->tableName = _S("database"); 63 | insetNode.table = tbn; 64 | insetNode.values = val1; 65 | this->insert(&insetNode); 66 | 67 | InUsedb = new fstream(dbfileName, ios::out | ios::binary); 68 | this->getNewDatPage(*InUsedb); 69 | this->getNewDatPage(*InUsedb); 70 | 71 | InUsedat = new fstream(datfileName, ios::out | ios::binary); 72 | 73 | useDatabase(databaseName); 74 | return 1; 75 | } 76 | 77 | int Core::useDatabase(const char *databaseName) { 78 | auto dbs = getDatabases(); 79 | for (auto db : dbs){ 80 | if(strcmp(db, databaseName) ==0){ 81 | InUseDBName = _S(databaseName); 82 | // TODO: 更新 InUSE文件流 83 | char dbfileName[40] = {0}; 84 | char datfileName[40] = {0}; 85 | strcat_s(dbfileName, strlen(databaseName) + 1, databaseName); 86 | strcat_s(dbfileName, ".db"); 87 | InUsedb->close(); 88 | InUsedb->open(dbfileName, ios::out | ios::in | ios::binary); 89 | strcat_s(datfileName, strlen(databaseName) + 1, databaseName); 90 | strcat_s(datfileName, ".dat"); 91 | InUsedat->close(); 92 | InUsedat->open(datfileName, ios::out | ios::in | ios::binary); 93 | this->InUseDBName = _S(databaseName); 94 | return 1; 95 | } 96 | } 97 | return 0; 98 | } 99 | 100 | int Core::createTable(const char *tableName, table_field_node *tfn) { 101 | auto tablesNow = getTables(); 102 | for (auto t : tablesNow) { 103 | if (strcmp(t.tableName, tableName) == 0) { 104 | cout << "Error: table '" << tableName << "' already exists" << endl; 105 | return 0; 106 | } 107 | } 108 | 109 | int PageNow = 0; //表字典 110 | for (int i = 0; i < 20; i++) { 111 | int offset = PageNow * PAGE_SIZE + i * 100; 112 | InUsedb->seekg(offset); 113 | if (InUsedb->peek() == '\0') { 114 | InUsedb->seekp(InUsedb->tellg()); 115 | InUsedb->write(tableName, strlen(tableName) * sizeof(char)); 116 | int page = getNewDatPage(*InUsedat); 117 | offset = offset + 100 - sizeof(int); 118 | InUsedb->seekp(offset); 119 | InUsedb->write((char *) &page, sizeof(int));; 120 | break; 121 | } 122 | } 123 | PageNow = getWriteablePageNum(*InUsedb, 1); // 列字典从 1 页开始存放 124 | 125 | int colNum = 0; 126 | int coloffset = 0; 127 | for (int i = 0; i < 20; i++) { 128 | std::streampos offset = PageNow * PAGE_SIZE + i * 100; 129 | InUsedb->seekg(offset); 130 | if (InUsedb->peek() == '\0' && tfn) { 131 | InUsedb->seekp(offset); 132 | InUsedb->write(tableName, strlen(tableName) * sizeof(char)); //写入数据库名 133 | offset += 40; 134 | InUsedb->seekp(offset); 135 | InUsedb->write((char *) &colNum, sizeof(int)); //写入列号 136 | offset += sizeof(int); 137 | InUsedb->seekp(offset); 138 | InUsedb->write(tfn->field_name, strlen(tfn->field_name)); // 写入列名 139 | offset += 40; 140 | InUsedb->seekp(offset); 141 | InUsedb->write((char *) &coloffset, sizeof(int)); //写入偏移 142 | offset += sizeof(int); 143 | InUsedb->seekp(offset); 144 | 145 | InUsedb->write((char *) &(tfn->len), sizeof(int)); //写入宽度 146 | 147 | coloffset += tfn->len == 0 ? sizeof(int) : tfn->len; 148 | tfn = tfn->next; 149 | colNum++; 150 | } 151 | } 152 | return 1; 153 | } 154 | 155 | /* 156 | 获取当前数据库中某个表所有的列 157 | */ 158 | vector Core::getColumn(char *tableName) { 159 | vector result; 160 | int PageNow = 1; 161 | readPage(*InUsedb, PageNow); 162 | for (int i = 0; i < 20; i++) { 163 | if (strcmp(tableName, DATPAGE + (i * 100)) == 0) { 164 | table_field_node node; 165 | node.field_name = _S(DATPAGE + (i * 100) + 44); 166 | node.offset = *(int *) (DATPAGE + (i * 100) + 84); 167 | node.len = *(int *) (DATPAGE + (i * 100) + 88); 168 | if (node.len == 0) { 169 | node.len = sizeof(int); 170 | node.type = table_field_node::INT; 171 | } else { 172 | node.type = table_field_node::STRING; 173 | } 174 | 175 | result.push_back(node); 176 | } 177 | } 178 | return result; 179 | } 180 | 181 | int Core::insert(insert_node *insertNode) { 182 | char *tableName = insertNode->table->tableName; 183 | auto cols = getColumn(tableName); 184 | vector offsets; 185 | auto fieldNow = insertNode->field; 186 | 187 | if (fieldNow == nullptr) { //不指定 field 时, 按顺序插入 188 | for (auto c : cols) { 189 | offsets.push_back(c.offset); 190 | } 191 | } 192 | while (fieldNow) { // 指定 field 时, 获取每个值的偏移量 193 | bool find = false; 194 | for (auto c : cols) { 195 | if (strcmp(c.field_name, fieldNow->field_name) == 0) { 196 | find = true; 197 | offsets.push_back(c.offset); 198 | break; 199 | } 200 | } 201 | if (!find) { 202 | cout << "Error: there is no field '" << fieldNow->field_name << "' in table " << tableName << endl; 203 | return 0; 204 | } 205 | fieldNow = fieldNow->next; 206 | } 207 | 208 | int page = getTableStartDatPage(tableName); //获取起始页 209 | //获取每条记录的长度 210 | int Recordlength = cols.at(cols.size() - 1).offset + cols.at(cols.size() - 1).len; 211 | page = getWriteablePageNum(*InUsedat, page, Recordlength); //获取可插入页 212 | readPage(*InUsedat, page); 213 | 214 | int offset = 0; 215 | while (offset + Recordlength <= PAGE_SIZE - sizeof(int)) { 216 | if (DATPAGE[offset] == '\0') break; 217 | offset += Recordlength; 218 | } 219 | 220 | int i = 0; // 当前插入了第几个数据项 221 | auto data = insertNode->values; 222 | while (data) { 223 | // TODO : 属性检查 224 | if (data->type == values_node::STRING) { 225 | // TODO : 插入数据项超长后的异常处理 226 | strcpy_s(&(DATPAGE[offset + offsets[i]]), strlen(data->chval) + 1, data->chval); 227 | } else if (data->type == values_node::INT) { 228 | // TODO : 这里写的不对 229 | *(int *) (DATPAGE + offset + offsets[i]) = data->intval; 230 | } 231 | data = data->next; 232 | i++; 233 | } 234 | writePage(*InUsedat, page); 235 | return 1; 236 | } 237 | 238 | pair, vector>> 239 | Core::select_single(select_node *selectNode) { 240 | char *tableName = selectNode->table->tableName; 241 | auto tableCols = getColumn(tableName); 242 | 243 | auto fieldrequest = selectNode->field; 244 | vector head; 245 | vector head_all; 246 | vector> body; 247 | while (fieldrequest) { //将请求 field 找到 248 | bool findField = false; 249 | if (strcmp(fieldrequest->field_name, "*") == 0) { 250 | findField = true; 251 | for (auto c : tableCols) { 252 | head.push_back(c); 253 | head_all.push_back(c); 254 | } 255 | } else { 256 | for (auto c : tableCols) { 257 | if (strcmp(c.field_name, fieldrequest->field_name) == 0) { 258 | findField = true; 259 | head.push_back(c); 260 | } 261 | head_all.push_back(c); 262 | } 263 | } 264 | if (!findField) cout << "Error: Field '" << fieldrequest->field_name << "can not find!" << endl; 265 | fieldrequest = fieldrequest->next; 266 | } 267 | 268 | auto datpageNum = getTableStartDatPage(tableName); 269 | //获取每条记录的长度 270 | int Recordlength = tableCols.at(tableCols.size() - 1).offset + tableCols.at(tableCols.size() - 1).len; 271 | while (datpageNum != -1) { 272 | if (!readPage(*InUsedat, datpageNum)) { 273 | cout << "SELECT: readPage Error!" << endl; 274 | } 275 | int i = 0; 276 | // TODO : 是否是最后一行的判定有问题 277 | while ((i+1) * Recordlength + sizeof(int) <= PAGE_SIZE){ 278 | if (*(DATPAGE + i * Recordlength) != '\0') { 279 | vector row; 280 | vector row_all; 281 | for (auto h : head_all) { // 获取完整行 282 | values_node node; 283 | if (h.type == table_field_node::INT) { // int 284 | node.intval = *(int *) (DATPAGE + i * Recordlength + h.offset); 285 | node.type = values_node::INT; 286 | } else { // string 287 | node.chval = _S(DATPAGE + i * Recordlength + h.offset); 288 | node.type = values_node::STRING; 289 | } 290 | row_all.push_back(node); 291 | } 292 | if (condVerify(head_all, row_all, selectNode->cons)){ //使用完整行进行筛选 293 | for (auto h : head) { //筛选通过后生成目标行 294 | values_node node; 295 | if (h.type == table_field_node::INT) { // int 296 | node.intval = *(int *) (DATPAGE + i * Recordlength + h.offset); 297 | node.type = values_node::INT; 298 | } else { // string 299 | node.chval = _S(DATPAGE + i * Recordlength + h.offset); 300 | node.type = values_node::STRING; 301 | } 302 | row.push_back(node); 303 | } 304 | body.push_back(row); 305 | } 306 | } 307 | i++; 308 | } 309 | datpageNum = getNextPageNum(); 310 | } 311 | 312 | return pair, vector>> 313 | (head, body); 314 | } 315 | 316 | 317 | pair, vector>> 318 | Core::select_mult(select_node *selectNode) { 319 | vector tables; 320 | vector head; 321 | auto table = selectNode->table; 322 | tables.push_back(*(selectNode->table)); 323 | table = table->next; 324 | while (table) { 325 | tables.push_back(*table); 326 | table = table->next; 327 | } 328 | 329 | auto userField = selectNode->field; 330 | while (userField) { 331 | for (auto &t : tables) { 332 | auto cols = getColumn(t.tableName); 333 | for (auto c : cols) { 334 | if (strcmp(c.field_name, userField->field_name) == 0 || 335 | strcmp(userField->field_name, "*") == 0) { 336 | auto *tfn = new table_field_node; 337 | tfn->field_name = userField->field_name; 338 | head.push_back(*tfn); 339 | auto f = t.field; 340 | if (!f) { 341 | t.field = tfn; 342 | } else { 343 | while (f->next) { 344 | f = f->next; 345 | } 346 | f->next = tfn; 347 | } 348 | break; 349 | } 350 | } 351 | } 352 | userField = userField->next; 353 | } 354 | 355 | vector > > temp; 356 | vector heads_New; 357 | for (auto &t : tables) { 358 | select_node sn; 359 | sn.table = &t; 360 | sn.cons = selectNode->cons; 361 | sn.field = t.field; 362 | auto res = select_single(&sn); 363 | temp.push_back(res.second); 364 | heads_New.insert(heads_New.end(), res.first.begin(), res.first.end()); 365 | } 366 | vector > colsNow = temp[0]; 367 | vector > colsNew; 368 | 369 | 370 | for (int i = 1; i < temp.size(); i++) { 371 | for (auto ac : temp[i]) { 372 | for (auto c : colsNow) { 373 | c.insert(c.end(), ac.begin(), ac.end()); 374 | colsNew.push_back(c); 375 | } 376 | } 377 | colsNow = colsNew; 378 | colsNew.clear(); 379 | } 380 | return pair, vector>>( 381 | heads_New, colsNow 382 | ); 383 | } 384 | 385 | 386 | void Core::SysdbInit() { 387 | 388 | } 389 | 390 | vector Core::getTables() { 391 | vector result; 392 | int PageNow = 0; //表字典 393 | for (int i = 0; i < 20; i++) { 394 | int offset = PageNow * PAGE_SIZE + i * 100; 395 | InUsedb->seekg(offset); 396 | InUsedb->read((char *) TEMP, 100); 397 | if (((char *) TEMP)[0] == '\0') return result; 398 | auto *tn = new table_node; 399 | tn->tableName = _strdup((char *) TEMP); 400 | offset = offset + 100 - sizeof(int); 401 | int beginPage; 402 | InUsedb->seekg(offset); 403 | InUsedb->read((char *) &beginPage, sizeof(int)); 404 | tn->beginPage = beginPage; 405 | result.push_back(*tn); 406 | } 407 | return result; 408 | } 409 | 410 | vector Core::getDatabases() { 411 | auto tempdb = this->InUsedb; 412 | auto tempdat = this->InUsedat; 413 | this->InUsedb = this->sysdb; 414 | this->InUsedat = this->sysdat; 415 | vector result; 416 | select_node snode; 417 | auto tfnode = new table_field_node; 418 | auto tnode = new table_node; 419 | tnode->tableName = _S("database"); 420 | tfnode->field_name = _S("name"); 421 | snode.table = tnode; 422 | snode.field = tfnode; 423 | auto selectrs = this->select_mult(&snode); 424 | for (auto s : selectrs.second) { 425 | result.push_back(s[0].chval); 426 | } 427 | this->InUsedb = tempdb; 428 | this->InUsedat = tempdat; 429 | return result; 430 | } 431 | 432 | 433 | int Core::getNewDatPage(fstream &datfile, int PageNow) { 434 | int offset = PageNow * PAGE_SIZE; 435 | datfile.seekg(0, ios::end); 436 | fpos fileSize = datfile.tellg(); 437 | while (offset + PAGE_SIZE <= fileSize) { 438 | datfile.seekg(offset + PAGE_SIZE - sizeof(int)); 439 | datfile.read((char *) TEMP, sizeof(int)); 440 | if (TEMP[0] == 0) { 441 | datfile.seekp(offset + PAGE_SIZE - sizeof(int)); 442 | TEMP[0] = -1; 443 | datfile.write((char *) TEMP, sizeof(int)); 444 | return PageNow; 445 | } else { 446 | PageNow++; 447 | } 448 | offset = PageNow * PAGE_SIZE; 449 | } 450 | addPage(datfile); 451 | datfile.seekp(offset + PAGE_SIZE - sizeof(int)); 452 | TEMP[0] = -1; 453 | datfile.write((char *) TEMP, sizeof(int)); 454 | return PageNow; 455 | } 456 | 457 | int Core::getNextPageNum() { 458 | int offset = PAGE_SIZE - sizeof(int); 459 | return *(int *) (DATPAGE + offset); 460 | } 461 | 462 | int Core::readPage(fstream &filestream, int pageNum, char *page) { 463 | int offset = pageNum * PAGE_SIZE; 464 | filestream.seekg(0, ios::end); 465 | fpos fileSize = filestream.tellg(); 466 | if (offset + PAGE_SIZE > fileSize) { // 判断这一页是否存在 467 | cerr << "Core ERROR: Page Not Found!" << endl; 468 | return 0; 469 | } 470 | filestream.seekg(offset); //偏移 471 | filestream.read(page, PAGE_SIZE); // 读取到 DATPAGE 472 | return 1; 473 | } 474 | 475 | int Core::writePage(fstream &filestream, int pageNum, char *page) { 476 | int offset = pageNum * PAGE_SIZE; 477 | filestream.seekp(0, ios::end); 478 | fpos fileSize = filestream.tellp(); 479 | if (offset + PAGE_SIZE > fileSize) { // 判断这一页是否存在 480 | cerr << "Core ERROR: Page Not Found!" << endl; 481 | return 0; 482 | } 483 | filestream.seekp(offset); //偏移 484 | filestream.write(page, PAGE_SIZE); // 写入到文件 485 | return 1; 486 | } 487 | 488 | int Core::getWriteablePageNum(fstream &filestream, int pageNum) { 489 | char temp[PAGE_SIZE]; 490 | int pageNow = pageNum; 491 | while (pageNow != -1) { 492 | readPage(filestream, pageNum, temp); 493 | pageNow = *(int *) (temp + PAGE_SIZE - sizeof(int)); 494 | if (pageNow != -1) pageNum = pageNow; 495 | } 496 | return pageNum; 497 | } 498 | 499 | /* 500 | 获取一个可写入页 501 | */ 502 | int Core::getWriteablePageNum(fstream &filestream, int pageNum, int rowlen) { 503 | char temp[PAGE_SIZE]; 504 | // 获取最后一页 505 | int lastPage = getWriteablePageNum(filestream, pageNum); 506 | // 判断是否被写满 507 | readPage(filestream, lastPage, temp); 508 | int offset = 0; 509 | while (offset + rowlen <= PAGE_SIZE - sizeof(int)) { 510 | if (temp[offset] == '\0') { 511 | return lastPage; 512 | } 513 | offset += rowlen; 514 | } 515 | // 写满后,添加一个新页,并修正当前页号 516 | int newPage = getNewDatPage(filestream, lastPage); 517 | *(int *) (temp + PAGE_SIZE - sizeof(int)) = newPage; 518 | writePage(filestream, lastPage, temp); 519 | return newPage; 520 | } 521 | 522 | int Core::getTableStartDatPage(char *tableName) { 523 | auto tables = getTables(); 524 | for (auto table : tables) { 525 | if (strcmp(tableName, table.tableName) == 0) { 526 | return table.beginPage; 527 | } 528 | } 529 | return -1; 530 | } 531 | 532 | 533 | Core::Core() { 534 | bool needrebuild = false; 535 | sysdb = new fstream("sys.db", ios::out | ios::in | ios::binary); 536 | if (!sysdb) { 537 | cout << "error!" << endl; 538 | } 539 | if (sysdb->peek() == EOF) { 540 | needrebuild = true; 541 | sysdb->close(); 542 | sysdb->open("sys.db", ios::out | ios::binary); 543 | sysdb->close(); 544 | sysdb->open("sys.db", ios::out | ios::in | ios::binary); 545 | getNewDatPage(*sysdb); 546 | getNewDatPage(*sysdb); 547 | } 548 | sysdat = new fstream("sys.dat", ios::out | ios::in | ios::binary); 549 | if (!sysdat) { 550 | cout << "error!" << endl; 551 | } 552 | if (sysdat->peek() == EOF) { 553 | needrebuild = true; 554 | sysdat->close(); 555 | sysdat->open("sys.dat", ios::out | ios::binary); 556 | sysdat->close(); 557 | sysdat->open("sys.dat", ios::out | ios::in | ios::binary); 558 | } 559 | 560 | if (needrebuild) { 561 | cout << "Core Info: can not find 'sys.db' and 'sys.dat'. Rebuilding the basic database... " ; 562 | //临时 563 | InUsedb = sysdb; 564 | InUsedat = sysdat; 565 | char d[] = "database"; 566 | char s[] = "security"; 567 | auto dbNameNode = new table_field_node; 568 | dbNameNode->field_name = _S("name"); 569 | dbNameNode->len = 50; 570 | auto dbFileNode = new table_field_node; 571 | dbFileNode->field_name = _S("dbfile"); 572 | dbFileNode->len = 100; 573 | auto datFileNode = new table_field_node; 574 | datFileNode->field_name = _S("datfile"); 575 | datFileNode->len = 100; 576 | dbNameNode->next = dbFileNode; 577 | dbFileNode->next = datFileNode; 578 | table_field_node secName; 579 | secName.field_name = _S("name"); 580 | secName.len = 50; 581 | auto secdb = new table_field_node; 582 | secdb->field_name = _S("database"); 583 | secdb->len = 50; 584 | secName.next = secdb; 585 | createTable(d, dbNameNode); 586 | createTable(s, &secName); 587 | 588 | insert_node insetNode; 589 | values_node val1; 590 | val1.type = values_node::STRING; 591 | val1.chval = _S("sys"); 592 | auto val2 = new values_node; 593 | val2->type = values_node::STRING; 594 | val2->chval = _S("sys.db"); 595 | auto val3 = new values_node; 596 | val3->type = values_node::STRING; 597 | val3->chval = _S("sys.dat"); 598 | val1.next = val2; 599 | val2->next = val3; 600 | table_node tbn; 601 | tbn.tableName = _S("database"); 602 | insetNode.table = &tbn; 603 | insetNode.values = &val1; 604 | this->insert(&insetNode); 605 | createDatabase("default"); 606 | cout << "ok!" <close(); 615 | sysdat->close(); 616 | } 617 | 618 | bool Core::condVerify(vector head, vector record, condexp_node *cond) { 619 | if (!cond) return true; 620 | if (cond->type == cond->LOGIC) { 621 | if (cond->op == condexp_node::AND) { 622 | return condVerify(head, record, cond->left) && condVerify(head, record, cond->right); 623 | } else if (cond->op == condexp_node::OR) { 624 | return condVerify(head, record, cond->left) || condVerify(head, record, cond->right); 625 | } 626 | } else { 627 | char *fieldName = cond->left->chval; 628 | string value; 629 | if (cond->right->type == condexp_node::STRING) { 630 | value = string(cond->right->chval); 631 | } else { 632 | value = to_string(cond->right->intval); 633 | } 634 | int intval = cond->right->intval; 635 | int i = 0; 636 | for (i = 0; i < head.size(); i++) { 637 | if (strcmp(fieldName, head[i].field_name) == 0) { 638 | if (head[i].type == head[i].INT) { 639 | if (cond->op == condexp_node::EQ) { 640 | return record[i].intval == intval; 641 | } else if (cond->op == condexp_node::G) { 642 | return record[i].intval > intval; 643 | } else if (cond->op == condexp_node::B) { 644 | return record[i].intval < intval; 645 | }else if (cond->op == condexp_node::NOT) { 646 | return record[i].intval != intval; 647 | } 648 | } else if (head[i].type == head[i].STRING) { 649 | string recstringval(record[i].chval); 650 | if (cond->op == condexp_node::EQ) { 651 | return recstringval == value; 652 | } else if (cond->op == condexp_node::G) { 653 | return recstringval > value; 654 | } else if (cond->op == condexp_node::B) { 655 | return recstringval < value; 656 | }else if (cond->op == condexp_node::NOT) { 657 | return recstringval != value; 658 | } 659 | } 660 | } 661 | } 662 | } 663 | return true; 664 | } 665 | 666 | int Core::sqldelete(select_node *deleteNode) { 667 | int delNum = 0; 668 | // 获取要删除的表名 669 | char *tableName = deleteNode->table->tableName; 670 | // auto tables = getTables(); 671 | // bool findflag = false; 672 | // for (auto t:tables){ 673 | // if (strcmp(tableName, t.tableName)==0){ 674 | // findflag = true; 675 | // break; 676 | // } 677 | // } 678 | // if (!findflag){ 679 | // cout << "There is no table named: " << tableName << endl; 680 | // return 0; 681 | // } 682 | // 获取表的所有列属性 683 | auto tableCols = getColumn(tableName); 684 | vector head = tableCols; 685 | 686 | auto datpageNum = getTableStartDatPage(tableName); 687 | //获取每条记录的长度 688 | int Recordlength = tableCols.at(tableCols.size() - 1).offset + tableCols.at(tableCols.size() - 1).len; 689 | 690 | while (datpageNum != -1) { 691 | if (!readPage(*InUsedat, datpageNum)) { 692 | cout << "SELECT: readPage Error!" << endl; 693 | } 694 | int i = 0; 695 | while ((i+1) * Recordlength + sizeof(int) <= PAGE_SIZE){ 696 | if (*(DATPAGE + i * Recordlength) != '\0') { 697 | vector row; 698 | for (auto h : head) { 699 | values_node node; 700 | if (h.type == table_field_node::INT) { // int 701 | node.intval = *(int *) (DATPAGE + i * Recordlength + h.offset); 702 | node.type = values_node::INT; 703 | } else { // string 704 | node.chval = _S(DATPAGE + i * Recordlength + h.offset); 705 | node.type = values_node::STRING; 706 | } 707 | row.push_back(node); 708 | } 709 | if (condVerify(head, row, deleteNode->cons)){ //将待删除的记录置0 710 | memset(DATPAGE + i*Recordlength, '\0', static_cast(Recordlength)); 711 | delNum++; 712 | } 713 | } 714 | i++; 715 | } 716 | writePage(*InUsedat, datpageNum); 717 | datpageNum = getNextPageNum(); 718 | } 719 | return delNum; 720 | } 721 | 722 | int Core::deleteDatabase(char *databaseName) { 723 | 724 | auto deleteNode = new select_node; 725 | auto deleteTable = new table_node; 726 | deleteTable->tableName = _S("database"); 727 | deleteNode->table = deleteTable; 728 | auto cons = new condexp_node; 729 | cons->op = cons->EQ; 730 | cons->left = new condexp_node; 731 | cons->left->chval = _S("name"); 732 | cons->right = new condexp_node; 733 | cons->right->chval = databaseName; 734 | cons->right->type = cons->right->STRING; 735 | deleteNode->cons = cons; 736 | InUsedb->close(); 737 | InUsedat->close(); 738 | useDatabase("sys"); 739 | char dbfileName[40] = {0}; 740 | char datfileName[40] = {0}; 741 | strcat_s(dbfileName, strlen(databaseName) + 1, databaseName); 742 | strcat_s(dbfileName, ".db"); 743 | strcat_s(datfileName, strlen(databaseName) + 1, databaseName); 744 | strcat_s(datfileName, ".dat"); 745 | 746 | if (sqldelete(deleteNode) && remove(dbfileName) && remove(datfileName)){ 747 | return 1; 748 | } 749 | return 0; 750 | } 751 | 752 | int Core::sqlupdate(update_node * updateNode) { 753 | int updateNum = 0; 754 | // 获取要删除的表名 755 | char *tableName = updateNode->table->tableName; 756 | // 获取表的所有列属性 757 | auto tableCols = getColumn(tableName); 758 | vector head = tableCols; 759 | 760 | auto datpageNum = getTableStartDatPage(tableName); 761 | //获取每条记录的长度 762 | int Recordlength = tableCols.at(tableCols.size() - 1).offset + tableCols.at(tableCols.size() - 1).len; 763 | 764 | while (datpageNum != -1) { 765 | if (!readPage(*InUsedat, datpageNum)) { 766 | cout << "SELECT: readPage Error!" << endl; 767 | } 768 | int i = 0; 769 | while ((i+1) * Recordlength + sizeof(int) <= PAGE_SIZE){ 770 | if (*(DATPAGE + i * Recordlength) != '\0') { 771 | vector row; 772 | for (auto h : head) { 773 | values_node node; 774 | if (h.type == table_field_node::INT) { // int 775 | node.intval = *(int *) (DATPAGE + i * Recordlength + h.offset); 776 | node.type = values_node::INT; 777 | } else { // string 778 | node.chval = _S(DATPAGE + i * Recordlength + h.offset); 779 | node.type = values_node::STRING; 780 | } 781 | row.push_back(node); 782 | } 783 | if (condVerify(head, row, updateNode->cons)){ // 784 | auto setNode = updateNode->setval; 785 | while (setNode){ 786 | for (auto h:head) { 787 | if (strcmp(h.field_name, setNode->field_name) ==0){ 788 | if (h.type == table_field_node::INT) { // int 789 | *(int *) (DATPAGE + i * Recordlength + h.offset) = setNode->intval; 790 | } else { // string 791 | strcpy_s(DATPAGE + i * Recordlength + h.offset, strlen(setNode->chval)+1, setNode->chval); 792 | } 793 | } 794 | } 795 | setNode = setNode->next; 796 | } 797 | updateNum++; 798 | } 799 | } 800 | i++; 801 | } 802 | writePage(*InUsedat, datpageNum); 803 | datpageNum = getNextPageNum(); 804 | } 805 | return updateNum; 806 | } 807 | 808 | int Core::deleteTable(const char * tableName) { 809 | auto tablesNow = getTables(); 810 | char temp[100] = {0}; 811 | for (auto t : tablesNow) { 812 | if (strcmp(t.tableName, tableName) == 0) { 813 | int PageNow = 0; //表字典 814 | for (int i = 0; i < 20; i++) { 815 | int offset = PageNow * PAGE_SIZE + i * 100; 816 | InUsedb->seekg(offset); 817 | InUsedb->seekp(InUsedb->tellg()); 818 | InUsedb->read(temp, 100); 819 | if (strcmp(temp, tableName)==0) { 820 | InUsedb->seekp(offset); 821 | memset(temp,'\0', 100); 822 | InUsedb->write(temp, 100); 823 | break; 824 | } 825 | } 826 | PageNow = 1; // 列字典从 1 页开始存放 827 | 828 | for (int i = 0; i < 20; i++) { 829 | std::streampos offset = PageNow * PAGE_SIZE + i * 100; 830 | InUsedb->seekg(offset); 831 | InUsedb->seekp(offset); 832 | InUsedb->read(temp, 100); 833 | if (strcmp(temp, tableName)==0) { 834 | InUsedb->seekp(offset); 835 | memset(temp,'\0', 100); 836 | InUsedb->write(temp, 100); //清空该记录向 837 | } 838 | } 839 | return 1; 840 | } 841 | } 842 | return 0; 843 | } 844 | 845 | char Core::DATPAGE[PAGE_SIZE]; 846 | int Core::TEMP[10]; --------------------------------------------------------------------------------