├── .gitignore ├── test ├── main.cpp ├── layouttest.cpp ├── lexertest.cpp ├── parsertest.cpp ├── filetest.cpp ├── buffertest.cpp ├── bufferfiletest.cpp ├── tablemanagertest.cpp ├── plannertest1.cpp ├── indexretrievaltest.cpp ├── buffermanagertest.cpp ├── tokenizertest.cpp ├── plannertest2.cpp ├── catalogtest.cpp ├── producttest.cpp ├── scantest1.cpp ├── logtest.cpp ├── transactiontest.cpp ├── tablescantest.cpp ├── indexselecttest.cpp ├── recordtest.cpp ├── parsertestactions.cpp ├── scantest2.cpp ├── indexjointest.cpp └── indexupdatetest.cpp ├── include ├── multibuffer │ ├── bufferneeds.hpp │ ├── multibufferproductplan.hpp │ ├── chunkscan.hpp │ └── multibufferproductscan.hpp ├── parse │ ├── pushbackreader.hpp │ ├── predparser.hpp │ ├── deletedata.hpp │ ├── createtabledata.hpp │ ├── createviewdata.hpp │ ├── insertdata.hpp │ ├── querydata.hpp │ ├── createindexdata.hpp │ ├── lexer.hpp │ ├── modifydata.hpp │ ├── object.hpp │ ├── streamtokenizer.hpp │ └── parser.hpp ├── plan │ ├── queryplanner.hpp │ ├── plan.hpp │ ├── basicqueryplanner.hpp │ ├── productplan.hpp │ ├── selectplan.hpp │ ├── planner.hpp │ ├── projectplan.hpp │ ├── tableplan.hpp │ ├── basicupdateplanner.hpp │ └── updateplanner.hpp ├── materialize │ ├── recordcomparator.hpp │ ├── aggregationfn.hpp │ ├── maxfn.hpp │ ├── groupvalue.hpp │ ├── temptable.hpp │ ├── materializeplan.hpp │ ├── groupbyplan.hpp │ ├── mergejoinplan.hpp │ ├── mergejoinscan.hpp │ ├── groupbyscan.hpp │ ├── sortscan.hpp │ └── sortplan.hpp ├── jdbc │ ├── embedded │ │ ├── embeddeddriver.hpp │ │ ├── embeddedmetadata.hpp │ │ ├── embeddedstatement.hpp │ │ ├── embeddedconnection.hpp │ │ └── embeddedresultset.hpp │ ├── driveradapter.hpp │ ├── statementadapter.hpp │ └── resultsetmetadataadapter.hpp ├── record │ ├── rid.hpp │ ├── layout.hpp │ ├── recordpage.hpp │ ├── schema.hpp │ └── tablescan.hpp ├── index │ ├── btree │ │ ├── direntry.hpp │ │ ├── btreeleaf.hpp │ │ ├── btreedir.hpp │ │ ├── btreeindex.hpp │ │ └── btpage.hpp │ ├── index.hpp │ ├── planner │ │ ├── indexselectplan.hpp │ │ ├── indexjoinplan.hpp │ │ └── indexupdateplanner.hpp │ ├── query │ │ ├── indexselectscan.hpp │ │ └── indexjoinscan.hpp │ └── hash │ │ └── hashindex.hpp ├── tx │ ├── concurrency │ │ ├── concurrencymanager.hpp │ │ └── locktable.hpp │ ├── bufferlist.hpp │ ├── recovery │ │ └── recoverymanager.hpp │ └── transaction.hpp ├── query │ ├── scan.hpp │ ├── term.hpp │ ├── updatescan.hpp │ ├── productscan.hpp │ ├── expression.hpp │ ├── projectscan.hpp │ ├── predicate.hpp │ ├── constant.hpp │ └── selectscan.hpp ├── metadata │ ├── tablemanager.hpp │ ├── viewmanager.hpp │ ├── statmanager.hpp │ ├── metadatamanager.hpp │ └── indexmanager.hpp ├── file │ ├── filemanager.hpp │ ├── blockid.hpp │ └── page.hpp ├── server │ └── simpledb.hpp ├── opt │ ├── heuristicqueryplanner.hpp │ └── tableplanner.hpp ├── log │ └── logmanager.hpp ├── utils │ └── utils.hpp └── buffer │ └── buffermanager.hpp ├── src ├── parse │ ├── deletedata.cpp │ ├── createtabledata.cpp │ ├── createviewdata.cpp │ ├── insertdata.cpp │ ├── createindexdata.cpp │ ├── modifydata.cpp │ ├── pushbackreader.cpp │ ├── predparser.cpp │ └── querydata.cpp ├── materialize │ ├── maxfn.cpp │ ├── recordcomparator.cpp │ ├── temptable.cpp │ ├── groupvalue.cpp │ ├── materializeplan.cpp │ ├── groupbyplan.cpp │ ├── mergejoinplan.cpp │ ├── groupbyscan.cpp │ ├── sortscan.cpp │ └── mergejoinscan.cpp ├── jdbc │ ├── embedded │ │ ├── embeddeddriver.cpp │ │ ├── embeddedconnection.cpp │ │ ├── embeddedmetadata.cpp │ │ ├── embeddedstatement.cpp │ │ └── embeddedresultset.cpp │ └── driveradapter.cpp ├── index │ ├── btree │ │ ├── direntry.cpp │ │ └── btreedir.cpp │ ├── planner │ │ ├── indexselectplan.cpp │ │ └── indexjoinplan.cpp │ ├── query │ │ ├── indexselectscan.cpp │ │ └── indexjoinscan.cpp │ └── hash │ │ └── hashindex.cpp ├── record │ ├── rid.cpp │ ├── layout.cpp │ └── schema.cpp ├── multibuffer │ ├── bufferneeds.cpp │ ├── chunkscan.cpp │ ├── multibufferproductplan.cpp │ └── multibufferproductscan.cpp ├── plan │ ├── tableplan.cpp │ ├── projectplan.cpp │ ├── productplan.cpp │ ├── selectplan.cpp │ ├── planner.cpp │ └── basicqueryplanner.cpp ├── tx │ ├── concurrency │ │ ├── concurrencymanager.cpp │ │ └── locktable.cpp │ └── bufferlist.cpp ├── query │ ├── expression.cpp │ ├── projectscan.cpp │ ├── productscan.cpp │ └── constant.cpp ├── metadata │ ├── viewmanager.cpp │ ├── metadatamanager.cpp │ └── statmanager.cpp ├── server │ └── simpledb.cpp └── file │ └── blockid.cpp └── third_party └── mysql-connector-c++ ├── cppconn ├── version_info.h └── datatype.h └── mysql_error.h /.gitignore: -------------------------------------------------------------------------------- 1 | /other 2 | /build 3 | .git 4 | *.DS_Store 5 | *.bak 6 | -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | 3 | int main(int argc, char **argv) { 4 | ::testing::InitGoogleTest(&argc, argv); 5 | // ::testing::GTEST_FLAG(filter) = "tx_*"; 6 | return RUN_ALL_TESTS(); 7 | } 8 | -------------------------------------------------------------------------------- /include/multibuffer/bufferneeds.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace simpledb { 4 | class buffer_needs { 5 | public: 6 | static int best_root(int pAvailable, int pSize); 7 | static int best_factor(int pAvailable, int pSize); 8 | }; 9 | } // namespace simpledb 10 | -------------------------------------------------------------------------------- /include/parse/pushbackreader.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace simpledb { 7 | class push_back_reader { 8 | public: 9 | push_back_reader(std::istream &pIS); 10 | int read(); 11 | void unread(int pCh); 12 | 13 | private: 14 | int mCurrentPos; 15 | std::vector mV; 16 | }; 17 | } // namespace simpledb 18 | -------------------------------------------------------------------------------- /include/plan/queryplanner.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "parse/querydata.hpp" 4 | #include "tx/transaction.hpp" 5 | 6 | namespace simpledb { 7 | class query_planner { 8 | public: 9 | virtual ~query_planner() {} 10 | virtual std::shared_ptr create_plan(query_data *pQD, 11 | transaction *pTx) = 0; 12 | }; 13 | } // namespace simpledb 14 | -------------------------------------------------------------------------------- /include/parse/predparser.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "parse/lexer.hpp" 6 | 7 | namespace simpledb { 8 | class pred_parser { 9 | public: 10 | pred_parser(const std::string &pS); 11 | void field(); 12 | void constant(); 13 | void expression(); 14 | void term(); 15 | void predicate(); 16 | 17 | private: 18 | lexer mLex; 19 | }; 20 | } // namespace simpledb 21 | -------------------------------------------------------------------------------- /include/materialize/recordcomparator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "query/scan.hpp" 7 | 8 | namespace simpledb { 9 | class record_comparator { 10 | public: 11 | record_comparator(const std::vector &pFields); 12 | int compare(scan *s1, scan *s2); 13 | 14 | private: 15 | std::vector mFields; 16 | }; 17 | } // namespace simpledb 18 | -------------------------------------------------------------------------------- /src/parse/deletedata.cpp: -------------------------------------------------------------------------------- 1 | #include "parse/deletedata.hpp" 2 | 3 | namespace simpledb { 4 | int delete_data::op() { return remove; } 5 | 6 | delete_data::delete_data(const std::string &pTblName, const predicate &pPred) 7 | : mTblName(pTblName), mPred(pPred) {} 8 | 9 | std::string delete_data::table_name() const { return mTblName; } 10 | 11 | predicate delete_data::pred() const { return mPred; } 12 | } // namespace simpledb 13 | -------------------------------------------------------------------------------- /include/materialize/aggregationfn.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "query/constant.hpp" 6 | #include "query/scan.hpp" 7 | 8 | namespace simpledb { 9 | class aggregation_fn { 10 | public: 11 | ~aggregation_fn() {} 12 | virtual void process_first(scan *pS) = 0; 13 | virtual void process_next(scan *pS) = 0; 14 | virtual std::string field_name() = 0; 15 | virtual constant value() = 0; 16 | }; 17 | } // namespace simpledb 18 | -------------------------------------------------------------------------------- /test/layouttest.cpp: -------------------------------------------------------------------------------- 1 | #include "record/layout.hpp" 2 | #include "gtest/gtest.h" 3 | 4 | namespace simpledb { 5 | TEST(record, layout_test) { 6 | schema sch; 7 | sch.add_int_field("A"); 8 | sch.add_string_field("B", 9); 9 | layout lt(sch); 10 | for (const std::string &fldName : lt.get_schema().fields()) { 11 | int offset = lt.offset(fldName); 12 | std::cout << fldName << " has offset " << offset << std::endl; 13 | } 14 | } 15 | } // namespace simpledb 16 | -------------------------------------------------------------------------------- /include/jdbc/embedded/embeddeddriver.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "jdbc/driveradapter.hpp" 4 | #include "jdbc/embedded/embeddedconnection.hpp" 5 | 6 | namespace simpledb { 7 | class EmbeddedDriver : public DriverAdapter { 8 | public: 9 | EmbeddedConnection *connect(const sql::SQLString &hostName, 10 | const sql::SQLString &userName, 11 | const sql::SQLString &password); 12 | }; 13 | } // namespace simpledb 14 | -------------------------------------------------------------------------------- /include/materialize/maxfn.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "materialize/aggregationfn.hpp" 4 | 5 | namespace simpledb { 6 | class max_fn : public aggregation_fn { 7 | public: 8 | max_fn(const std::string &pFldName); 9 | void process_first(scan *s) override; 10 | void process_next(scan *pS) override; 11 | std::string field_name() override; 12 | constant value() override; 13 | 14 | private: 15 | std::string mFldName; 16 | constant mVal; 17 | }; 18 | } // namespace simpledb 19 | -------------------------------------------------------------------------------- /include/plan/plan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "query/scan.hpp" 6 | #include "record/schema.hpp" 7 | 8 | namespace simpledb { 9 | class plan { 10 | public: 11 | virtual ~plan() {} 12 | virtual std::shared_ptr open() = 0; 13 | virtual int blocks_accessed() = 0; 14 | virtual int records_output() = 0; 15 | virtual int distinct_values(const std::string &pFldName) = 0; 16 | virtual schema get_schema() = 0; 17 | }; 18 | } // namespace simpledb 19 | -------------------------------------------------------------------------------- /include/record/rid.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace simpledb { 6 | class rid { 7 | friend bool operator==(const rid &pLhs, const rid &pRhs); 8 | 9 | public: 10 | rid(const rid &pRID); 11 | rid(int pBlockNum, int pSlot); 12 | int block_number() const; 13 | int slot() const; 14 | bool equals(const rid &pRID) const; 15 | std::string to_string() const; 16 | 17 | private: 18 | int mBlockNum; 19 | int mSlot; 20 | }; 21 | 22 | } // namespace simpledb 23 | -------------------------------------------------------------------------------- /include/index/btree/direntry.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "query/constant.hpp" 4 | 5 | namespace simpledb { 6 | class dir_entry { 7 | public: 8 | dir_entry(); 9 | dir_entry(const dir_entry &pDE); 10 | dir_entry(const constant &pDataVal, int pBlockNum); 11 | dir_entry &operator=(const dir_entry &pDE); 12 | constant data_val() const; 13 | int block_number() const; 14 | bool is_null() const; 15 | 16 | private: 17 | constant mDataVal; 18 | int mBlockNum; 19 | }; 20 | } // namespace simpledb 21 | -------------------------------------------------------------------------------- /src/parse/createtabledata.cpp: -------------------------------------------------------------------------------- 1 | #include "parse/createtabledata.hpp" 2 | 3 | namespace simpledb { 4 | int create_table_data::op() { return createtable; } 5 | 6 | create_table_data::create_table_data(const std::string &pTblName, 7 | const schema &pSch) 8 | : mTblName(pTblName), mSch(pSch) {} 9 | 10 | std::string create_table_data::table_name() const { return mTblName; } 11 | 12 | schema create_table_data::new_schema() const { return mSch; } 13 | } // namespace simpledb 14 | -------------------------------------------------------------------------------- /include/parse/deletedata.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "parse/object.hpp" 7 | #include "query/predicate.hpp" 8 | 9 | namespace simpledb { 10 | class delete_data : public object { 11 | public: 12 | int op() override; 13 | delete_data(const std::string &pTblName, const predicate &pPred); 14 | std::string table_name() const; 15 | predicate pred() const; 16 | 17 | private: 18 | std::string mTblName; 19 | predicate mPred; 20 | }; 21 | } // namespace simpledb 22 | -------------------------------------------------------------------------------- /include/plan/basicqueryplanner.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "metadata/metadatamanager.hpp" 4 | #include "plan/queryplanner.hpp" 5 | #include "tx/transaction.hpp" 6 | 7 | namespace simpledb { 8 | class basic_query_planner : public query_planner { 9 | public: 10 | basic_query_planner(metadata_manager *pMM); 11 | std::shared_ptr create_plan(query_data *pData, 12 | transaction *pTx) override; 13 | 14 | private: 15 | metadata_manager *mMM; 16 | }; 17 | } // namespace simpledb 18 | -------------------------------------------------------------------------------- /include/parse/createtabledata.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "parse/object.hpp" 7 | #include "record/schema.hpp" 8 | 9 | namespace simpledb { 10 | class create_table_data : public object { 11 | public: 12 | int op() override; 13 | create_table_data(const std::string &pTblName, const schema &pSch); 14 | std::string table_name() const; 15 | schema new_schema() const; 16 | 17 | private: 18 | std::string mTblName; 19 | schema mSch; 20 | }; 21 | } // namespace simpledb 22 | -------------------------------------------------------------------------------- /src/parse/createviewdata.cpp: -------------------------------------------------------------------------------- 1 | #include "parse/createviewdata.hpp" 2 | 3 | namespace simpledb { 4 | int create_view_data::op() { return createview; } 5 | 6 | create_view_data::create_view_data(const std::string &pViewName, 7 | std::unique_ptr pQD) 8 | : mViewName(pViewName), mQD(std::move(pQD)) {} 9 | 10 | std::string create_view_data::view_name() const { return mViewName; } 11 | 12 | std::string create_view_data::view_def() const { return mQD->to_string(); } 13 | } // namespace simpledb 14 | -------------------------------------------------------------------------------- /include/tx/concurrency/concurrencymanager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "file/blockid.hpp" 6 | #include "tx/concurrency/locktable.hpp" 7 | 8 | namespace simpledb { 9 | class concurrency_manager { 10 | public: 11 | void slock(const block_id &pBlockId); 12 | void xlock(const block_id &pBlockId); 13 | void release(); 14 | 15 | private: 16 | static lock_table mLockTable; 17 | std::map mLocks; 18 | 19 | bool has_xlock(const block_id &pBlockId); 20 | }; 21 | } // namespace simpledb 22 | -------------------------------------------------------------------------------- /include/index/index.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "query/constant.hpp" 4 | #include "record/rid.hpp" 5 | 6 | namespace simpledb { 7 | class index { 8 | public: 9 | virtual ~index() {} 10 | virtual void before_first(const constant &pSearchKey) = 0; 11 | virtual bool next() = 0; 12 | virtual rid get_data_rid() = 0; 13 | virtual void insert(const constant &pDataVal, const rid &pDataRID) = 0; 14 | virtual void remove(const constant &pDataVal, const rid &pDataRID) = 0; 15 | virtual void close() = 0; 16 | }; 17 | } // namespace simpledb 18 | -------------------------------------------------------------------------------- /src/materialize/maxfn.cpp: -------------------------------------------------------------------------------- 1 | #include "materialize/maxfn.hpp" 2 | 3 | namespace simpledb { 4 | max_fn::max_fn(const std::string &pFldName) : mFldName(pFldName) {} 5 | 6 | void max_fn::process_first(scan *pS) { mVal = pS->get_val(mFldName); } 7 | 8 | void max_fn::process_next(scan *pS) { 9 | constant newVal = pS->get_val(mFldName); 10 | if (newVal > mVal) { 11 | mVal = newVal; 12 | } 13 | } 14 | 15 | std::string max_fn::field_name() { return "maxof" + mFldName; } 16 | 17 | constant max_fn::value() { return mVal; } 18 | } // namespace simpledb 19 | -------------------------------------------------------------------------------- /include/tx/bufferlist.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "buffer/buffermanager.hpp" 7 | 8 | namespace simpledb { 9 | class buffer_list { 10 | public: 11 | buffer_list(buffer_manager *pBM); 12 | buffer *get_buffer(const block_id &pBlockId); 13 | void pin(const block_id &pBlockId); 14 | void unpin(const block_id &pBlockId); 15 | void unpin_all(); 16 | 17 | private: 18 | std::map mBuffers; 19 | std::vector mPins; 20 | buffer_manager *mBM; 21 | }; 22 | } // namespace simpledb 23 | -------------------------------------------------------------------------------- /src/jdbc/embedded/embeddeddriver.cpp: -------------------------------------------------------------------------------- 1 | #include "jdbc/embedded/embeddeddriver.hpp" 2 | 3 | namespace simpledb { 4 | EmbeddedConnection *EmbeddedDriver::connect(const sql::SQLString &pHostName, 5 | const sql::SQLString &pUsername, 6 | const sql::SQLString &pPassword) { 7 | sql::SQLString url = pUsername + ":" + pPassword + "@" + pHostName; 8 | auto db = std::make_unique(url.asStdString()); 9 | return new EmbeddedConnection(std::move(db)); 10 | } 11 | } // namespace simpledb 12 | -------------------------------------------------------------------------------- /include/parse/createviewdata.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "parse/object.hpp" 7 | #include "parse/querydata.hpp" 8 | 9 | namespace simpledb { 10 | class create_view_data : public object { 11 | public: 12 | int op() override; 13 | create_view_data(const std::string &pViewName, 14 | std::unique_ptr pQD); 15 | std::string view_name() const; 16 | std::string view_def() const; 17 | 18 | private: 19 | std::string mViewName; 20 | std::unique_ptr mQD; 21 | }; 22 | } // namespace simpledb 23 | -------------------------------------------------------------------------------- /include/query/scan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "query/constant.hpp" 6 | 7 | namespace simpledb { 8 | class scan { 9 | public: 10 | virtual ~scan() = default; 11 | virtual void before_first() = 0; 12 | virtual bool next() = 0; 13 | virtual int get_int(const std::string &pFldName) = 0; 14 | virtual std::string get_string(const std::string &pFldName) = 0; 15 | virtual constant get_val(const std::string &pFldName) = 0; 16 | virtual bool has_field(const std::string &pFldName) = 0; 17 | virtual void close() = 0; 18 | }; 19 | } // namespace simpledb 20 | -------------------------------------------------------------------------------- /include/jdbc/embedded/embeddedmetadata.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "jdbc/resultsetmetadataadapter.hpp" 4 | #include "record/schema.hpp" 5 | 6 | namespace simpledb { 7 | class EmbeddedMetaData : public ResultSetMetaDataAdapter { 8 | public: 9 | EmbeddedMetaData(const schema &pSch); 10 | unsigned int getColumnCount() override; 11 | sql::SQLString getColumnName(unsigned int pColumn) override; 12 | int getColumnType(unsigned int pColumn) override; 13 | unsigned int getColumnDisplaySize(unsigned int pColumn) override; 14 | 15 | private: 16 | schema mSch; 17 | }; 18 | } // namespace simpledb 19 | -------------------------------------------------------------------------------- /src/materialize/recordcomparator.cpp: -------------------------------------------------------------------------------- 1 | #include "materialize/recordcomparator.hpp" 2 | 3 | namespace simpledb { 4 | record_comparator::record_comparator(const std::vector &pFields) 5 | : mFields(pFields) {} 6 | 7 | int record_comparator::compare(scan *s1, scan *s2) { 8 | for (const std::string &fldName : mFields) { 9 | constant val1 = s1->get_val(fldName); 10 | constant val2 = s2->get_val(fldName); 11 | if (val1 < val2) { 12 | return -1; 13 | } 14 | if (val2 < val1) { 15 | return 1; 16 | } 17 | } 18 | return 0; 19 | } 20 | } // namespace simpledb 21 | -------------------------------------------------------------------------------- /include/metadata/tablemanager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "record/layout.hpp" 6 | #include "record/schema.hpp" 7 | #include "tx/transaction.hpp" 8 | 9 | namespace simpledb { 10 | class table_manager { 11 | public: 12 | table_manager(bool pIsNew, transaction *pTx); 13 | void create_table(const std::string &pTblName, const schema &pSch, 14 | transaction *pTx); 15 | layout get_layout(const std::string &pTblName, transaction *pTx); 16 | const int mMaxName = 16; 17 | 18 | private: 19 | layout mTCatLayout, mFCatLayout; 20 | }; 21 | } // namespace simpledb 22 | -------------------------------------------------------------------------------- /include/plan/productplan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "plan/plan.hpp" 6 | 7 | namespace simpledb { 8 | class product_plan : public plan { 9 | public: 10 | product_plan(const std::shared_ptr &pP1, 11 | const std::shared_ptr &pP2); 12 | std::shared_ptr open() override; 13 | int blocks_accessed() override; 14 | int records_output() override; 15 | int distinct_values(const std::string &pFldName) override; 16 | schema get_schema() override; 17 | 18 | private: 19 | std::shared_ptr mP1, mP2; 20 | schema mSch; 21 | }; 22 | } // namespace simpledb 23 | -------------------------------------------------------------------------------- /include/plan/selectplan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "plan/plan.hpp" 6 | #include "query/predicate.hpp" 7 | 8 | namespace simpledb { 9 | class select_plan : public plan { 10 | public: 11 | select_plan(const std::shared_ptr &pPlan, const predicate &pPred); 12 | std::shared_ptr open() override; 13 | int blocks_accessed() override; 14 | int records_output() override; 15 | int distinct_values(const std::string &pFldName) override; 16 | schema get_schema() override; 17 | 18 | private: 19 | std::shared_ptr mPlan; 20 | predicate mPred; 21 | }; 22 | } // namespace simpledb 23 | -------------------------------------------------------------------------------- /src/parse/insertdata.cpp: -------------------------------------------------------------------------------- 1 | #include "parse/insertdata.hpp" 2 | 3 | namespace simpledb { 4 | int insert_data::op() { return insert; } 5 | 6 | insert_data::insert_data(const std::string &pTblName, 7 | const std::vector &pFlds, 8 | const std::vector &pVals) 9 | : mTblName(pTblName), mFlds(pFlds), mVals(pVals) {} 10 | 11 | std::string insert_data::table_name() const { return mTblName; } 12 | 13 | std::vector insert_data::fields() const { return mFlds; } 14 | 15 | std::vector insert_data::vals() const { return mVals; } 16 | } // namespace simpledb 17 | -------------------------------------------------------------------------------- /include/materialize/groupvalue.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "query/constant.hpp" 8 | #include "query/scan.hpp" 9 | 10 | namespace simpledb { 11 | class group_value { 12 | friend bool operator==(const group_value &pR, const group_value &pL); 13 | friend bool operator!=(const group_value &pR, const group_value &pL); 14 | 15 | public: 16 | group_value(scan *s, const std::vector &pFields); 17 | constant get_val(const std::string &pFldName); 18 | int hash_code(); 19 | 20 | private: 21 | std::map mVals; 22 | }; 23 | } // namespace simpledb 24 | -------------------------------------------------------------------------------- /include/plan/planner.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "plan/queryplanner.hpp" 6 | #include "plan/updateplanner.hpp" 7 | 8 | namespace simpledb { 9 | class planner { 10 | public: 11 | planner(std::unique_ptr pQP, 12 | std::unique_ptr pUP); 13 | std::shared_ptr create_query_plan(const std::string &pCMD, 14 | transaction *pTx); 15 | int execute_update(const std::string &pCMD, transaction *pTx); 16 | 17 | private: 18 | std::unique_ptr mQP; 19 | std::unique_ptr mUP; 20 | }; 21 | } // namespace simpledb 22 | -------------------------------------------------------------------------------- /include/metadata/viewmanager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "metadata/tablemanager.hpp" 6 | #include "record/tablescan.hpp" 7 | #include "tx/transaction.hpp" 8 | 9 | namespace simpledb { 10 | class view_manager { 11 | public: 12 | view_manager(bool pIsNew, table_manager *pTM, transaction *pTx); 13 | void create_view(const std::string &pVName, const std::string &pVDef, 14 | transaction *pTx); 15 | std::string get_view_def(const std::string &pVName, transaction *pTx); 16 | 17 | private: 18 | const int mMaxViewDiff = 100; // max view def chars 19 | table_manager *mTM; 20 | }; 21 | } // namespace simpledb 22 | -------------------------------------------------------------------------------- /include/materialize/temptable.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "query/updatescan.hpp" 6 | #include "record/layout.hpp" 7 | #include "record/tablescan.hpp" 8 | #include "tx/transaction.hpp" 9 | 10 | namespace simpledb { 11 | class temp_table { 12 | public: 13 | temp_table(transaction *pTx, const schema &pSch); 14 | std::shared_ptr open(); 15 | std::string table_name(); 16 | layout get_layout(); 17 | std::string next_table_name(); 18 | 19 | private: 20 | static int mNextTableNum; 21 | static std::mutex mMutex; 22 | transaction *mTx; 23 | std::string mTblName; 24 | layout mLayout; 25 | }; 26 | } // namespace simpledb 27 | -------------------------------------------------------------------------------- /include/plan/projectplan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "plan/plan.hpp" 8 | 9 | namespace simpledb { 10 | class project_plan : public plan { 11 | public: 12 | project_plan(const std::shared_ptr &pP, 13 | const std::vector &pFieldList); 14 | std::shared_ptr open() override; 15 | int blocks_accessed() override; 16 | int records_output() override; 17 | int distinct_values(const std::string &pFldName) override; 18 | schema get_schema() override; 19 | 20 | private: 21 | std::shared_ptr mP; 22 | schema mSch; 23 | }; 24 | } // namespace simpledb 25 | -------------------------------------------------------------------------------- /include/index/planner/indexselectplan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "metadata/indexmanager.hpp" 4 | #include "plan/plan.hpp" 5 | 6 | namespace simpledb { 7 | class index_select_plan : public plan { 8 | public: 9 | index_select_plan(const std::shared_ptr &pP, const index_info &pII, 10 | const constant &pVal); 11 | std::shared_ptr open() override; 12 | int blocks_accessed() override; 13 | int records_output() override; 14 | int distinct_values(const std::string &pFldName) override; 15 | schema get_schema() override; 16 | 17 | private: 18 | std::shared_ptr mP; 19 | index_info mII; 20 | constant mVal; 21 | }; 22 | } // namespace simpledb 23 | -------------------------------------------------------------------------------- /src/parse/createindexdata.cpp: -------------------------------------------------------------------------------- 1 | #include "parse/createindexdata.hpp" 2 | 3 | namespace simpledb { 4 | int create_index_data::op() { return createindex; } 5 | 6 | create_index_data::create_index_data(const std::string &pIdxName, 7 | const std::string &pTblName, 8 | const std::string &pFldName) 9 | : mIdxName(pIdxName), mTblName(pTblName), mFldName(pFldName) {} 10 | 11 | std::string create_index_data::index_name() const { return mIdxName; } 12 | 13 | std::string create_index_data::table_name() const { return mTblName; } 14 | 15 | std::string create_index_data::field_name() const { return mFldName; } 16 | } // namespace simpledb 17 | -------------------------------------------------------------------------------- /include/jdbc/embedded/embeddedstatement.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "jdbc/embedded/embeddedresultset.hpp" 4 | #include "jdbc/embedded/embeddedstatement.hpp" 5 | #include "jdbc/statementadapter.hpp" 6 | #include "plan/planner.hpp" 7 | 8 | namespace simpledb { 9 | class EmbeddedConnection; 10 | 11 | class EmbeddedStatement : public StatementAdapter { 12 | public: 13 | EmbeddedStatement(EmbeddedConnection &pConn, planner &pPlanner); 14 | EmbeddedResultSet *executeQuery(const sql::SQLString &pSQL); 15 | 16 | int executeUpdate(const sql::SQLString &pSQL); 17 | 18 | void close(); 19 | 20 | private: 21 | EmbeddedConnection &mConn; 22 | planner &mPlanner; 23 | }; 24 | 25 | } // namespace simpledb 26 | -------------------------------------------------------------------------------- /include/parse/insertdata.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "parse/object.hpp" 7 | #include "query/constant.hpp" 8 | 9 | namespace simpledb { 10 | class insert_data : public object { 11 | public: 12 | int op() override; 13 | insert_data(const std::string &pTblName, 14 | const std::vector &pFlds, 15 | const std::vector &pVals); 16 | std::string table_name() const; 17 | std::vector fields() const; 18 | std::vector vals() const; 19 | 20 | private: 21 | std::string mTblName; 22 | std::vector mFlds; 23 | std::vector mVals; 24 | }; 25 | } // namespace simpledb 26 | -------------------------------------------------------------------------------- /include/parse/querydata.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "query/predicate.hpp" 9 | 10 | namespace simpledb { 11 | class query_data { 12 | public: 13 | query_data(const std::vector pFields, 14 | const std::set &pTables, const predicate &pPred); 15 | 16 | std::vector fields() const; 17 | 18 | std::set tables() const; 19 | 20 | predicate pred() const; 21 | 22 | std::string to_string() const; 23 | 24 | private: 25 | std::vector mFields; 26 | std::set mTables; 27 | predicate mPred; 28 | }; 29 | } // namespace simpledb 30 | -------------------------------------------------------------------------------- /include/query/term.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "plan/plan.hpp" 4 | #include "query/expression.hpp" 5 | 6 | namespace simpledb { 7 | class term { 8 | public: 9 | term(); 10 | term(const term &pT); 11 | term(const expression &pLhs, const expression &pRhs); 12 | term &operator=(const term &pT); 13 | bool is_satisfied(scan *pS) const; 14 | bool applies_to(const schema &pSch) const; 15 | int reduction_factor(plan *pPlan) const; 16 | constant equates_with_constant(const std::string &pFldName) const; 17 | std::string equates_with_field(const std::string &pFldName) const; 18 | std::string to_string() const; 19 | 20 | private: 21 | expression mLhs, mRhs; 22 | }; 23 | } // namespace simpledb 24 | -------------------------------------------------------------------------------- /test/lexertest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "parse/lexer.hpp" 5 | #include "gtest/gtest.h" 6 | 7 | namespace simpledb { 8 | TEST(parse, lexer_test) { 9 | std::string s = ""; 10 | std::stringstream sS("A=1 \n 3=A"); 11 | std::string x = ""; 12 | int y = 0; 13 | while (std::getline(sS, s, '\n')) { 14 | lexer lex(s); 15 | if (lex.match_id()) { 16 | x = lex.eat_id(); 17 | lex.eat_delim('='); 18 | y = lex.eat_int_constant(); 19 | } else { 20 | y = lex.eat_int_constant(); 21 | lex.eat_delim('='); 22 | x = lex.eat_id(); 23 | } 24 | std::cout << x << " equals " << y << std::endl; 25 | } 26 | } 27 | } // namespace simpledb 28 | -------------------------------------------------------------------------------- /src/parse/modifydata.cpp: -------------------------------------------------------------------------------- 1 | #include "parse/modifydata.hpp" 2 | 3 | namespace simpledb { 4 | int modify_data::op() { return modify; } 5 | 6 | modify_data::modify_data(const std::string &pTblName, 7 | const std::string &pFldName, const expression &pNewVal, 8 | const predicate &pPred) 9 | : mTblName(pTblName), mFldName(pFldName), mNewVal(pNewVal), mPred(pPred) {} 10 | 11 | std::string modify_data::table_name() const { return mTblName; } 12 | 13 | std::string modify_data::target_field() const { return mFldName; } 14 | 15 | expression modify_data::new_value() const { return mNewVal; } 16 | 17 | predicate modify_data::pred() const { return mPred; } 18 | } // namespace simpledb 19 | -------------------------------------------------------------------------------- /include/materialize/materializeplan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "plan/plan.hpp" 4 | #include "query/updatescan.hpp" 5 | #include "record/layout.hpp" 6 | #include "record/tablescan.hpp" 7 | #include "tx/transaction.hpp" 8 | 9 | namespace simpledb { 10 | class materialize_plan : public plan { 11 | public: 12 | materialize_plan(transaction *pTx, const std::shared_ptr &pSrcPlan); 13 | std::shared_ptr open() override; 14 | int blocks_accessed() override; 15 | int records_output() override; 16 | int distinct_values(const std::string &pFldName) override; 17 | schema get_schema() override; 18 | 19 | private: 20 | transaction *mTx; 21 | std::shared_ptr mSrcPlan; 22 | }; 23 | } // namespace simpledb 24 | -------------------------------------------------------------------------------- /include/record/layout.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "record/schema.hpp" 6 | 7 | namespace simpledb { 8 | class layout { 9 | public: 10 | layout(); 11 | layout(const layout &pLt); 12 | 13 | layout(const schema &pSchema); 14 | layout(const schema &pSchema, const std::map &pOffsets, 15 | int pSlotSize); 16 | 17 | layout &operator=(const layout &pLt); 18 | schema get_schema() const; 19 | int offset(const std::string &pFldName); 20 | int slot_size() const; 21 | 22 | private: 23 | schema mSchema; 24 | std::map mOffsets; 25 | int mSlotSize; 26 | 27 | int length_in_bytes(const std::string &pFldName); 28 | }; 29 | } // namespace simpledb 30 | -------------------------------------------------------------------------------- /include/query/updatescan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "query/constant.hpp" 6 | #include "query/scan.hpp" 7 | #include "record/rid.hpp" 8 | 9 | namespace simpledb { 10 | class update_scan : public scan { 11 | public: 12 | virtual ~update_scan() = default; 13 | virtual void set_int(const std::string &pFldName, int pVal) = 0; 14 | virtual void set_string(const std::string &pFldName, 15 | const std::string &pVal) = 0; 16 | virtual void set_val(const std::string &pFldName, const constant &pVal) = 0; 17 | virtual void insert() = 0; 18 | virtual void remove() = 0; 19 | virtual rid get_rid() = 0; 20 | virtual void move_to_rid(const rid &pRID) = 0; 21 | }; 22 | } // namespace simpledb 23 | -------------------------------------------------------------------------------- /include/jdbc/embedded/embeddedconnection.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "jdbc/connectionadapter.hpp" 6 | #include "jdbc/embedded/embeddedstatement.hpp" 7 | #include "server/simpledb.hpp" 8 | #include "tx/transaction.hpp" 9 | 10 | namespace simpledb { 11 | class EmbeddedConnection : public ConnectionAdapter { 12 | public: 13 | EmbeddedConnection(std::unique_ptr pDb); 14 | EmbeddedStatement *createStatement() override; 15 | void close() override; 16 | void commit() override; 17 | void rollback() override; 18 | transaction &getTransaction(); 19 | 20 | private: 21 | std::unique_ptr mDb; 22 | std::unique_ptr mCurrentTx; 23 | planner &mPlanner; 24 | }; 25 | } // namespace simpledb 26 | -------------------------------------------------------------------------------- /include/jdbc/embedded/embeddedresultset.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "jdbc/resultsetadapter.hpp" 4 | #include "plan/plan.hpp" 5 | #include "query/scan.hpp" 6 | #include "record/schema.hpp" 7 | 8 | namespace simpledb { 9 | class EmbeddedConnection; 10 | class EmbeddedResultSet : public ResultSetAdapter { 11 | public: 12 | EmbeddedResultSet(plan &pPlan, EmbeddedConnection &pConn); 13 | bool next(); 14 | int32_t getInt(const sql::SQLString &pColumnLabel) const; 15 | sql::SQLString getString(const sql::SQLString &pColumnLabel) const; 16 | sql::ResultSetMetaData *getMetaData() const; 17 | void close(); 18 | 19 | private: 20 | EmbeddedConnection &mConn; 21 | std::shared_ptr mS; 22 | schema mSch; 23 | }; 24 | } // namespace simpledb 25 | -------------------------------------------------------------------------------- /include/query/productscan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "query/scan.hpp" 6 | 7 | namespace simpledb { 8 | class product_scan : public scan { 9 | public: 10 | product_scan(const std::shared_ptr &pS1, 11 | const std::shared_ptr &pS2); 12 | 13 | void before_first() override; 14 | bool next() override; 15 | int get_int(const std::string &pFldName) override; 16 | std::string get_string(const std::string &pFldName) override; 17 | constant get_val(const std::string &pFldName) override; 18 | bool has_field(const std::string &pFldName) override; 19 | void close() override; 20 | 21 | private: 22 | std::shared_ptr mS1; 23 | std::shared_ptr mS2; 24 | }; 25 | } // namespace simpledb 26 | -------------------------------------------------------------------------------- /src/index/btree/direntry.cpp: -------------------------------------------------------------------------------- 1 | #include "index/btree/direntry.hpp" 2 | 3 | namespace simpledb { 4 | dir_entry::dir_entry() {} 5 | dir_entry::dir_entry(const dir_entry &pDE) 6 | : mDataVal(pDE.mDataVal), mBlockNum(pDE.mBlockNum) {} 7 | dir_entry::dir_entry(const constant &pDataVal, int pBlockNum) 8 | : mDataVal(pDataVal), mBlockNum(pBlockNum) {} 9 | dir_entry &dir_entry::operator=(const dir_entry &pDE) { 10 | if (this != &pDE) { 11 | mDataVal = pDE.mDataVal; 12 | mBlockNum = pDE.mBlockNum; 13 | } 14 | return *this; 15 | } 16 | constant dir_entry::data_val() const { return mDataVal; } 17 | int dir_entry::block_number() const { return mBlockNum; } 18 | 19 | bool dir_entry::is_null() const { return mDataVal.is_null(); } 20 | } // namespace simpledb 21 | -------------------------------------------------------------------------------- /include/plan/tableplan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "metadata/metadatamanager.hpp" 6 | #include "plan/plan.hpp" 7 | #include "query/predicate.hpp" 8 | #include "tx/transaction.hpp" 9 | 10 | namespace simpledb { 11 | class table_plan : public plan { 12 | public: 13 | table_plan(transaction *pTx, const std::string &pTblName, 14 | metadata_manager *pMM); 15 | std::shared_ptr open() override; 16 | int blocks_accessed() override; 17 | int records_output() override; 18 | int distinct_values(const std::string &pFldName) override; 19 | schema get_schema() override; 20 | 21 | private: 22 | transaction *mTx; 23 | std::string mTblName; 24 | layout mLt; 25 | stat_info mSI; 26 | }; 27 | } // namespace simpledb 28 | -------------------------------------------------------------------------------- /include/parse/createindexdata.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "parse/object.hpp" 6 | 7 | namespace simpledb { 8 | class create_index_data : public object { 9 | public: 10 | int op() override; 11 | // create_index_data(); 12 | // create_index_data(const create_index_data &pCID); 13 | create_index_data(const std::string &pIdxName, const std::string &pTblName, 14 | const std::string &pFldName); 15 | // create_index_data& operator=(const create_index_data &pCID); 16 | std::string index_name() const; 17 | std::string table_name() const; 18 | std::string field_name() const; 19 | 20 | private: 21 | std::string mIdxName; 22 | std::string mTblName; 23 | std::string mFldName; 24 | }; 25 | } // namespace simpledb 26 | -------------------------------------------------------------------------------- /src/record/rid.cpp: -------------------------------------------------------------------------------- 1 | #include "record/rid.hpp" 2 | 3 | namespace simpledb { 4 | bool operator==(const rid &pLhs, const rid &pRhs) { 5 | return (pLhs.mBlockNum == pRhs.mBlockNum) && (pLhs.mSlot == pRhs.mSlot); 6 | } 7 | rid::rid(const rid &pRID) : mBlockNum(pRID.mBlockNum), mSlot(pRID.mSlot) {} 8 | 9 | rid::rid(int pBlockNum, int pSlot) : mBlockNum(pBlockNum), mSlot(pSlot) {} 10 | 11 | int rid::block_number() const { return mBlockNum; } 12 | 13 | int rid::slot() const { return mSlot; } 14 | 15 | bool rid::equals(const rid &pRID) const { 16 | return (mBlockNum == pRID.block_number()) && (mSlot == pRID.slot()); 17 | } 18 | 19 | std::string rid::to_string() const { 20 | return "[" + std::to_string(mBlockNum) + ", " + std::to_string(mSlot) + "]"; 21 | } 22 | } // namespace simpledb 23 | -------------------------------------------------------------------------------- /include/jdbc/driveradapter.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "mysql-connector-c++/cppconn/driver.h" 4 | 5 | namespace simpledb { 6 | class DriverAdapter : public sql::Driver { 7 | public: 8 | virtual sql::Connection *connect(const sql::SQLString &hostName, 9 | const sql::SQLString &userName, 10 | const sql::SQLString &password) override; 11 | virtual sql::Connection *connect(sql::ConnectOptionsMap &options) override; 12 | virtual int getMajorVersion() override; 13 | virtual int getMinorVersion() override; 14 | virtual int getPatchVersion() override; 15 | virtual const sql::SQLString &getName() override; 16 | virtual void threadInit() override; 17 | virtual void threadEnd() override; 18 | }; 19 | } // namespace simpledb 20 | -------------------------------------------------------------------------------- /include/query/expression.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "query/constant.hpp" 7 | #include "query/scan.hpp" 8 | #include "record/schema.hpp" 9 | 10 | namespace simpledb { 11 | class expression { 12 | public: 13 | expression(); 14 | expression(const expression &pE); 15 | expression(const constant &pVal); 16 | expression(const std::string &pFldName); 17 | expression &operator=(const expression &pE); 18 | bool is_field_name() const; 19 | constant as_constant() const; 20 | std::string as_field_name() const; 21 | constant evaluate(scan *pS) const; 22 | bool applies_to(const schema &pSch) const; 23 | std::string to_string() const; 24 | 25 | private: 26 | constant mVal; 27 | std::string mFldName; 28 | }; 29 | } // namespace simpledb 30 | -------------------------------------------------------------------------------- /src/parse/pushbackreader.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "parse/pushbackreader.hpp" 4 | 5 | namespace simpledb { 6 | push_back_reader::push_back_reader(std::istream &pIS) : mCurrentPos(0) { 7 | // get length of input 8 | pIS.seekg(0, pIS.end); 9 | int length = pIS.tellg(); 10 | pIS.seekg(0, pIS.beg); 11 | 12 | mV.resize(length); 13 | pIS.read(&(mV[0]), length); 14 | } 15 | 16 | int push_back_reader::read() { 17 | if (mCurrentPos == static_cast(mV.size())) { 18 | return -1; 19 | } 20 | return static_cast(mV[mCurrentPos++]); 21 | } 22 | 23 | void push_back_reader::unread(int pCh) { 24 | if (mCurrentPos == 0) { 25 | throw std::runtime_error("push back buffer is full"); 26 | } 27 | mV[--mCurrentPos] = static_cast(pCh); 28 | } 29 | } // namespace simpledb 30 | -------------------------------------------------------------------------------- /include/index/planner/indexjoinplan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "metadata/indexmanager.hpp" 6 | #include "plan/plan.hpp" 7 | 8 | namespace simpledb { 9 | class index_join_plan : public plan { 10 | public: 11 | index_join_plan(const std::shared_ptr &pP1, 12 | const std::shared_ptr &pP2, const index_info &pII, 13 | const std::string &pJoinField); 14 | std::shared_ptr open() override; 15 | int blocks_accessed() override; 16 | int records_output() override; 17 | int distinct_values(const std::string &pFldName) override; 18 | schema get_schema() override; 19 | 20 | private: 21 | std::shared_ptr mP1, mP2; 22 | index_info mII; 23 | std::string mJoinField; 24 | schema mSch; 25 | }; 26 | } // namespace simpledb 27 | -------------------------------------------------------------------------------- /include/parse/lexer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "parse/streamtokenizer.hpp" 8 | 9 | namespace simpledb { 10 | class lexer { 11 | public: 12 | lexer(const std::string &pS); 13 | bool match_delim(const char &pD); 14 | bool match_int_constant(); 15 | bool match_string_constant(); 16 | bool match_keyword(const std::string &pW); 17 | bool match_id(); 18 | void eat_delim(const char &pD); 19 | int eat_int_constant(); 20 | std::string eat_string_constant(); 21 | void eat_keyword(const std::string &pW); 22 | std::string eat_id(); 23 | 24 | private: 25 | std::set mKeywords; 26 | std::unique_ptr mTok; 27 | 28 | void next_token(); 29 | void init_keywords(); 30 | }; 31 | } // namespace simpledb 32 | -------------------------------------------------------------------------------- /src/jdbc/embedded/embeddedconnection.cpp: -------------------------------------------------------------------------------- 1 | #include "jdbc/embedded/embeddedconnection.hpp" 2 | 3 | namespace simpledb { 4 | EmbeddedConnection::EmbeddedConnection(std::unique_ptr pDb) 5 | : mDb(std::move(pDb)), mCurrentTx(mDb->new_tx()), mPlanner(mDb->plnr()) {} 6 | 7 | EmbeddedStatement *EmbeddedConnection::createStatement() { 8 | return new EmbeddedStatement(*this, mPlanner); 9 | } 10 | 11 | void EmbeddedConnection::close() { mCurrentTx->commit(); } 12 | 13 | void EmbeddedConnection::commit() { 14 | mCurrentTx->commit(); 15 | mCurrentTx = mDb->new_tx(); 16 | } 17 | 18 | void EmbeddedConnection::rollback() { 19 | mCurrentTx->rollback(); 20 | mCurrentTx = mDb->new_tx(); 21 | } 22 | 23 | transaction &EmbeddedConnection::getTransaction() { return *mCurrentTx; } 24 | } // namespace simpledb 25 | -------------------------------------------------------------------------------- /include/tx/recovery/recoverymanager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "buffer/buffermanager.hpp" 6 | #include "log/logmanager.hpp" 7 | 8 | namespace simpledb { 9 | class transaction; 10 | 11 | class recovery_manager { 12 | public: 13 | recovery_manager(transaction *pTx, int pTxNum, log_manager *pLM, 14 | buffer_manager *pBM); 15 | 16 | void commit(); 17 | 18 | void rollback(); 19 | 20 | void recover(); 21 | 22 | int set_int(buffer *pBuff, int pOffset, int pNewVal); 23 | 24 | int set_string(buffer *pBuff, int pOffset, const std::string &pNewVal); 25 | 26 | private: 27 | transaction *mTx; 28 | int mTxNum; 29 | log_manager *mLM; 30 | buffer_manager *mBM; 31 | 32 | void do_rollback(); 33 | void do_recover(); 34 | }; 35 | } // namespace simpledb 36 | -------------------------------------------------------------------------------- /src/materialize/temptable.cpp: -------------------------------------------------------------------------------- 1 | #include "materialize/temptable.hpp" 2 | 3 | namespace simpledb { 4 | int temp_table::mNextTableNum = 0; 5 | std::mutex temp_table::mMutex; 6 | 7 | temp_table::temp_table(transaction *pTx, const schema &pSch) 8 | : mTx(pTx), mTblName(next_table_name()), mLayout(pSch) {} 9 | 10 | std::shared_ptr temp_table::open() { 11 | return std::static_pointer_cast( 12 | std::make_shared(mTx, mTblName, mLayout)); 13 | } 14 | 15 | std::string temp_table::table_name() { return mTblName; } 16 | 17 | layout temp_table::get_layout() { return mLayout; } 18 | 19 | std::string temp_table::next_table_name() { 20 | std::unique_lock lock(mMutex); 21 | mNextTableNum++; 22 | return "temp" + std::to_string(mNextTableNum); 23 | } 24 | } // namespace simpledb 25 | -------------------------------------------------------------------------------- /include/query/projectscan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "query/scan.hpp" 8 | 9 | namespace simpledb { 10 | class project_scan : public scan { 11 | public: 12 | project_scan(const std::shared_ptr &pS, 13 | const std::vector &pFieldList); 14 | 15 | void before_first() override; 16 | bool next() override; 17 | int get_int(const std::string &pFldName) override; 18 | std::string get_string(const std::string &pFldName) override; 19 | constant get_val(const std::string &pFldName) override; 20 | bool has_field(const std::string &pFldName) override; 21 | void close() override; 22 | 23 | private: 24 | std::shared_ptr mS; 25 | std::vector mFieldList; 26 | }; 27 | } // namespace simpledb 28 | -------------------------------------------------------------------------------- /include/index/planner/indexupdateplanner.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "metadata/metadatamanager.hpp" 4 | #include "plan/updateplanner.hpp" 5 | 6 | namespace simpledb { 7 | class index_update_planner : public update_planner { 8 | public: 9 | index_update_planner(metadata_manager *pMM); 10 | int execute_insert(insert_data *pID, transaction *pTx) override; 11 | int execute_delete(delete_data *pDD, transaction *pTx) override; 12 | int execute_modify(modify_data *pMD, transaction *pTx) override; 13 | int execute_create_table(create_table_data *pCTD, transaction *pTx) override; 14 | int execute_create_view(create_view_data *pCVD, transaction *pTx) override; 15 | int execute_create_index(create_index_data *pCID, transaction *pTx) override; 16 | 17 | private: 18 | metadata_manager *mMM; 19 | }; 20 | } // namespace simpledb 21 | -------------------------------------------------------------------------------- /include/multibuffer/multibufferproductplan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "materialize/temptable.hpp" 4 | #include "plan/plan.hpp" 5 | #include "tx/transaction.hpp" 6 | 7 | namespace simpledb { 8 | class multibuffer_product_plan : public plan { 9 | public: 10 | multibuffer_product_plan(transaction &tx, const std::shared_ptr &pLhs, 11 | const std::shared_ptr &pRhs); 12 | std::shared_ptr open() override; 13 | int blocks_accessed() override; 14 | int records_output() override; 15 | int distinct_values(const std::string &pFldName) override; 16 | schema get_schema() override; 17 | 18 | private: 19 | transaction &mTx; 20 | std::shared_ptr mLhs, mRhs; 21 | schema mSch; 22 | 23 | std::shared_ptr copy_records_from(plan &p); 24 | }; 25 | } // namespace simpledb 26 | -------------------------------------------------------------------------------- /src/parse/predparser.cpp: -------------------------------------------------------------------------------- 1 | #include "parse/predparser.hpp" 2 | 3 | namespace simpledb { 4 | pred_parser::pred_parser(const std::string &pS) : mLex(pS) {} 5 | 6 | void pred_parser::field() { mLex.eat_id(); } 7 | 8 | void pred_parser::constant() { 9 | if (mLex.match_string_constant()) { 10 | mLex.eat_string_constant(); 11 | } else { 12 | mLex.eat_int_constant(); 13 | } 14 | } 15 | 16 | void pred_parser::expression() { 17 | if (mLex.match_id()) { 18 | field(); 19 | } else { 20 | constant(); 21 | } 22 | } 23 | 24 | void pred_parser::term() { 25 | expression(); 26 | mLex.eat_delim('='); 27 | expression(); 28 | } 29 | 30 | void pred_parser::predicate() { 31 | term(); 32 | if (mLex.match_keyword("and")) { 33 | mLex.eat_keyword("and"); 34 | predicate(); 35 | } 36 | } 37 | } // namespace simpledb 38 | -------------------------------------------------------------------------------- /include/plan/basicupdateplanner.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "metadata/metadatamanager.hpp" 6 | #include "plan/updateplanner.hpp" 7 | 8 | namespace simpledb { 9 | class basic_update_planner : public update_planner { 10 | public: 11 | basic_update_planner(metadata_manager *pMM); 12 | int execute_insert(insert_data *pID, transaction *pTx) override; 13 | int execute_delete(delete_data *pDD, transaction *pTx) override; 14 | int execute_modify(modify_data *pMD, transaction *pTx) override; 15 | int execute_create_table(create_table_data *pCTD, transaction *pTx) override; 16 | int execute_create_view(create_view_data *pCVD, transaction *pTx) override; 17 | int execute_create_index(create_index_data *pCID, transaction *pTx) override; 18 | 19 | private: 20 | metadata_manager *mMM; 21 | }; 22 | } // namespace simpledb 23 | -------------------------------------------------------------------------------- /include/index/btree/btreeleaf.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "file/blockid.hpp" 6 | #include "index/btree/btpage.hpp" 7 | #include "index/btree/direntry.hpp" 8 | #include "record/layout.hpp" 9 | #include "record/rid.hpp" 10 | #include "tx/transaction.hpp" 11 | 12 | namespace simpledb { 13 | class btree_leaf { 14 | public: 15 | btree_leaf(transaction *pTx, const block_id &pBlk, const layout &pLt, 16 | const constant &pSeachKey); 17 | void close(); 18 | bool next(); 19 | rid get_data_rid(); 20 | void remove(const rid &pDataRid); 21 | dir_entry insert(const rid &pDataRID); 22 | bool try_overflow(); 23 | 24 | private: 25 | transaction *mTx; 26 | layout mLt; 27 | constant mSearchKey; 28 | std::unique_ptr mContents; 29 | int mCurrentSlot; 30 | std::string mFileName; 31 | }; 32 | } // namespace simpledb 33 | -------------------------------------------------------------------------------- /include/materialize/groupbyplan.hpp: -------------------------------------------------------------------------------- 1 | #include "materialize/aggregationfn.hpp" 2 | #include "plan/plan.hpp" 3 | #include "tx/transaction.hpp" 4 | 5 | namespace simpledb { 6 | class group_by_plan : public plan { 7 | public: 8 | group_by_plan(transaction *pTx, const std::shared_ptr &pP, 9 | const std::vector &pGroupFields, 10 | const std::vector> &pAffFns); 11 | std::shared_ptr open() override; 12 | int blocks_accessed() override; 13 | int records_output() override; 14 | int distinct_values(const std::string &pFldName) override; 15 | schema get_schema() override; 16 | 17 | private: 18 | std::shared_ptr mP; 19 | std::vector mGroupFields; 20 | std::vector> mAggFns; 21 | schema mSch; 22 | }; 23 | 24 | } // namespace simpledb 25 | -------------------------------------------------------------------------------- /include/materialize/mergejoinplan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "plan/plan.hpp" 6 | #include "query/scan.hpp" 7 | #include "record/schema.hpp" 8 | #include "tx/transaction.hpp" 9 | 10 | namespace simpledb { 11 | class merge_join_plan : public plan { 12 | public: 13 | merge_join_plan(transaction *pTx, const std::shared_ptr &pP1, 14 | const std::shared_ptr &pP2, 15 | const std::string &pFldName1, const std::string &pFldName2); 16 | std::shared_ptr open() override; 17 | int blocks_accessed() override; 18 | int records_output() override; 19 | int distinct_values(const std::string &pFldName) override; 20 | schema get_schema() override; 21 | 22 | private: 23 | std::shared_ptr mP1, mP2; 24 | std::string mFldName1, mFldName2; 25 | schema mSch; 26 | }; 27 | } // namespace simpledb 28 | -------------------------------------------------------------------------------- /src/multibuffer/bufferneeds.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "multibuffer/bufferneeds.hpp" 5 | 6 | namespace simpledb { 7 | int buffer_needs::best_root(int pAvailable, int pSize) { 8 | int avail = pAvailable - 2; // reserve a couple 9 | if (avail <= 1) { 10 | return 1; 11 | } 12 | int k = std::numeric_limits::max(); 13 | double i = 1.0; 14 | while (k > avail) { 15 | i++; 16 | k = std::ceil(std::pow(static_cast(pSize), 1 / i)); 17 | } 18 | return k; 19 | } 20 | 21 | int buffer_needs::best_factor(int pAvailable, int pSize) { 22 | int avail = pAvailable - 2; // reserve a couple 23 | if (avail <= 1) { 24 | return 1; 25 | } 26 | int k = pSize; 27 | double i = 1.0; 28 | while (k > avail) { 29 | i++; 30 | k = std::ceil(pSize / i); 31 | } 32 | return k; 33 | } 34 | } // namespace simpledb 35 | -------------------------------------------------------------------------------- /src/plan/tableplan.cpp: -------------------------------------------------------------------------------- 1 | #include "plan/tableplan.hpp" 2 | 3 | namespace simpledb { 4 | table_plan::table_plan(transaction *pTx, const std::string &pTblName, 5 | metadata_manager *pMM) 6 | : mTx(pTx), mTblName(pTblName) { 7 | mLt = pMM->get_layout(mTblName, mTx); 8 | mSI = pMM->get_stat_info(mTblName, mLt, mTx); 9 | } 10 | 11 | std::shared_ptr table_plan::open() { 12 | return std::static_pointer_cast( 13 | std::make_shared(mTx, mTblName, mLt)); 14 | } 15 | 16 | int table_plan::blocks_accessed() { return mSI.blocks_accessed(); } 17 | 18 | int table_plan::records_output() { return mSI.records_output(); } 19 | 20 | int table_plan::distinct_values(const std::string &pFldName) { 21 | return mSI.distinct_values(pFldName); 22 | } 23 | 24 | schema table_plan::get_schema() { return mLt.get_schema(); } 25 | } // namespace simpledb 26 | -------------------------------------------------------------------------------- /include/tx/concurrency/locktable.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "file/blockid.hpp" 10 | 11 | namespace simpledb { 12 | class lock_table { 13 | public: 14 | lock_table(); 15 | void slock(const block_id &pBlockId); 16 | void xlock(const block_id &pBlockId); 17 | void unlock(const block_id &pBlockId); 18 | 19 | private: 20 | const int mMaxTime = 10000; 21 | std::map mLocks; 22 | std::mutex mMutex; 23 | std::condition_variable mCondVar; 24 | 25 | bool has_xlock(const block_id &pBlockId); 26 | bool has_other_slocks(const block_id &pBlockId); 27 | bool waiting_too_long( 28 | std::chrono::time_point pStartTime); 29 | int get_lock_val(const block_id &pBlockId); 30 | }; 31 | } // namespace simpledb 32 | -------------------------------------------------------------------------------- /include/index/btree/btreedir.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "file/blockid.hpp" 7 | #include "index/btree/btpage.hpp" 8 | #include "index/btree/direntry.hpp" 9 | #include "query/constant.hpp" 10 | #include "record/layout.hpp" 11 | #include "tx/transaction.hpp" 12 | 13 | namespace simpledb { 14 | class btree_dir { 15 | public: 16 | btree_dir(transaction *pTx, const block_id &pBlk, const layout &pLt); 17 | void close(); 18 | int search(const constant &pSearchKey); 19 | void make_new_root(const dir_entry &pDE); 20 | dir_entry insert(const dir_entry &pDE); 21 | 22 | private: 23 | transaction *mTx; 24 | layout mLt; 25 | std::unique_ptr mContents; 26 | std::string mFileName; 27 | 28 | dir_entry insert_entry(const dir_entry &pDE); 29 | block_id find_child_block(const constant &pSearchKey); 30 | }; 31 | } // namespace simpledb 32 | -------------------------------------------------------------------------------- /include/parse/modifydata.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "parse/object.hpp" 7 | #include "query/expression.hpp" 8 | #include "query/predicate.hpp" 9 | 10 | namespace simpledb { 11 | class modify_data : public object { 12 | public: 13 | int op() override; 14 | // modify_data(); 15 | // modify_data(const modify_data &pMD); 16 | modify_data(const std::string &pTblName, const std::string &pFldName, 17 | const expression &pNewVal, const predicate &pPred); 18 | // modify_data& operator=(const modify_data &pMD); 19 | 20 | std::string table_name() const; 21 | 22 | std::string target_field() const; 23 | 24 | expression new_value() const; 25 | 26 | predicate pred() const; 27 | 28 | private: 29 | std::string mTblName; 30 | std::string mFldName; 31 | expression mNewVal; 32 | predicate mPred; 33 | }; 34 | } // namespace simpledb 35 | -------------------------------------------------------------------------------- /include/index/query/indexselectscan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "index/index.hpp" 7 | #include "query/constant.hpp" 8 | #include "record/tablescan.hpp" 9 | 10 | namespace simpledb { 11 | class index_select_scan : public scan { 12 | public: 13 | index_select_scan(const std::shared_ptr &pTS, 14 | const std::shared_ptr &pIdx, const constant &pVal); 15 | void before_first() override; 16 | bool next() override; 17 | int get_int(const std::string &pFldName) override; 18 | std::string get_string(const std::string &pFldName) override; 19 | constant get_val(const std::string &pFldName) override; 20 | bool has_field(const std::string &pFldName) override; 21 | void close() override; 22 | 23 | private: 24 | std::shared_ptr mTS; 25 | std::shared_ptr mIdx; 26 | constant mVal; 27 | }; 28 | } // namespace simpledb 29 | -------------------------------------------------------------------------------- /include/index/hash/hashindex.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "index/index.hpp" 4 | #include "query/constant.hpp" 5 | #include "record/layout.hpp" 6 | #include "record/tablescan.hpp" 7 | #include "tx/transaction.hpp" 8 | 9 | namespace simpledb { 10 | class hash_index : public index { 11 | public: 12 | hash_index(transaction *pTx, const std::string &pIdxName, const layout &pLt); 13 | void before_first(const constant &pSearckKey) override; 14 | bool next() override; 15 | rid get_data_rid() override; 16 | void insert(const constant &pDataVal, const rid &pDataRID) override; 17 | void remove(const constant &pDataVal, const rid &pDataRID) override; 18 | void close() override; 19 | static int search_cost(int pNumBlocks, int pRPB); 20 | static int mNumBuckets; 21 | 22 | private: 23 | transaction *mTx; 24 | std::string mIdxName; 25 | layout mLt; 26 | constant mSearchKey; 27 | std::unique_ptr mTS; 28 | }; 29 | } // namespace simpledb 30 | -------------------------------------------------------------------------------- /include/parse/object.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace simpledb { 5 | class object { 6 | public: 7 | enum operation { 8 | insert, 9 | remove, 10 | modify, 11 | createtable, 12 | createview, 13 | createindex 14 | }; 15 | virtual ~object(){}; 16 | virtual int op() = 0; 17 | }; 18 | 19 | inline std::ostream &operator<<(std::ostream &os, const object::operation &op) { 20 | switch (op) { 21 | case object::insert: 22 | os << "insert"; 23 | break; 24 | case object::remove: 25 | os << "remove"; 26 | break; 27 | case object::modify: 28 | os << "modify"; 29 | break; 30 | case object::createtable: 31 | os << "createtable"; 32 | break; 33 | case object::createview: 34 | os << "createview"; 35 | break; 36 | case object::createindex: 37 | os << "createindex"; 38 | break; 39 | default: 40 | break; 41 | } 42 | return os; 43 | } 44 | } // namespace simpledb 45 | -------------------------------------------------------------------------------- /include/materialize/mergejoinscan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "materialize/sortscan.hpp" 6 | #include "query/constant.hpp" 7 | 8 | namespace simpledb { 9 | class merge_join_scan : public scan { 10 | public: 11 | merge_join_scan(const std::shared_ptr &pS1, 12 | const std::shared_ptr &pS2, 13 | const std::string &pFldName1, const std::string &pFldName2); 14 | 15 | void before_first() override; 16 | bool next() override; 17 | int get_int(const std::string &pFldName) override; 18 | std::string get_string(const std::string &pFldName) override; 19 | constant get_val(const std::string &pFldName) override; 20 | bool has_field(const std::string &pFldName) override; 21 | void close() override; 22 | 23 | private: 24 | std::shared_ptr mS1; 25 | std::shared_ptr mS2; 26 | std::string mFldName1, mFldName2; 27 | constant mJoinVal; 28 | }; 29 | } // namespace simpledb 30 | -------------------------------------------------------------------------------- /src/plan/projectplan.cpp: -------------------------------------------------------------------------------- 1 | #include "plan/projectplan.hpp" 2 | #include "query/projectscan.hpp" 3 | 4 | namespace simpledb { 5 | project_plan::project_plan(const std::shared_ptr &pP, 6 | const std::vector &pFieldList) 7 | : mP(pP) { 8 | for (const std::string &fieldName : pFieldList) { 9 | mSch.add(fieldName, mP->get_schema()); 10 | } 11 | } 12 | 13 | std::shared_ptr project_plan::open() { 14 | std::shared_ptr s = mP->open(); 15 | return std::static_pointer_cast( 16 | std::make_shared(s, mSch.fields())); 17 | } 18 | 19 | int project_plan::blocks_accessed() { return mP->blocks_accessed(); } 20 | 21 | int project_plan::records_output() { return mP->records_output(); } 22 | 23 | int project_plan::distinct_values(const std::string &pFldName) { 24 | return mP->distinct_values(pFldName); 25 | } 26 | 27 | schema project_plan::get_schema() { return mSch; } 28 | } // namespace simpledb 29 | -------------------------------------------------------------------------------- /include/file/filemanager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "file/blockid.hpp" 9 | #include "file/page.hpp" 10 | 11 | namespace simpledb { 12 | class file_manager { 13 | public: 14 | file_manager(const std::filesystem::path &pDbDirectory, int pBlockSize); 15 | void read(const block_id &pBlockId, page &pPage); 16 | void write(const block_id &pBlockId, page &pPage); 17 | block_id append(const std::string &pFileName); 18 | bool is_new(); 19 | int block_size(); 20 | int length(const std::string &pFileName); 21 | 22 | private: 23 | std::shared_ptr get_file(const std::string &pFileName); 24 | int get_file_size(const std::string &pFileName); 25 | std::filesystem::path mDbDirectory; 26 | int mBlockSize; 27 | bool mIsNew; 28 | std::mutex mMutex; 29 | std::map> mOpenFiles; 30 | }; 31 | } // namespace simpledb 32 | -------------------------------------------------------------------------------- /src/tx/concurrency/concurrencymanager.cpp: -------------------------------------------------------------------------------- 1 | #include "tx/concurrency/concurrencymanager.hpp" 2 | 3 | namespace simpledb { 4 | // instantiate static member 5 | lock_table concurrency_manager::mLockTable; 6 | 7 | void concurrency_manager::slock(const block_id &pBlockId) { 8 | if (mLocks.find(pBlockId) == mLocks.end()) { 9 | mLockTable.slock(pBlockId); 10 | mLocks[pBlockId] = "S"; 11 | } 12 | } 13 | 14 | void concurrency_manager::xlock(const block_id &pBlockId) { 15 | if (!has_xlock(pBlockId)) { 16 | slock(pBlockId); 17 | mLockTable.xlock(pBlockId); 18 | mLocks[pBlockId] = "X"; 19 | } 20 | } 21 | 22 | void concurrency_manager::release() { 23 | for (auto &item : mLocks) { 24 | mLockTable.unlock(item.first); 25 | } 26 | mLocks.clear(); 27 | } 28 | 29 | bool concurrency_manager::has_xlock(const block_id &pBlockId) { 30 | auto iter = mLocks.find(pBlockId); 31 | return (iter != mLocks.end()) && (iter->second == "X"); 32 | } 33 | } // namespace simpledb 34 | -------------------------------------------------------------------------------- /test/parsertest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "parse/parser.hpp" 5 | #include "gtest/gtest.h" 6 | 7 | namespace simpledb { 8 | TEST(parse, parser_test) { 9 | std::string s1 = "select C from T where A =B"; 10 | std::string s2 = "insert into T(A, B, C) values('a' , 'b', 'c')"; 11 | std::string s3 = "delete from T where A=B"; 12 | std::string s4 = "update T set A='a' where B=C"; 13 | std::string s5 = "create table T(A int, B varchar(9))"; 14 | std::string s6 = "create view V as " + s1; 15 | std::string s7 = "create index I on T(A)"; 16 | 17 | parser p1(s1); 18 | p1.query(); 19 | 20 | parser p2(s2); 21 | p2.update_cmd(); 22 | 23 | parser p3(s3); 24 | p3.update_cmd(); 25 | 26 | parser p4(s4); 27 | p4.update_cmd(); 28 | 29 | parser p5(s5); 30 | p5.update_cmd(); 31 | 32 | parser p6(s6); 33 | p6.update_cmd(); 34 | 35 | parser p7(s7); 36 | p7.update_cmd(); 37 | } 38 | } // namespace simpledb 39 | -------------------------------------------------------------------------------- /include/index/btree/btreeindex.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "file/blockid.hpp" 6 | #include "index/btree/btreeleaf.hpp" 7 | #include "index/index.hpp" 8 | #include "record/layout.hpp" 9 | #include "tx/transaction.hpp" 10 | 11 | namespace simpledb { 12 | class btree_index : public index { 13 | public: 14 | btree_index(transaction *pTx, const std::string &pIdxName, const layout &mLt); 15 | void before_first(const constant &pSearchKey) override; 16 | bool next() override; 17 | rid get_data_rid() override; 18 | void insert(const constant &pDataVal, const rid &pDataRid) override; 19 | void remove(const constant &pDataVal, const rid &pDataRid) override; 20 | void close() override; 21 | static int search_cost(int pNumBlocks, int pRPB); 22 | 23 | private: 24 | transaction *mTx; 25 | std::string mLeafTbl; 26 | layout mDirLayout, mLeafLayout; 27 | std::unique_ptr mLeaf; 28 | block_id mRootBlk; 29 | }; 30 | } // namespace simpledb 31 | -------------------------------------------------------------------------------- /include/query/predicate.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "plan/plan.hpp" 7 | #include "query/scan.hpp" 8 | #include "query/term.hpp" 9 | #include "record/schema.hpp" 10 | 11 | namespace simpledb { 12 | class predicate { 13 | public: 14 | predicate(); 15 | predicate(const predicate &pPred); 16 | predicate(const term &pT); 17 | predicate &operator=(const predicate &pPred); 18 | bool is_null() const; 19 | void con_join_with(const predicate &pP); 20 | bool is_satisfied(scan *pS) const; 21 | int reduction_factor(plan *pPlan) const; 22 | predicate select_sub_pred(const schema &pSch) const; 23 | predicate join_sub_pred(const schema &pSch1, const schema &pSch2) const; 24 | constant equates_with_constant(const std::string &pFldName) const; 25 | std::string equates_with_field(const std::string &pFldName) const; 26 | std::string to_string() const; 27 | 28 | private: 29 | std::vector mTerms; 30 | }; 31 | } // namespace simpledb 32 | -------------------------------------------------------------------------------- /src/jdbc/embedded/embeddedmetadata.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "jdbc/embedded/embeddedmetadata.hpp" 4 | 5 | namespace simpledb { 6 | EmbeddedMetaData::EmbeddedMetaData(const schema &pSch) : mSch(pSch) {} 7 | 8 | unsigned int EmbeddedMetaData::getColumnCount() { return mSch.fields().size(); } 9 | 10 | sql::SQLString EmbeddedMetaData::getColumnName(unsigned int pColumn) { 11 | return sql::SQLString(mSch.fields()[pColumn - 1]); 12 | } 13 | 14 | int EmbeddedMetaData::getColumnType(unsigned int pColumn) { 15 | std::string fldName = getColumnName(pColumn).asStdString(); 16 | return mSch.type(fldName); 17 | } 18 | 19 | unsigned int EmbeddedMetaData::getColumnDisplaySize(unsigned int pColumn) { 20 | std::string fldName = getColumnName(pColumn).asStdString(); 21 | int fldType = mSch.type(fldName); 22 | int fldLength = (fldType == schema::integer) ? 6 : mSch.length(fldName); 23 | return std::max(static_cast(fldName.size()), fldLength) + 1; 24 | } 25 | } // namespace simpledb 26 | -------------------------------------------------------------------------------- /include/plan/updateplanner.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "parse/createindexdata.hpp" 4 | #include "parse/createtabledata.hpp" 5 | #include "parse/createviewdata.hpp" 6 | #include "parse/deletedata.hpp" 7 | #include "parse/insertdata.hpp" 8 | #include "parse/modifydata.hpp" 9 | #include "tx/transaction.hpp" 10 | 11 | namespace simpledb { 12 | class update_planner { 13 | public: 14 | virtual ~update_planner() {} 15 | virtual int execute_insert(insert_data *pID, transaction *pTx) = 0; 16 | virtual int execute_delete(delete_data *pDD, transaction *pTx) = 0; 17 | virtual int execute_modify(modify_data *pMD, transaction *pTx) = 0; 18 | virtual int execute_create_table(create_table_data *pCTD, 19 | transaction *pTx) = 0; 20 | virtual int execute_create_view(create_view_data *pCVD, transaction *pTx) = 0; 21 | virtual int execute_create_index(create_index_data *pCID, 22 | transaction *pTx) = 0; 23 | }; 24 | } // namespace simpledb 25 | -------------------------------------------------------------------------------- /test/filetest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "file/blockid.hpp" 4 | #include "file/filemanager.hpp" 5 | #include "file/page.hpp" 6 | #include "server/simpledb.hpp" 7 | #include "gtest/gtest.h" 8 | 9 | namespace simpledb { 10 | TEST(file, file_test) { 11 | simpledb db("filetest", 400, 8); 12 | file_manager &fM = db.file_mgr(); 13 | block_id blk("testfile", 2); 14 | int pos1 = 88; 15 | 16 | auto p1 = std::make_unique(fM.block_size()); 17 | std::string sample = "abcdefghijklm"; 18 | p1->set_string(pos1, sample); 19 | int size = page::max_length(sample.size()); 20 | int pos2 = pos1 + size; 21 | p1->set_int(pos2, 345); 22 | fM.write(blk, *p1); 23 | 24 | auto p2 = std::make_unique(fM.block_size()); 25 | fM.read(blk, *p2); 26 | std::cout << "offset " << pos2 << " contains " << p2->get_int(pos2) 27 | << std::endl; 28 | std::cout << "offset " << pos1 << " contains " << p2->get_string(pos1) 29 | << std::endl; 30 | } 31 | } // namespace simpledb 32 | -------------------------------------------------------------------------------- /include/server/simpledb.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "buffer/buffermanager.hpp" 4 | #include "file/filemanager.hpp" 5 | #include "log/logmanager.hpp" 6 | #include "metadata/metadatamanager.hpp" 7 | #include "plan/planner.hpp" 8 | #include "tx/transaction.hpp" 9 | 10 | namespace simpledb { 11 | class simpledb { 12 | public: 13 | static int mBlockSize; 14 | static int mBufferSize; 15 | static std::string mLogFile; 16 | 17 | simpledb(const std::string &pDirname, int pBlockSize, int pBuffSize); 18 | simpledb(const std::string &pDirname); 19 | 20 | std::unique_ptr new_tx(); 21 | metadata_manager &md_mgr(); 22 | planner &plnr(); 23 | file_manager &file_mgr(); 24 | log_manager &log_mgr(); 25 | buffer_manager &buffer_mgr(); 26 | 27 | private: 28 | std::unique_ptr mFM; 29 | std::unique_ptr mBM; 30 | std::unique_ptr mP; 31 | std::unique_ptr mLM; 32 | std::unique_ptr mMM; 33 | }; 34 | } // namespace simpledb 35 | -------------------------------------------------------------------------------- /include/index/query/indexjoinscan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "index/index.hpp" 6 | #include "record/tablescan.hpp" 7 | 8 | namespace simpledb { 9 | class index_join_scan : public scan { 10 | public: 11 | index_join_scan(const std::shared_ptr &pLhs, 12 | const std::shared_ptr &pIdx, 13 | const std::string &pJoinFld, 14 | const std::shared_ptr &pRhs); 15 | void before_first() override; 16 | bool next() override; 17 | int get_int(const std::string &pFldName) override; 18 | std::string get_string(const std::string &pFldName) override; 19 | constant get_val(const std::string &pFldName) override; 20 | bool has_field(const std::string &pFldName) override; 21 | void close() override; 22 | void reset_index(); 23 | 24 | private: 25 | std::shared_ptr mLhs; 26 | std::shared_ptr mIdx; 27 | std::string mJoinField; 28 | std::shared_ptr mRhs; 29 | }; 30 | } // namespace simpledb 31 | -------------------------------------------------------------------------------- /include/opt/heuristicqueryplanner.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "metadata/metadatamanager.hpp" 6 | #include "opt/tableplanner.hpp" 7 | #include "parse/querydata.hpp" 8 | #include "plan/plan.hpp" 9 | #include "plan/planner.hpp" 10 | #include "plan/queryplanner.hpp" 11 | #include "tx/transaction.hpp" 12 | 13 | namespace simpledb { 14 | class heuristic_query_planner : public query_planner { 15 | public: 16 | heuristic_query_planner(metadata_manager &pMM); 17 | std::shared_ptr create_plan(query_data *pData, 18 | transaction *pTx) override; 19 | std::shared_ptr get_lowest_select_plan(); 20 | std::shared_ptr 21 | get_lowest_join_plan(const std::shared_ptr &pCurrent); 22 | std::shared_ptr 23 | get_lowest_product_plan(const std::shared_ptr &pCurrent); 24 | void set_planner(planner *pP); 25 | 26 | private: 27 | metadata_manager &mMM; 28 | std::set> mTablePlanners; 29 | }; 30 | } // namespace simpledb 31 | -------------------------------------------------------------------------------- /include/file/blockid.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace simpledb { 6 | class block_id { 7 | friend bool operator==(const block_id &pLhs, const block_id &pRhs); 8 | friend bool operator!=(const block_id &pLhs, const block_id &pRhs); 9 | friend bool operator<(const block_id &pLhs, const block_id &pRhs); 10 | friend bool operator>(const block_id &pLhs, const block_id &pRhs); 11 | friend bool operator<=(const block_id &pLhs, const block_id &pRhs); 12 | friend bool operator>=(const block_id &pLhs, const block_id &pRhs); 13 | 14 | public: 15 | block_id(); 16 | block_id(const block_id &pBlk); 17 | block_id(const std::string &pFileName, int pBlockNum); 18 | block_id &operator=(const block_id &pBlk); 19 | 20 | bool is_null(); 21 | 22 | std::string file_name() const; 23 | 24 | int number() const; 25 | 26 | bool equals(const block_id &obj) const; 27 | 28 | std::string to_string() const; 29 | 30 | private: 31 | std::string mFileName; 32 | int mBlockNum; 33 | }; 34 | } // namespace simpledb 35 | -------------------------------------------------------------------------------- /include/multibuffer/chunkscan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "query/scan.hpp" 4 | #include "record/layout.hpp" 5 | #include "record/recordpage.hpp" 6 | #include "tx/transaction.hpp" 7 | 8 | namespace simpledb { 9 | class chunk_scan : public scan { 10 | public: 11 | chunk_scan(transaction *pTx, const std::string &pFileName, const layout &pLt, 12 | int pStartBNum, int pEndBNum); 13 | void before_first() override; 14 | bool next() override; 15 | int get_int(const std::string &pFldName) override; 16 | std::string get_string(const std::string &pFldName) override; 17 | constant get_val(const std::string &pFldName) override; 18 | bool has_field(const std::string &pFldName) override; 19 | void close() override; 20 | 21 | private: 22 | std::vector> mBuffs; 23 | transaction *mTx; 24 | std::string mFileName; 25 | layout mLt; 26 | int mStartBNum, mEndBNum, mCurrentBNum; 27 | record_page *mRP; 28 | int mCurrentSlot; 29 | 30 | void move_to_block(int pBlkNum); 31 | }; 32 | } // namespace simpledb 33 | -------------------------------------------------------------------------------- /include/multibuffer/multibufferproductscan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "query/scan.hpp" 4 | #include "record/layout.hpp" 5 | #include "tx/transaction.hpp" 6 | 7 | namespace simpledb { 8 | class multibuffer_product_scan : public scan { 9 | public: 10 | multibuffer_product_scan(transaction *pTx, 11 | const std::shared_ptr &pLhsScan, 12 | const std::string &pTblName, const layout &pLt); 13 | void before_first() override; 14 | bool next() override; 15 | int get_int(const std::string &pFldName) override; 16 | std::string get_string(const std::string &pFldName) override; 17 | constant get_val(const std::string &pFldName) override; 18 | bool has_field(const std::string &pFldName) override; 19 | void close() override; 20 | 21 | private: 22 | transaction *mTx; 23 | std::shared_ptr mLhsScan, mRhsScan, mProdScan; 24 | std::string mFileName; 25 | layout mLt; 26 | int mChunkSize, mNextBlkNum, mFileSize; 27 | 28 | bool use_next_chunk(); 29 | }; 30 | } // namespace simpledb 31 | -------------------------------------------------------------------------------- /include/query/constant.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace simpledb { 7 | class constant { 8 | friend bool operator==(const constant &pLhs, const constant &pRhs); 9 | friend bool operator!=(const constant &pLhs, const constant &pRhs); 10 | friend bool operator<(const constant &pLhs, const constant &pRhs); 11 | friend bool operator>(const constant &pLhs, const constant &pRhs); 12 | friend bool operator<=(const constant &pLhs, const constant &pRhs); 13 | friend bool operator>=(const constant &pLhs, const constant &pRhs); 14 | 15 | public: 16 | constant(); 17 | constant(const constant &pVal); 18 | constant(int pVal); 19 | constant(const std::string &pVal); 20 | constant &operator=(const constant &pVal); 21 | int as_int() const; 22 | std::string as_string() const; 23 | std::string to_string() const; 24 | int hash_code() const; 25 | bool is_null() const; 26 | 27 | private: 28 | std::unique_ptr mIVal; 29 | std::unique_ptr mSVal; 30 | }; 31 | } // namespace simpledb 32 | -------------------------------------------------------------------------------- /test/buffertest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "buffer/buffermanager.hpp" 4 | #include "file/blockid.hpp" 5 | #include "file/filemanager.hpp" 6 | #include "file/page.hpp" 7 | #include "server/simpledb.hpp" 8 | #include "gtest/gtest.h" 9 | 10 | namespace simpledb { 11 | TEST(buffer, buffer_test) { 12 | simpledb db("buffertest", 400, 3); // three buffers 13 | buffer_manager &bM = db.buffer_mgr(); 14 | 15 | std::string testFile = "testfile"; 16 | buffer *buff1 = bM.pin(block_id(testFile, 1)); 17 | page *p = buff1->contents(); 18 | int n = p->get_int(80); 19 | p->set_int(80, n + 1); 20 | buff1->set_modified(1, 0); 21 | std::cout << "The new value is " << (n + 1) << std::endl; 22 | bM.unpin(buff1); 23 | 24 | buffer *buff2 = bM.pin(block_id(testFile, 2)); 25 | bM.pin(block_id(testFile, 3)); 26 | bM.pin(block_id(testFile, 4)); 27 | 28 | bM.unpin(buff2); 29 | buff2 = bM.pin(block_id(testFile, 1)); 30 | page *p2 = buff2->contents(); 31 | p2->set_int(80, 9999); 32 | buff2->set_modified(1, 0); 33 | } 34 | } // namespace simpledb 35 | -------------------------------------------------------------------------------- /include/file/page.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace simpledb { 8 | class page { 9 | public: 10 | page(int pBlockSize); 11 | 12 | page(const std::shared_ptr> &pByteBuffer); 13 | 14 | int get_int(int pOffset) const; 15 | 16 | void set_int(int pOffset, int n); 17 | 18 | std::vector get_bytes(int pOffset) const; 19 | 20 | void set_bytes(int pOffset, const std::vector &pByteBuffer); 21 | 22 | std::string get_string(int pOffset) const; 23 | 24 | void set_string(int pOffset, const std::string &pString); 25 | 26 | static int max_length(int pStrLen); 27 | 28 | std::shared_ptr> 29 | contents(); // sometimes page contents should be alive after the death of page 30 | // instance (ここがただのポインタを返してしまうと, 31 | // pageが死んだあとnullになる) 32 | 33 | private: 34 | std::shared_ptr> 35 | mByteBuffer; // ここがただのポインタだと開放するのを忘れてしまう恐れがあり. 36 | // コンストラクタでもできるので. 37 | }; 38 | } // namespace simpledb 39 | -------------------------------------------------------------------------------- /src/materialize/groupvalue.cpp: -------------------------------------------------------------------------------- 1 | #include "materialize/groupvalue.hpp" 2 | 3 | namespace simpledb { 4 | bool operator==(const group_value &pR, const group_value &pL) { 5 | for (const auto &[fldName, valueR] : pR.mVals) { 6 | if (pL.mVals.find(fldName) == pL.mVals.end() || 7 | pL.mVals.at(fldName) != valueR) { 8 | return false; 9 | } 10 | } 11 | return true; 12 | } 13 | 14 | bool operator!=(const group_value &pR, const group_value &pL) { 15 | if (pR == pL) { 16 | return false; 17 | } else { 18 | return true; 19 | } 20 | } 21 | 22 | group_value::group_value(scan *s, const std::vector &pFields) { 23 | for (const std::string &fldName : pFields) { 24 | mVals[fldName] = s->get_val(fldName); 25 | } 26 | } 27 | 28 | constant group_value::get_val(const std::string &pFldName) { 29 | return mVals.at(pFldName); 30 | } 31 | 32 | int group_value::hash_code() { 33 | int hashVal = 0; 34 | for (const auto &[fldName, value] : mVals) { 35 | hashVal += value.hash_code(); 36 | } 37 | return hashVal; 38 | } 39 | 40 | } // namespace simpledb 41 | -------------------------------------------------------------------------------- /src/jdbc/driveradapter.cpp: -------------------------------------------------------------------------------- 1 | #include "mysql-connector-c++/cppconn/exception.h" 2 | 3 | #include "jdbc/driveradapter.hpp" 4 | 5 | namespace simpledb { 6 | sql::Connection *DriverAdapter::connect(const sql::SQLString &hostName, 7 | const sql::SQLString &userName, 8 | const sql::SQLString &password) { 9 | throw sql::SQLException("operation not implemented"); 10 | } 11 | sql::Connection *DriverAdapter::connect(sql::ConnectOptionsMap &options) { 12 | throw sql::SQLException("operation not implemented"); 13 | } 14 | int DriverAdapter::getMajorVersion() { return 0; } 15 | int DriverAdapter::getMinorVersion() { return 0; } 16 | int DriverAdapter::getPatchVersion() { return 0; } 17 | const sql::SQLString &DriverAdapter::getName() { 18 | throw sql::SQLException("operation not implemented"); 19 | } 20 | void DriverAdapter::threadInit() { 21 | throw sql::SQLException("operation not implemented"); 22 | } 23 | void DriverAdapter::threadEnd() { 24 | throw sql::SQLException("operation not implemented"); 25 | } 26 | } // namespace simpledb 27 | -------------------------------------------------------------------------------- /src/tx/bufferlist.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "tx/bufferlist.hpp" 4 | 5 | namespace simpledb { 6 | buffer_list::buffer_list(buffer_manager *pBM) : mBM(pBM) {} 7 | 8 | buffer *buffer_list::get_buffer(const block_id &pBlockId) { 9 | return mBuffers.at(pBlockId); 10 | } 11 | 12 | void buffer_list::pin(const block_id &pBlockId) { 13 | buffer *buff = mBM->pin(pBlockId); 14 | mBuffers[pBlockId] = buff; 15 | mPins.emplace_back(pBlockId); 16 | } 17 | 18 | void buffer_list::unpin(const block_id &pBlockId) { 19 | buffer *buff = mBuffers.at(pBlockId); 20 | mBM->unpin(buff); 21 | auto iter = std::find(mPins.begin(), mPins.end(), pBlockId); 22 | if (iter != mPins.end()) { 23 | mPins.erase(iter); 24 | } 25 | iter = std::find(mPins.begin(), mPins.end(), pBlockId); 26 | if (iter == mPins.end()) { 27 | mBuffers.erase(pBlockId); 28 | } 29 | } 30 | 31 | void buffer_list::unpin_all() { 32 | for (auto &&blockId : mPins) { 33 | buffer *buff = mBuffers.at(blockId); 34 | mBM->unpin(buff); 35 | } 36 | mBuffers.clear(); 37 | mPins.clear(); 38 | } 39 | } // namespace simpledb 40 | -------------------------------------------------------------------------------- /include/log/logmanager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "file/filemanager.hpp" 6 | 7 | namespace simpledb { 8 | class log_manager { 9 | public: 10 | log_manager(file_manager *pFileManager, const std::string &pLogFile); 11 | int append(const std::vector &pLogRecord); 12 | void flush(int pLSN); 13 | 14 | class log_iterator { 15 | public: 16 | log_iterator(file_manager *ppFileManager, const block_id &ppBlockId); 17 | bool has_next(); 18 | std::vector next(); 19 | void move_to_block(const block_id &ppBlockId); 20 | 21 | private: 22 | file_manager *mmFileManager; 23 | block_id mmBlockId; 24 | std::unique_ptr mmPage; 25 | int mmCurrentPos; 26 | int mmBoundary; 27 | }; 28 | 29 | log_iterator iterator(); 30 | 31 | private: 32 | file_manager *mFileManager; 33 | std::unique_ptr mLogPage; 34 | block_id mCurrentBlk; 35 | std::string mLogFile; 36 | int mLatestLSN = 0; 37 | int mLastSavedLSN = 0; 38 | std::mutex mMutex; 39 | 40 | block_id append_new_block(); 41 | void flush(); 42 | }; 43 | 44 | } // namespace simpledb 45 | -------------------------------------------------------------------------------- /include/record/recordpage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "record/layout.hpp" 6 | #include "tx/transaction.hpp" 7 | 8 | namespace simpledb { 9 | class record_page { 10 | public: 11 | const int empty = 0; 12 | const int used = 1; 13 | record_page(transaction *pTx, const block_id &pBlockId, 14 | const layout &pLayout); 15 | int get_int(int pSlot, const std::string &pFldName); 16 | std::string get_string(int pSlot, const std::string &pFldName); 17 | void set_int(int pSlot, const std::string &pFldname, int pVal); 18 | void set_string(int pSlot, const std::string &pFldName, 19 | const std::string &pVal); 20 | void remove(int pSlot); 21 | void format(); 22 | int next_after(int pSlot); 23 | int insert_after(int pSlot); 24 | block_id block() const; 25 | 26 | private: 27 | transaction *mTx; 28 | block_id mBlockId; 29 | layout mLayout; 30 | 31 | void set_flag(int pSlot, int pFlag); 32 | int search_after(int pSlot, int pFlag); 33 | bool is_valid_slot(int pSlot) const; 34 | int offset(int pSlot) const; 35 | }; 36 | } // namespace simpledb 37 | -------------------------------------------------------------------------------- /test/bufferfiletest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "buffer/buffermanager.hpp" 4 | #include "file/blockid.hpp" 5 | #include "file/filemanager.hpp" 6 | #include "file/page.hpp" 7 | #include "server/simpledb.hpp" 8 | #include "gtest/gtest.h" 9 | 10 | namespace simpledb { 11 | TEST(buffer, bufferfile_test) { 12 | simpledb db("bufferfiletest", 400, 3); // three buffers 13 | buffer_manager &bM = db.buffer_mgr(); 14 | 15 | block_id blk("testfile", 2); 16 | int pos1 = 88; 17 | 18 | buffer *b1 = bM.pin(blk); 19 | page *p1 = b1->contents(); 20 | std::string sample = "abcdefghijklm"; 21 | p1->set_string(pos1, sample); 22 | int size = page::max_length(sample.size()); 23 | int pos2 = pos1 + size; 24 | p1->set_int(pos2, 345); 25 | b1->set_modified(1, 0); 26 | bM.unpin(b1); 27 | 28 | buffer *b2 = bM.pin(blk); 29 | page *p2 = b2->contents(); 30 | std::cout << "offset " << pos2 << " contains " << p2->get_int(pos2) 31 | << std::endl; 32 | std::cout << "offset " << pos1 << " contains " << p2->get_string(pos1) 33 | << std::endl; 34 | bM.unpin(b1); 35 | } 36 | } // namespace simpledb 37 | -------------------------------------------------------------------------------- /test/tablemanagertest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "metadata/tablemanager.hpp" 5 | #include "server/simpledb.hpp" 6 | #include "gtest/gtest.h" 7 | 8 | namespace simpledb { 9 | TEST(metadata, tablemanager_test) { 10 | simpledb db("tblmgrtest", 400, 8); 11 | auto tx = db.new_tx(); 12 | table_manager tM(true, tx.get()); 13 | schema sch; 14 | sch.add_int_field("A"); 15 | sch.add_string_field("B", 9); 16 | tM.create_table("MyTable", sch, tx.get()); 17 | 18 | layout lt = tM.get_layout("MyTable", tx.get()); 19 | int size = lt.slot_size(); 20 | schema sch2 = lt.get_schema(); 21 | std::cout << "MyTable has slot size " << size << std::endl; 22 | std::cout << "Its fields are: " << std::endl; 23 | for (const std::string &fldName : sch2.fields()) { 24 | std::string type; 25 | if (sch2.type(fldName) == schema::integer) { 26 | type = "int"; 27 | } else { 28 | int strLen = sch2.length(fldName); 29 | type = "varchar(" + std::to_string(strLen) + ")"; 30 | } 31 | std::cout << fldName << ": " << type << std::endl; 32 | } 33 | tx->commit(); 34 | } 35 | } // namespace simpledb 36 | -------------------------------------------------------------------------------- /include/materialize/groupbyscan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "materialize/aggregationfn.hpp" 8 | #include "materialize/groupvalue.hpp" 9 | #include "query/constant.hpp" 10 | #include "query/scan.hpp" 11 | 12 | namespace simpledb { 13 | class group_by_scan : public scan { 14 | public: 15 | group_by_scan(const std::shared_ptr &pS, 16 | const std::vector &pGroupFields, 17 | const std::vector> &pAggFns); 18 | void before_first() override; 19 | bool next() override; 20 | int get_int(const std::string &pFldName) override; 21 | std::string get_string(const std::string &pFldName) override; 22 | constant get_val(const std::string &pFldName) override; 23 | bool has_field(const std::string &pFldName) override; 24 | void close() override; 25 | 26 | private: 27 | std::shared_ptr mS; 28 | std::vector mGroupFields; 29 | std::vector> mAggFns; 30 | std::unique_ptr mGroupVal; 31 | bool mMoreGroups; 32 | }; 33 | } // namespace simpledb 34 | -------------------------------------------------------------------------------- /include/metadata/statmanager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "metadata/tablemanager.hpp" 8 | 9 | namespace simpledb { 10 | class stat_info { 11 | public: 12 | stat_info(); 13 | stat_info(const stat_info &pSI); 14 | stat_info(int pNumBlocks, int pNumRecs); 15 | stat_info &operator=(const stat_info &pSI); 16 | int blocks_accessed(); 17 | int records_output(); 18 | int distinct_values(const std::string &pFldName); 19 | 20 | private: 21 | int mNumBlocks; 22 | int mNumRecs; 23 | }; 24 | 25 | class stat_manager { 26 | public: 27 | stat_manager(table_manager *pTM, transaction *pTx); 28 | stat_info get_stat_info(const std::string &pTblName, const layout &pLt, 29 | transaction *pTx); 30 | 31 | private: 32 | table_manager *mTM; 33 | std::map mTableStats; 34 | int mNumCalls; 35 | std::recursive_mutex mMutex; 36 | 37 | void refresh_statistics(transaction *pTx); 38 | stat_info calc_table_stats(const std::string &pTblName, const layout &pLt, 39 | transaction *pTx); 40 | }; 41 | } // namespace simpledb 42 | -------------------------------------------------------------------------------- /include/utils/utils.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace simpledb { 6 | // trim from start (in place) 7 | static inline void ltrim(std::string &s) { 8 | s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { 9 | return !std::isspace(ch); 10 | })); 11 | } 12 | 13 | // trim from end (in place) 14 | static inline void rtrim(std::string &s) { 15 | s.erase(std::find_if(s.rbegin(), s.rend(), 16 | [](unsigned char ch) { return !std::isspace(ch); }) 17 | .base(), 18 | s.end()); 19 | } 20 | 21 | // trim from both ends (in place) 22 | static inline void trim(std::string &s) { 23 | ltrim(s); 24 | rtrim(s); 25 | } 26 | 27 | // trim from start (copying) 28 | static inline std::string ltrim_copy(std::string s) { 29 | ltrim(s); 30 | return s; 31 | } 32 | 33 | // trim from end (copying) 34 | static inline std::string rtrim_copy(std::string s) { 35 | rtrim(s); 36 | return s; 37 | } 38 | 39 | // trim from both ends (copying) 40 | static inline std::string trim_copy(std::string s) { 41 | trim(s); 42 | return s; 43 | } 44 | } // namespace simpledb 45 | -------------------------------------------------------------------------------- /src/parse/querydata.cpp: -------------------------------------------------------------------------------- 1 | #include "parse/querydata.hpp" 2 | 3 | namespace simpledb { 4 | query_data::query_data(const std::vector pFields, 5 | const std::set &pTables, 6 | const predicate &pPred) 7 | : mFields(pFields), mTables(pTables), mPred(pPred) {} 8 | 9 | std::vector query_data::fields() const { return mFields; } 10 | 11 | std::set query_data::tables() const { return mTables; } 12 | 13 | predicate query_data::pred() const { return mPred; } 14 | 15 | std::string query_data::to_string() const { 16 | std::string result = "select "; 17 | for (const std::string &fldName : mFields) { 18 | result += fldName + ", "; 19 | } 20 | result = result.substr(0, result.size() - 2); // zap final comma 21 | result += " from "; 22 | for (const std::string &tblName : mTables) { 23 | result += tblName + ", "; 24 | } 25 | result = result.substr(0, result.size() - 2); // zap final comma 26 | std::string predString = mPred.to_string(); 27 | if (!predString.empty()) { 28 | result += " where " + predString; 29 | } 30 | return result; 31 | } 32 | } // namespace simpledb 33 | -------------------------------------------------------------------------------- /src/query/expression.cpp: -------------------------------------------------------------------------------- 1 | #include "query/expression.hpp" 2 | 3 | namespace simpledb { 4 | expression::expression() {} 5 | 6 | expression::expression(const expression &pE) 7 | : mVal(pE.mVal), mFldName(pE.mFldName) {} 8 | 9 | expression::expression(const constant &pVal) : mVal(pVal) {} 10 | 11 | expression::expression(const std::string &pFldName) : mFldName(pFldName) {} 12 | 13 | expression &expression::operator=(const expression &pE) { 14 | if (this != &pE) { 15 | mVal = pE.mVal; 16 | mFldName = pE.mFldName; 17 | } 18 | return *this; 19 | } 20 | 21 | bool expression::is_field_name() const { return !mFldName.empty(); } 22 | 23 | constant expression::as_constant() const { return mVal; } 24 | 25 | std::string expression::as_field_name() const { return mFldName; } 26 | 27 | constant expression::evaluate(scan *pS) const { 28 | return (mVal.is_null() ? pS->get_val(mFldName) : mVal); 29 | } 30 | 31 | bool expression::applies_to(const schema &pSch) const { 32 | return (mVal.is_null() ? pSch.has_field(mFldName) : true); 33 | } 34 | 35 | std::string expression::to_string() const { 36 | return (mVal.is_null() ? mFldName : mVal.to_string()); 37 | } 38 | } // namespace simpledb 39 | -------------------------------------------------------------------------------- /include/materialize/sortscan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "materialize/materializeplan.hpp" 4 | #include "materialize/recordcomparator.hpp" 5 | #include "materialize/temptable.hpp" 6 | #include "plan/plan.hpp" 7 | #include "query/updatescan.hpp" 8 | #include "record/layout.hpp" 9 | #include "record/tablescan.hpp" 10 | #include "tx/transaction.hpp" 11 | 12 | namespace simpledb { 13 | class sort_scan : public scan { 14 | public: 15 | sort_scan(const std::vector> &pRuns, 16 | record_comparator &pComp); // todo record comparator is ref ok?? 17 | void before_first() override; 18 | bool next() override; 19 | int get_int(const std::string &pFldName) override; 20 | std::string get_string(const std::string &pFldName) override; 21 | constant get_val(const std::string &pFldName) override; 22 | bool has_field(const std::string &pFldName) override; 23 | void close() override; 24 | 25 | void save_position(); 26 | void restore_position(); 27 | 28 | private: 29 | std::shared_ptr mS1, mS2, mCurrentScan; 30 | record_comparator &mComp; 31 | bool mHasMore1, mHasMore2; 32 | std::vector mSavedPosition; 33 | }; 34 | } // namespace simpledb 35 | -------------------------------------------------------------------------------- /src/plan/productplan.cpp: -------------------------------------------------------------------------------- 1 | #include "plan/productplan.hpp" 2 | #include "query/productscan.hpp" 3 | 4 | namespace simpledb { 5 | product_plan::product_plan(const std::shared_ptr &pP1, 6 | const std::shared_ptr &pP2) 7 | : mP1(pP1), mP2(pP2) { 8 | mSch.add_all(mP1->get_schema()); 9 | mSch.add_all(mP2->get_schema()); 10 | } 11 | 12 | std::shared_ptr product_plan::open() { 13 | std::shared_ptr s1 = mP1->open(); 14 | std::shared_ptr s2 = mP2->open(); 15 | return std::static_pointer_cast(std::make_shared(s1, s2)); 16 | } 17 | 18 | int product_plan::blocks_accessed() { 19 | return mP1->blocks_accessed() + 20 | mP1->records_output() * mP2->blocks_accessed(); 21 | } 22 | 23 | int product_plan::records_output() { 24 | return mP1->records_output() * mP2->records_output(); 25 | } 26 | 27 | int product_plan::distinct_values(const std::string &pFldName) { 28 | if (mP1->get_schema().has_field(pFldName)) { 29 | return mP1->distinct_values(pFldName); 30 | } else { 31 | return mP2->distinct_values(pFldName); 32 | } 33 | } 34 | 35 | schema product_plan::get_schema() { return mSch; } 36 | } // namespace simpledb 37 | -------------------------------------------------------------------------------- /include/query/selectscan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "query/constant.hpp" 6 | #include "query/predicate.hpp" 7 | #include "query/scan.hpp" 8 | #include "query/updatescan.hpp" 9 | 10 | namespace simpledb { 11 | class select_scan : public update_scan { 12 | public: 13 | select_scan(const std::shared_ptr &pS, const predicate &pP); 14 | 15 | void before_first() override; 16 | bool next() override; 17 | int get_int(const std::string &pFldName) override; 18 | std::string get_string(const std::string &pFldName) override; 19 | constant get_val(const std::string &pFldName) override; 20 | bool has_field(const std::string &pFldName) override; 21 | void close() override; 22 | 23 | void set_int(const std::string &pFldName, int pVal) override; 24 | void set_string(const std::string &pFldName, 25 | const std::string &pVal) override; 26 | void set_val(const std::string &pFldName, const constant &pVal) override; 27 | void insert() override; 28 | void remove() override; 29 | rid get_rid() override; 30 | void move_to_rid(const rid &pRID) override; 31 | 32 | private: 33 | std::shared_ptr mS; 34 | predicate mP; 35 | }; 36 | } // namespace simpledb 37 | -------------------------------------------------------------------------------- /src/jdbc/embedded/embeddedstatement.cpp: -------------------------------------------------------------------------------- 1 | #include "jdbc/embedded/embeddedstatement.hpp" 2 | #include "jdbc/embedded/embeddedconnection.hpp" 3 | #include "tx/transaction.hpp" 4 | 5 | namespace simpledb { 6 | EmbeddedStatement::EmbeddedStatement(EmbeddedConnection &pConn, 7 | planner &pPlanner) 8 | : mConn(pConn), mPlanner(pPlanner) {} 9 | 10 | EmbeddedResultSet *EmbeddedStatement::executeQuery(const sql::SQLString &pSQL) { 11 | try { 12 | transaction &tx = mConn.getTransaction(); 13 | auto pln = mPlanner.create_query_plan(pSQL.asStdString(), &tx); 14 | return new EmbeddedResultSet(*pln, mConn); 15 | } catch (const std::exception &e) { 16 | mConn.rollback(); 17 | throw sql::SQLException(e.what()); 18 | } 19 | } 20 | 21 | int EmbeddedStatement::executeUpdate(const sql::SQLString &pSQL) { 22 | try { 23 | transaction &tx = mConn.getTransaction(); 24 | int result = mPlanner.execute_update(pSQL.asStdString(), &tx); 25 | mConn.commit(); 26 | return result; 27 | } catch (const std::exception &e) { 28 | mConn.rollback(); 29 | throw sql::SQLException(e.what()); 30 | } 31 | } 32 | 33 | void EmbeddedStatement::close() { return; } 34 | } // namespace simpledb 35 | -------------------------------------------------------------------------------- /test/plannertest1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "query/scan.hpp" 5 | #include "server/simpledb.hpp" 6 | #include "tx/transaction.hpp" 7 | #include "gtest/gtest.h" 8 | 9 | namespace simpledb { 10 | TEST(plan, plannertest1_test) { 11 | simpledb db("plannertest1"); 12 | auto tx = db.new_tx(); 13 | planner &plnr = db.plnr(); 14 | std::string cmd = "create table T1(A int, B varchar(9))"; 15 | plnr.execute_update(cmd, tx.get()); 16 | 17 | int n = 200; 18 | std::cout << "Inserting " << n << " random records" << std::endl; 19 | 20 | std::random_device rd; 21 | std::mt19937 gen(rd()); 22 | std::uniform_real_distribution d(0, 1); 23 | 24 | for (int i = 0; i < n; i++) { 25 | int a = round(d(gen) * 50); 26 | std::string b = "rec" + std::to_string(a); 27 | cmd = "insert into T1(A,B) values (" + std::to_string(a) + ", '" + b + "')"; 28 | plnr.execute_update(cmd, tx.get()); 29 | } 30 | 31 | std::string qry = "select B from T1 where A=10"; 32 | auto p = plnr.create_query_plan(qry, tx.get()); 33 | auto s = p->open(); 34 | while (s->next()) { 35 | std::cout << s->get_string("b") << std::endl; 36 | } 37 | s->close(); 38 | tx->commit(); 39 | } 40 | } // namespace simpledb 41 | -------------------------------------------------------------------------------- /src/plan/selectplan.cpp: -------------------------------------------------------------------------------- 1 | #include "plan/selectplan.hpp" 2 | #include "query/selectscan.hpp" 3 | 4 | namespace simpledb { 5 | select_plan::select_plan(const std::shared_ptr &pPlan, 6 | const predicate &pPred) 7 | : mPlan(pPlan), mPred(pPred) {} 8 | 9 | std::shared_ptr select_plan::open() { 10 | std::shared_ptr s = mPlan->open(); 11 | return std::static_pointer_cast( 12 | std::make_shared(s, mPred)); 13 | } 14 | 15 | int select_plan::blocks_accessed() { return mPlan->blocks_accessed(); } 16 | 17 | int select_plan::records_output() { 18 | return mPlan->records_output() / mPred.reduction_factor(mPlan.get()); 19 | } 20 | 21 | int select_plan::distinct_values(const std::string &pFldName) { 22 | if (!mPred.equates_with_constant(pFldName).is_null()) { 23 | return 1; 24 | } else { 25 | std::string fldName = mPred.equates_with_field(pFldName); 26 | if (!fldName.empty()) { 27 | return std::min(mPlan->distinct_values(pFldName), 28 | mPlan->distinct_values(fldName)); 29 | } else { 30 | return mPlan->distinct_values(pFldName); 31 | } 32 | } 33 | } 34 | 35 | schema select_plan::get_schema() { return mPlan->get_schema(); } 36 | } // namespace simpledb 37 | -------------------------------------------------------------------------------- /src/index/planner/indexselectplan.cpp: -------------------------------------------------------------------------------- 1 | #include "index/planner/indexselectplan.hpp" 2 | #include "index/query/indexselectscan.hpp" 3 | #include "record/tablescan.hpp" 4 | 5 | namespace simpledb { 6 | index_select_plan::index_select_plan(const std::shared_ptr &pP, 7 | const index_info &pII, 8 | const constant &pVal) 9 | : mP(pP), mII(pII), mVal(pVal) {} 10 | 11 | std::shared_ptr index_select_plan::open() { 12 | std::shared_ptr tS = 13 | std::dynamic_pointer_cast(mP->open()); 14 | if (!tS) { 15 | throw std::runtime_error("type conversion failed"); 16 | } 17 | std::shared_ptr idx = mII.open(); 18 | return std::static_pointer_cast( 19 | std::make_shared(tS, idx, mVal)); 20 | } 21 | 22 | int index_select_plan::blocks_accessed() { 23 | return mII.blocks_accessed() + records_output(); 24 | } 25 | 26 | int index_select_plan::records_output() { return mII.records_output(); } 27 | 28 | int index_select_plan::distinct_values(const std::string &pFldName) { 29 | return mII.distinct_values(pFldName); 30 | } 31 | 32 | schema index_select_plan::get_schema() { return mP->get_schema(); } 33 | 34 | } // namespace simpledb 35 | -------------------------------------------------------------------------------- /src/index/query/indexselectscan.cpp: -------------------------------------------------------------------------------- 1 | #include "index/query/indexselectscan.hpp" 2 | 3 | namespace simpledb { 4 | index_select_scan::index_select_scan(const std::shared_ptr &pTS, 5 | const std::shared_ptr &pIdx, 6 | const constant &pVal) 7 | : mTS(pTS), mIdx(pIdx), mVal(pVal) { 8 | mIdx->before_first(mVal); 9 | } 10 | 11 | void index_select_scan::before_first() { mIdx->before_first(mVal); } 12 | 13 | bool index_select_scan::next() { 14 | bool ok = mIdx->next(); 15 | if (ok) { 16 | rid r = mIdx->get_data_rid(); 17 | mTS->move_to_rid(r); 18 | } 19 | return ok; 20 | } 21 | 22 | int index_select_scan::get_int(const std::string &pFldName) { 23 | return mTS->get_int(pFldName); 24 | } 25 | 26 | std::string index_select_scan::get_string(const std::string &pFldName) { 27 | return mTS->get_string(pFldName); 28 | } 29 | 30 | constant index_select_scan::get_val(const std::string &pFldName) { 31 | return mTS->get_val(pFldName); 32 | } 33 | 34 | bool index_select_scan::has_field(const std::string &pFldName) { 35 | return mTS->has_field(pFldName); 36 | } 37 | 38 | void index_select_scan::close() { 39 | mIdx->close(); 40 | mTS->close(); 41 | } 42 | } // namespace simpledb 43 | -------------------------------------------------------------------------------- /src/metadata/viewmanager.cpp: -------------------------------------------------------------------------------- 1 | #include "metadata/viewmanager.hpp" 2 | 3 | namespace simpledb { 4 | view_manager::view_manager(bool pIsNew, table_manager *pTM, transaction *pTx) 5 | : mTM(pTM) { 6 | if (pIsNew) { 7 | schema sch; 8 | sch.add_string_field("viewname", mTM->mMaxName); 9 | sch.add_string_field("viewdef", mMaxViewDiff); 10 | mTM->create_table("viewcat", sch, pTx); 11 | } 12 | } 13 | 14 | void view_manager::create_view(const std::string &pVName, 15 | const std::string &pVDef, transaction *pTx) { 16 | layout lt = mTM->get_layout("viewcat", pTx); 17 | table_scan tS(pTx, "viewcat", lt); 18 | tS.insert(); 19 | tS.set_string("viewname", pVName); // bug 20 | tS.set_string("viewdef", pVDef); 21 | tS.close(); 22 | } 23 | 24 | std::string view_manager::get_view_def(const std::string &pVName, 25 | transaction *pTx) { 26 | std::string result; 27 | layout lt = mTM->get_layout("viewcat", pTx); 28 | table_scan tS(pTx, "viewcat", lt); 29 | 30 | while (tS.next()) { 31 | if (tS.get_string("viewname") == pVName) { 32 | result = tS.get_string("viewdef"); 33 | break; 34 | } 35 | } 36 | 37 | tS.close(); 38 | return result; 39 | } 40 | } // namespace simpledb 41 | -------------------------------------------------------------------------------- /include/record/schema.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace simpledb { 9 | class schema { 10 | public: 11 | enum type { integer = 0, varchar = 1 }; 12 | schema(); 13 | 14 | schema(const schema &pSch); 15 | 16 | schema &operator=(const schema &pSch); 17 | 18 | void add_field(const std::string &pFldName, int pType, int pLength); 19 | void add_int_field(const std::string &pFldName); 20 | 21 | void add_string_field(const std::string &pFldName, int pLength); 22 | 23 | void add(const std::string &pFldName, const schema &pSchema); 24 | 25 | void add_all(const schema &pSchema); 26 | 27 | std::vector fields() const; 28 | 29 | bool has_field(const std::string &pFldName) const; 30 | 31 | int type(const std::string &pFldName) const; 32 | 33 | int length(const std::string &pFldName) const; 34 | 35 | class field_info { 36 | public: 37 | field_info() = default; 38 | field_info(int pType, int pLength); 39 | int type() const; 40 | int length() const; 41 | 42 | private: 43 | int mType, mLength; 44 | }; 45 | 46 | private: 47 | std::vector mFields; 48 | std::map mInfo; 49 | }; 50 | } // namespace simpledb 51 | -------------------------------------------------------------------------------- /include/materialize/sortplan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "materialize/materializeplan.hpp" 4 | #include "materialize/recordcomparator.hpp" 5 | #include "materialize/sortscan.hpp" 6 | #include "materialize/temptable.hpp" 7 | #include "plan/plan.hpp" 8 | #include "query/updatescan.hpp" 9 | #include "record/layout.hpp" 10 | #include "record/tablescan.hpp" 11 | #include "tx/transaction.hpp" 12 | 13 | namespace simpledb { 14 | class sort_plan : public plan { 15 | public: 16 | sort_plan(transaction *pTx, const std::shared_ptr &pP, 17 | const std::vector &pSortFields); 18 | std::shared_ptr open() override; 19 | int blocks_accessed() override; 20 | int records_output() override; 21 | int distinct_values(const std::string &pFldName) override; 22 | schema get_schema() override; 23 | 24 | private: 25 | std::shared_ptr mP; 26 | transaction *mTx; 27 | schema mSch; 28 | record_comparator mComp; 29 | 30 | std::vector> split_into_runs(scan *pSrc); 31 | std::vector> 32 | do_a_merge_iteration(const std::vector> &pRuns); 33 | std::shared_ptr merge_two_runs(temp_table *pP1, temp_table *pP2); 34 | bool copy(scan *pSrc, update_scan *pDest); 35 | }; 36 | } // namespace simpledb 37 | -------------------------------------------------------------------------------- /test/indexretrievaltest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "metadata/indexmanager.hpp" 4 | #include "metadata/metadatamanager.hpp" 5 | #include "plan/plan.hpp" 6 | #include "plan/tableplan.hpp" 7 | #include "record/rid.hpp" 8 | #include "server/simpledb.hpp" 9 | #include "tx/transaction.hpp" 10 | #include "gtest/gtest.h" 11 | 12 | namespace simpledb { 13 | TEST(index, indexretrieval_test) { 14 | simpledb db("root:password@localhost"); 15 | auto tx = db.new_tx(); 16 | metadata_manager &mM = db.md_mgr(); 17 | 18 | std::shared_ptr studentPlan = std::static_pointer_cast( 19 | std::make_shared(tx.get(), "student", &mM)); 20 | std::shared_ptr studentScan = 21 | std::static_pointer_cast(studentPlan->open()); 22 | 23 | layout lt = mM.get_layout("student", tx.get()); 24 | 25 | std::map indexes = 26 | mM.get_index_info("student", tx.get()); 27 | index_info ii = indexes.at("majorid"); 28 | std::shared_ptr idx = ii.open(); 29 | 30 | idx->before_first(constant(20)); 31 | while (idx->next()) { 32 | rid dataRID = idx->get_data_rid(); 33 | studentScan->move_to_rid(dataRID); 34 | std::cout << studentScan->get_string("sname") << std::endl; 35 | } 36 | 37 | idx->close(); 38 | studentScan->close(); 39 | tx->commit(); 40 | } 41 | } // namespace simpledb 42 | -------------------------------------------------------------------------------- /src/query/projectscan.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "query/projectscan.hpp" 5 | 6 | namespace simpledb { 7 | project_scan::project_scan(const std::shared_ptr &pS, 8 | const std::vector &pFieldList) 9 | : mS(pS), mFieldList(pFieldList) {} 10 | 11 | void project_scan::before_first() { mS->before_first(); } 12 | 13 | bool project_scan::next() { return mS->next(); } 14 | 15 | int project_scan::get_int(const std::string &pFldName) { 16 | if (has_field(pFldName)) { 17 | return mS->get_int(pFldName); 18 | } else { 19 | throw std::runtime_error("field not found"); 20 | } 21 | } 22 | 23 | std::string project_scan::get_string(const std::string &pFldName) { 24 | if (has_field(pFldName)) { 25 | return mS->get_string(pFldName); 26 | } else { 27 | throw std::runtime_error("field not found"); 28 | } 29 | } 30 | 31 | constant project_scan::get_val(const std::string &pFldName) { 32 | if (has_field(pFldName)) { 33 | return mS->get_val(pFldName); 34 | } else { 35 | throw std::runtime_error("field not found"); 36 | } 37 | } 38 | 39 | bool project_scan::has_field(const std::string &pFldName) { 40 | return std::find(mFieldList.begin(), mFieldList.end(), pFldName) != 41 | mFieldList.end(); 42 | } 43 | 44 | void project_scan::close() { mS->close(); } 45 | } // namespace simpledb 46 | -------------------------------------------------------------------------------- /src/materialize/materializeplan.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "materialize/materializeplan.hpp" 4 | #include "materialize/temptable.hpp" 5 | 6 | namespace simpledb { 7 | materialize_plan::materialize_plan(transaction *pTx, 8 | const std::shared_ptr &pSrcPlan) 9 | : mTx(pTx), mSrcPlan(pSrcPlan) {} 10 | 11 | std::shared_ptr materialize_plan::open() { 12 | schema sch = mSrcPlan->get_schema(); 13 | std::shared_ptr src = mSrcPlan->open(); 14 | temp_table temp(mTx, sch); 15 | std::shared_ptr dest = temp.open(); 16 | while (src->next()) { 17 | dest->insert(); 18 | for (const std::string &fldName : sch.fields()) { 19 | dest->set_val(fldName, src->get_val(fldName)); 20 | } 21 | } 22 | src->close(); 23 | dest->before_first(); 24 | return std::static_pointer_cast(dest); 25 | } 26 | 27 | int materialize_plan::blocks_accessed() { 28 | layout lt(mSrcPlan->get_schema()); 29 | int rPB = (mTx->block_size() / lt.slot_size()); 30 | return std::ceil(static_cast(mSrcPlan->records_output()) / 31 | static_cast(rPB)); 32 | } 33 | 34 | int materialize_plan::records_output() { return mSrcPlan->records_output(); } 35 | 36 | int materialize_plan::distinct_values(const std::string &pFldName) { 37 | return mSrcPlan->distinct_values(pFldName); 38 | } 39 | 40 | schema materialize_plan::get_schema() { return mSrcPlan->get_schema(); } 41 | } // namespace simpledb 42 | -------------------------------------------------------------------------------- /include/tx/transaction.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "buffer/buffermanager.hpp" 6 | #include "file/filemanager.hpp" 7 | #include "tx/bufferlist.hpp" 8 | #include "tx/concurrency/concurrencymanager.hpp" 9 | #include "tx/recovery/recoverymanager.hpp" 10 | 11 | namespace simpledb { 12 | class transaction { 13 | public: 14 | transaction(file_manager *pFM, log_manager *pLM, buffer_manager *pBM); 15 | 16 | void commit(); 17 | void rollback(); 18 | void recover(); 19 | void pin(const block_id &pBlockId); 20 | void unpin(const block_id &pBlockId); 21 | int get_int(const block_id &pBlockId, int pOffset); 22 | std::string get_string(const block_id &pBlockId, int pOffset); 23 | void set_int(const block_id &pBlockId, int pOffset, int pVal, bool pOkToLog); 24 | void set_string(const block_id &pBlockId, int pOffset, 25 | const std::string &pVal, bool pOkToLog); 26 | int size(const std::string &pFileName); 27 | block_id append(const std::string &pFileName); 28 | int block_size(); 29 | int available_buffers(); 30 | int num() const; 31 | 32 | private: 33 | static int mNextTxNum; 34 | static std::mutex mMutex; 35 | const int mEndOfFile = -1; 36 | file_manager *mFM; 37 | log_manager *mLM; 38 | buffer_manager *mBM; 39 | int mTxNum; 40 | std::unique_ptr mRM; 41 | std::unique_ptr mCM; 42 | std::unique_ptr mBL; 43 | 44 | static int next_tx_number(); 45 | }; 46 | } // namespace simpledb 47 | -------------------------------------------------------------------------------- /include/record/tablescan.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "query/updatescan.hpp" 7 | #include "record/layout.hpp" 8 | #include "record/recordpage.hpp" 9 | #include "record/rid.hpp" 10 | #include "tx/transaction.hpp" 11 | 12 | namespace simpledb { 13 | class table_scan : public update_scan { 14 | public: 15 | table_scan(transaction *pTx, const std::string &pTableName, 16 | const layout &pLayout); 17 | ~table_scan(); 18 | void before_first() override; 19 | bool next() override; 20 | int get_int(const std::string &pFldName) override; 21 | std::string get_string(const std::string &pFldName) override; 22 | constant get_val(const std::string &pFldName) override; 23 | bool has_field(const std::string &pFldName) override; 24 | void close() override; 25 | 26 | void set_int(const std::string &pFldName, int pVal) override; 27 | void set_string(const std::string &pFldName, 28 | const std::string &pVal) override; 29 | void set_val(const std::string &pFldName, const constant &pVal) override; 30 | void insert() override; 31 | void remove() override; 32 | rid get_rid() override; 33 | void move_to_rid(const rid &pRID) override; 34 | 35 | private: 36 | transaction *mTx; 37 | layout mLt; 38 | std::unique_ptr mRP; 39 | std::string mFileName; 40 | int mCurrentSlot; 41 | 42 | void move_to_block(int pBlkNum); 43 | void move_to_new_block(); 44 | bool at_last_block(); 45 | }; 46 | } // namespace simpledb 47 | -------------------------------------------------------------------------------- /test/buffermanagertest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "buffer/buffermanager.hpp" 4 | #include "file/blockid.hpp" 5 | #include "file/filemanager.hpp" 6 | #include "file/page.hpp" 7 | #include "server/simpledb.hpp" 8 | #include "gtest/gtest.h" 9 | 10 | namespace simpledb { 11 | TEST(buffer, buffermanager_test) { 12 | simpledb db("buffermgrtest", 400, 3); // three buffers 13 | buffer_manager &bM = db.buffer_mgr(); 14 | 15 | std::vector buff(6); 16 | std::string testFile = "testfile"; 17 | buff[0] = bM.pin(block_id(testFile, 0)); 18 | buff[1] = bM.pin(block_id(testFile, 1)); 19 | buff[2] = bM.pin(block_id(testFile, 2)); 20 | 21 | bM.unpin(buff[1]); 22 | buff[1] = nullptr; 23 | 24 | buff[3] = bM.pin(block_id(testFile, 0)); 25 | buff[4] = bM.pin(block_id(testFile, 1)); 26 | std::cout << "Available buffers " << bM.available() << std::endl; 27 | try { 28 | std::cout << "Attempting to pin block 3" << std::endl; 29 | buff[5] = bM.pin(block_id(testFile, 3)); 30 | } catch (std::exception &e) { 31 | std::cout << e.what() << std::endl; 32 | } 33 | 34 | bM.unpin(buff[2]); 35 | buff[2] = nullptr; 36 | buff[5] = bM.pin(block_id(testFile, 3)); 37 | std::cout << "Final Buffer Allocation" << std::endl; 38 | 39 | for (int i = 0; i < buff.size(); i++) { 40 | buffer *b = buff[i]; 41 | if (b != nullptr) { 42 | std::cout << "buff[" << i << "] pinned to block" << b->block().to_string() 43 | << std::endl; 44 | } 45 | } 46 | } 47 | } // namespace simpledb 48 | -------------------------------------------------------------------------------- /src/query/productscan.cpp: -------------------------------------------------------------------------------- 1 | #include "query/productscan.hpp" 2 | 3 | namespace simpledb { 4 | product_scan::product_scan(const std::shared_ptr &pS1, 5 | const std::shared_ptr &pS2) 6 | : mS1(pS1), mS2(pS2) { 7 | mS1->before_first(); 8 | mS1->next(); 9 | mS2->before_first(); 10 | }; 11 | 12 | void product_scan::before_first() { 13 | mS1->before_first(); 14 | mS1->next(); 15 | mS2->before_first(); 16 | } 17 | 18 | bool product_scan::next() { 19 | if (mS2->next()) { 20 | return true; 21 | } else { 22 | mS2->before_first(); 23 | return mS2->next() && mS1->next(); 24 | } 25 | } 26 | 27 | int product_scan::get_int(const std::string &pFldName) { 28 | if (mS1->has_field(pFldName)) { 29 | return mS1->get_int(pFldName); 30 | } else { 31 | return mS2->get_int(pFldName); 32 | } 33 | } 34 | 35 | std::string product_scan::get_string(const std::string &pFldName) { 36 | if (mS1->has_field(pFldName)) { 37 | return mS1->get_string(pFldName); 38 | } else { 39 | return mS2->get_string(pFldName); 40 | } 41 | } 42 | 43 | constant product_scan::get_val(const std::string &pFldName) { 44 | if (mS1->has_field(pFldName)) { 45 | return mS1->get_val(pFldName); 46 | } else { 47 | return mS2->get_val(pFldName); 48 | } 49 | } 50 | 51 | bool product_scan::has_field(const std::string &pFldName) { 52 | return mS1->has_field(pFldName) && mS2->has_field(pFldName); 53 | } 54 | 55 | void product_scan::close() { 56 | mS1->close(); 57 | mS2->close(); 58 | } 59 | } // namespace simpledb 60 | -------------------------------------------------------------------------------- /include/opt/tableplanner.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "metadata/indexmanager.hpp" 7 | #include "metadata/metadatamanager.hpp" 8 | #include "plan/plan.hpp" 9 | #include "plan/tableplan.hpp" 10 | #include "query/predicate.hpp" 11 | #include "record/schema.hpp" 12 | #include "tx/transaction.hpp" 13 | 14 | namespace simpledb { 15 | class table_planner { 16 | public: 17 | table_planner(const std::string &pTblName, const predicate &pMyPred, 18 | transaction &pTx, metadata_manager &pMM); 19 | std::shared_ptr make_select_plan(); 20 | std::shared_ptr make_join_plan(const std::shared_ptr &pCurrent); 21 | std::shared_ptr 22 | make_product_plan(const std::shared_ptr &pCurrent); 23 | 24 | private: 25 | predicate mMyPred; 26 | transaction &mTx; 27 | std::shared_ptr mMyPlan; 28 | schema mMySchema; 29 | std::map mIndexes; 30 | 31 | std::shared_ptr make_index_select(); 32 | std::shared_ptr make_index_join(const std::shared_ptr &pCurrent, 33 | const schema &pCurrSch); 34 | std::shared_ptr make_product_join(const std::shared_ptr &pCurrent, 35 | const schema &pCurrSch); 36 | std::shared_ptr add_select_pred(const std::shared_ptr &pP); 37 | std::shared_ptr add_join_pred(const std::shared_ptr &pP, 38 | const schema &pCurrSch); 39 | }; 40 | } // namespace simpledb 41 | -------------------------------------------------------------------------------- /test/tokenizertest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "parse/streamtokenizer.hpp" 4 | #include "gtest/gtest.h" 5 | 6 | namespace simpledb { 7 | void print_current_token(const std::set &keywords, 8 | stream_tokenizer &tok) { 9 | 10 | if (tok.mTType == stream_tokenizer::mTT_NUMBER) { 11 | std::cout << "IntConstant " << tok.mNVal << std::endl; 12 | } else if (tok.mTType == stream_tokenizer::mTT_WORD) { 13 | std::string word = tok.mSVal; 14 | if (keywords.find(word) != keywords.end()) { 15 | std::cout << "Keyword " << word << std::endl; 16 | } else { 17 | std::cout << "Id " << word << std::endl; 18 | } 19 | } else if (tok.mTType == '\'') { 20 | std::cout << "StringConstant " << tok.mSVal << std::endl; 21 | } else { 22 | std::cout << "Delimiter " << static_cast(tok.mTType) << std::endl; 23 | } 24 | } 25 | 26 | TEST(parse, tokenizer_test) { 27 | std::set keywords = { 28 | "select", "from", "where", "and", "insert", "into", 29 | "values", "delete", "update", "set", "create", "table", 30 | "int", "varchar", "view", "as", "index", "on"}; 31 | 32 | std::string s; 33 | std::stringstream ss; 34 | ss << "select a from x, z where b = 3 and c = 'foobar'"; 35 | 36 | stream_tokenizer tok(ss); 37 | tok.ordinary_char('.'); 38 | tok.word_chars('_', '_'); 39 | tok.lower_case_mode(true); 40 | while (tok.next_token() != stream_tokenizer::mTT_EOF) { 41 | print_current_token(keywords, tok); 42 | } 43 | } 44 | } // namespace simpledb 45 | -------------------------------------------------------------------------------- /test/plannertest2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "query/scan.hpp" 5 | #include "server/simpledb.hpp" 6 | #include "tx/transaction.hpp" 7 | #include "gtest/gtest.h" 8 | 9 | namespace simpledb { 10 | TEST(plan, plannertest2_test) { 11 | simpledb db("plannertest2"); 12 | auto tx = db.new_tx(); 13 | planner &plnr = db.plnr(); 14 | 15 | std::string cmd = "create table T1(A int, B varchar(9))"; 16 | plnr.execute_update(cmd, tx.get()); 17 | 18 | int n = 200; 19 | std::cout << "Inserting " << n << " records int T1." << std::endl; 20 | 21 | for (int i = 0; i < n; i++) { 22 | int a = i; 23 | std::string b = "bbb" + std::to_string(a); 24 | cmd = "insert into T1(A,B) values (" + std::to_string(a) + ", '" + b + "')"; 25 | plnr.execute_update(cmd, tx.get()); 26 | } 27 | 28 | cmd = "create table T2(C int, D varchar(9))"; 29 | plnr.execute_update(cmd, tx.get()); 30 | std::cout << "Inserting " << n << " records int T2." << std::endl; 31 | 32 | for (int i = 0; i < n; i++) { 33 | int c = n - i - 1; 34 | std::string d = "ddd" + std::to_string(c); 35 | cmd = "insert into T2(C,D) values(" + std::to_string(c) + ", '" + d + "')"; 36 | plnr.execute_update(cmd, tx.get()); 37 | } 38 | 39 | std::string qry = "select B,D from T1,T2 where A=C"; 40 | auto p = plnr.create_query_plan(qry, tx.get()); 41 | auto s = p->open(); 42 | while (s->next()) { 43 | std::cout << s->get_string("b") << " " << s->get_string("d") << std::endl; 44 | } 45 | s->close(); 46 | tx->commit(); 47 | } 48 | } // namespace simpledb 49 | -------------------------------------------------------------------------------- /include/metadata/metadatamanager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "metadata/indexmanager.hpp" 8 | #include "metadata/statmanager.hpp" 9 | #include "metadata/tablemanager.hpp" 10 | #include "metadata/viewmanager.hpp" 11 | #include "record/layout.hpp" 12 | #include "record/schema.hpp" 13 | #include "tx/transaction.hpp" 14 | 15 | namespace simpledb { 16 | class metadata_manager { 17 | public: 18 | metadata_manager(bool pIsNew, transaction *pTx); 19 | void create_table(const std::string &pTblName, const schema &pSch, 20 | transaction *pTx); 21 | layout get_layout(const std::string &pTblName, transaction *pTx); 22 | void create_view(const std::string &pViewName, const std::string &pViewDiff, 23 | transaction *pTx); 24 | std::string get_view_def(const std::string &pViewName, transaction *pTx); 25 | void create_index(const std::string &pIdxName, const std::string &pTblName, 26 | const std::string &pFldName, transaction *pTx); 27 | std::map get_index_info(const std::string &pTblName, 28 | transaction *pTx) const; 29 | stat_info get_stat_info(const std::string &pTblName, const layout &pLt, 30 | transaction *pTx); 31 | 32 | private: 33 | static std::unique_ptr mTM; 34 | static std::unique_ptr mVM; 35 | static std::unique_ptr mSM; 36 | static std::unique_ptr mIM; 37 | }; 38 | } // namespace simpledb 39 | -------------------------------------------------------------------------------- /test/catalogtest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "metadata/tablemanager.hpp" 4 | #include "server/simpledb.hpp" 5 | #include "tx/transaction.hpp" 6 | #include "gtest/gtest.h" 7 | 8 | namespace simpledb { 9 | TEST(metadata, catalog_test) { 10 | simpledb db("catalogtest", 400, 8); 11 | auto tx = db.new_tx(); 12 | table_manager tM(true, tx.get()); 13 | 14 | schema sch1; 15 | sch1.add_int_field("A"); 16 | sch1.add_string_field("B", 9); 17 | tM.create_table("T1", sch1, tx.get()); 18 | 19 | schema sch2; 20 | sch2.add_int_field("C"); 21 | sch2.add_string_field("D", 9); 22 | tM.create_table("T2", sch2, tx.get()); 23 | 24 | layout tCatLayout = tM.get_layout("tblcat", tx.get()); 25 | std::cout << "Here are all the talbes and their lengths." << std::endl; 26 | table_scan tS1(tx.get(), "tblcat", tCatLayout); 27 | while (tS1.next()) { 28 | std::string tName = tS1.get_string("tblname"); 29 | int slotSize = tS1.get_int("slotsize"); 30 | std::cout << tName << " " << slotSize << std::endl; 31 | } 32 | tS1.close(); 33 | 34 | std::cout << "Here are the fields for each table and their offsets" 35 | << std::endl; 36 | layout fCatLayout = tM.get_layout("fldcat", tx.get()); 37 | table_scan tS2(tx.get(), "fldcat", fCatLayout); 38 | while (tS2.next()) { 39 | std::string tName = tS2.get_string("tblname"); 40 | std::string fName = tS2.get_string("fldname"); 41 | int offset = tS2.get_int("offset"); 42 | std::cout << tName << " " << fName << " " << offset << std::endl; 43 | } 44 | tS2.close(); 45 | tx->commit(); 46 | } 47 | } // namespace simpledb 48 | -------------------------------------------------------------------------------- /src/materialize/groupbyplan.cpp: -------------------------------------------------------------------------------- 1 | #include "materialize/groupbyplan.hpp" 2 | #include "materialize/groupbyscan.hpp" 3 | #include "materialize/sortplan.hpp" 4 | 5 | namespace simpledb { 6 | group_by_plan::group_by_plan( 7 | transaction *pTx, const std::shared_ptr &pP, 8 | const std::vector &pGroupFields, 9 | const std::vector> &pAggFns) 10 | : mGroupFields(pGroupFields), mAggFns(pAggFns) { 11 | mP = std::static_pointer_cast( 12 | std::make_shared(pTx, pP, mGroupFields)); 13 | for (const std::string &fldName : mGroupFields) { 14 | mSch.add(fldName, mP->get_schema()); 15 | } 16 | for (const auto &fn : mAggFns) { 17 | mSch.add_int_field(fn->field_name()); 18 | } 19 | } 20 | 21 | std::shared_ptr group_by_plan::open() { 22 | std::shared_ptr s = mP->open(); 23 | return std::static_pointer_cast( 24 | std::make_shared(s, mGroupFields, mAggFns)); 25 | } 26 | 27 | int group_by_plan::blocks_accessed() { return mP->blocks_accessed(); } 28 | 29 | int group_by_plan::records_output() { 30 | int numGroups = 1; 31 | for (const std::string &fldName : mGroupFields) { 32 | numGroups *= mP->distinct_values(fldName); 33 | } 34 | return numGroups; 35 | } 36 | 37 | int group_by_plan::distinct_values(const std::string &pFldName) { 38 | if (mP->get_schema().has_field(pFldName)) { 39 | return mP->distinct_values(pFldName); 40 | } else { 41 | return records_output(); 42 | } 43 | } 44 | 45 | schema group_by_plan::get_schema() { return mSch; } 46 | 47 | } // namespace simpledb 48 | -------------------------------------------------------------------------------- /include/metadata/indexmanager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "index/index.hpp" 7 | #include "metadata/statmanager.hpp" 8 | #include "metadata/tablemanager.hpp" 9 | 10 | namespace simpledb { 11 | class index_manager; 12 | 13 | class index_info { 14 | public: 15 | index_info(); 16 | index_info(const index_info &pII); 17 | index_info(const std::string &pIdxName, const std::string &pFldName, 18 | const schema &pTblSchema, transaction *pTx, const stat_info &pSI); 19 | 20 | index_info &operator=(const index_info &pII); 21 | std::shared_ptr open() const; 22 | int blocks_accessed(); 23 | int records_output(); 24 | int distinct_values(const std::string &pFldName); 25 | 26 | private: 27 | std::string mIdxName, mFldName; 28 | transaction *mTx; 29 | schema mTblSchema; 30 | stat_info mSI; 31 | layout mIdxLayout; 32 | 33 | layout create_idx_layout(); 34 | }; 35 | 36 | class index_manager : public std::enable_shared_from_this { 37 | friend class index_info; 38 | 39 | public: 40 | index_manager(bool pIsNew, table_manager *pTM, stat_manager *pSM, 41 | transaction *pTx); 42 | void create_index(const std::string &pIdxName, const std::string &pTblName, 43 | const std::string &pFldName, transaction *pTx); 44 | std::map get_index_info(const std::string &pTblName, 45 | transaction *pTx) const; 46 | 47 | private: 48 | table_manager *mTM; 49 | stat_manager *mSM; 50 | layout mLt; 51 | }; 52 | } // namespace simpledb 53 | -------------------------------------------------------------------------------- /src/index/planner/indexjoinplan.cpp: -------------------------------------------------------------------------------- 1 | #include "index/planner/indexjoinplan.hpp" 2 | #include "index/query/indexjoinscan.hpp" 3 | #include "record/tablescan.hpp" 4 | 5 | namespace simpledb { 6 | index_join_plan::index_join_plan(const std::shared_ptr &pP1, 7 | const std::shared_ptr &pP2, 8 | const index_info &pII, 9 | const std::string &pJoinField) 10 | : mP1(pP1), mP2(pP2), mII(pII), mJoinField(pJoinField) { 11 | mSch.add_all(mP1->get_schema()); 12 | mSch.add_all(mP2->get_schema()); 13 | } 14 | 15 | std::shared_ptr index_join_plan::open() { 16 | std::shared_ptr s = mP1->open(); 17 | std::shared_ptr tS = 18 | std::dynamic_pointer_cast(mP2->open()); 19 | if (!tS) { 20 | throw std::runtime_error("type conversion failed"); 21 | } 22 | std::shared_ptr idx = mII.open(); 23 | return std::static_pointer_cast( 24 | std::make_shared(s, idx, mJoinField, tS)); 25 | } 26 | 27 | int index_join_plan::blocks_accessed() { 28 | return mP1->blocks_accessed() + 29 | mP1->records_output() * mII.blocks_accessed() + records_output(); 30 | } 31 | 32 | int index_join_plan::records_output() { 33 | return mP1->records_output() * mII.records_output(); 34 | } 35 | 36 | int index_join_plan::distinct_values(const std::string &pFldName) { 37 | if (mP1->get_schema().has_field(pFldName)) { 38 | return mP1->distinct_values(pFldName); 39 | } else { 40 | return mP2->distinct_values(pFldName); 41 | } 42 | } 43 | 44 | schema index_join_plan::get_schema() { return mSch; } 45 | } // namespace simpledb 46 | -------------------------------------------------------------------------------- /include/jdbc/statementadapter.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mysql-connector-c++/cppconn/statement.h" 3 | 4 | namespace simpledb { 5 | class StatementAdapter : public sql::Statement { 6 | public: 7 | virtual sql::Connection *getConnection() override; 8 | 9 | virtual void cancel() override; 10 | 11 | virtual void clearWarnings() override; 12 | 13 | virtual void close() override; 14 | 15 | virtual bool execute(const sql::SQLString &sql) override; 16 | 17 | virtual sql::ResultSet *executeQuery(const sql::SQLString &sql) override; 18 | 19 | virtual int executeUpdate(const sql::SQLString &sql) override; 20 | 21 | virtual size_t getFetchSize() override; 22 | 23 | virtual unsigned int getMaxFieldSize() override; 24 | 25 | virtual uint64_t getMaxRows() override; 26 | 27 | virtual bool getMoreResults() override; 28 | 29 | virtual unsigned int getQueryTimeout() override; 30 | 31 | virtual sql::ResultSet *getResultSet() override; 32 | 33 | virtual sql::ResultSet::enum_type getResultSetType() override; 34 | 35 | virtual uint64_t getUpdateCount() override; 36 | 37 | virtual const sql::SQLWarning *getWarnings() override; 38 | 39 | virtual void setCursorName(const sql::SQLString &name) override; 40 | 41 | virtual void setEscapeProcessing(bool enable) override; 42 | 43 | virtual void setFetchSize(size_t rows) override; 44 | 45 | virtual void setMaxFieldSize(unsigned int max) override; 46 | 47 | virtual void setMaxRows(unsigned int max) override; 48 | 49 | virtual void setQueryTimeout(unsigned int seconds) override; 50 | 51 | virtual sql::Statement * 52 | setResultSetType(sql::ResultSet::enum_type type) override; 53 | }; 54 | } // namespace simpledb 55 | -------------------------------------------------------------------------------- /src/plan/planner.cpp: -------------------------------------------------------------------------------- 1 | #include "plan/planner.hpp" 2 | #include "parse/object.hpp" 3 | #include "parse/parser.hpp" 4 | 5 | namespace simpledb { 6 | planner::planner(std::unique_ptr pQP, 7 | std::unique_ptr pUP) 8 | : mQP(std::move(pQP)), mUP(std::move(pUP)) {} 9 | 10 | std::shared_ptr planner::create_query_plan(const std::string &pCMD, 11 | transaction *pTx) { 12 | parser p(pCMD); 13 | std::unique_ptr data = p.query(); 14 | return mQP->create_plan(data.get(), pTx); 15 | } 16 | 17 | int planner::execute_update(const std::string &pCMD, transaction *pTx) { 18 | parser p(pCMD); 19 | std::unique_ptr obj = p.update_cmd(); 20 | if (obj->op() == object::insert) { 21 | return mUP->execute_insert(static_cast(obj.get()), pTx); 22 | } else if (obj->op() == object::remove) { 23 | return mUP->execute_delete(static_cast(obj.get()), pTx); 24 | } else if (obj->op() == object::modify) { 25 | return mUP->execute_modify(static_cast(obj.get()), pTx); 26 | } else if (obj->op() == object::createtable) { 27 | return mUP->execute_create_table( 28 | static_cast(obj.get()), pTx); 29 | } else if (obj->op() == object::createview) { 30 | return mUP->execute_create_view(static_cast(obj.get()), 31 | pTx); 32 | } else if (obj->op() == object::createindex) { 33 | return mUP->execute_create_index( 34 | static_cast(obj.get()), pTx); 35 | } else { 36 | return 0; 37 | } 38 | } 39 | } // namespace simpledb 40 | -------------------------------------------------------------------------------- /src/plan/basicqueryplanner.cpp: -------------------------------------------------------------------------------- 1 | #include "plan/basicqueryplanner.hpp" 2 | #include "parse/parser.hpp" 3 | #include "plan/productplan.hpp" 4 | #include "plan/projectplan.hpp" 5 | #include "plan/selectplan.hpp" 6 | #include "plan/tableplan.hpp" 7 | 8 | namespace simpledb { 9 | basic_query_planner::basic_query_planner(metadata_manager *pMM) : mMM(pMM) {} 10 | 11 | std::shared_ptr basic_query_planner::create_plan(query_data *pData, 12 | transaction *pTx) { 13 | // step1 create a plan for each menthioned table or view 14 | std::vector> plans; 15 | for (const std::string &tblName : pData->tables()) { 16 | std::string viewDef = mMM->get_view_def(tblName, pTx); 17 | if (!viewDef.empty()) { 18 | parser p(viewDef); 19 | std::unique_ptr viewData = p.query(); 20 | plans.emplace_back(create_plan(viewData.get(), pTx)); 21 | } else { 22 | plans.emplace_back(std::static_pointer_cast( 23 | std::make_shared(pTx, tblName, mMM))); 24 | } 25 | } 26 | // step2 create the product of all table plans 27 | std::shared_ptr p = plans[0]; 28 | for (int i = 1; i < static_cast(plans.size()); i++) { 29 | p = std::static_pointer_cast( 30 | std::make_shared(p, plans[i])); 31 | } 32 | 33 | // step3 add a selection plan for the predicate 34 | p = std::static_pointer_cast( 35 | std::make_shared(p, pData->pred())); 36 | 37 | // step4 project on the field names 38 | return std::static_pointer_cast( 39 | std::make_shared(p, pData->fields())); 40 | } 41 | } // namespace simpledb 42 | -------------------------------------------------------------------------------- /include/buffer/buffermanager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "file/filemanager.hpp" 8 | #include "log/logmanager.hpp" 9 | 10 | namespace simpledb { 11 | class buffer { 12 | public: 13 | buffer(file_manager *pFileManager, log_manager *pLogManager); 14 | page *contents() const; 15 | block_id block() const; 16 | void set_modified(int pTxNum, int pLSN); 17 | bool is_pinned() const; 18 | int modifying_tx() const; 19 | void assign_to_block(const block_id &pBlockId); 20 | void flush(); 21 | void pin(); 22 | void unpin(); 23 | 24 | private: 25 | file_manager *mFileManager; 26 | log_manager *mLogManager; 27 | std::unique_ptr mContents; 28 | block_id mBlockId; 29 | int mPins = 0; 30 | int mTxNum = -1; // transaction that touched the buffer last 31 | int mLSN = -1; 32 | }; 33 | 34 | class buffer_manager { 35 | public: 36 | buffer_manager(file_manager *pFileManager, log_manager *pLogManager, 37 | int pNumBuffs); 38 | 39 | int available(); 40 | void flush_all(int pTxNum); 41 | void unpin(buffer *pBuff); 42 | buffer *pin(const block_id &pBlockId); 43 | 44 | private: 45 | std::vector> mBufferPool; 46 | int mNumAvailable; // number of unpinned buffers 47 | const int mMaxTime = 10000; 48 | std::mutex mMutex; 49 | std::condition_variable mCondVar; 50 | 51 | bool waiting_too_long( 52 | std::chrono::time_point pStartTime); 53 | buffer *try_to_pin(const block_id &pBlockId); 54 | buffer *find_existing_buffer(const block_id &pBlockId); 55 | buffer *choose_unpinned_buffer(); 56 | }; 57 | } // namespace simpledb 58 | -------------------------------------------------------------------------------- /test/producttest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "query/productscan.hpp" 4 | #include "record/layout.hpp" 5 | #include "server/simpledb.hpp" 6 | #include "tx/transaction.hpp" 7 | #include "gtest/gtest.h" 8 | 9 | namespace simpledb { 10 | TEST(query, product_test) { 11 | simpledb db("producttest"); 12 | auto tx = db.new_tx(); 13 | schema sch1; 14 | sch1.add_int_field("A"); 15 | sch1.add_string_field("B", 9); 16 | layout lt1(sch1); 17 | table_scan tS1(tx.get(), "T1", lt1); 18 | 19 | schema sch2; 20 | sch2.add_int_field("C"); 21 | sch2.add_string_field("D", 9); 22 | layout lt2(sch2); 23 | table_scan tS2(tx.get(), "T2", lt2); 24 | 25 | tS1.before_first(); 26 | int n = 200; 27 | std::cout << "Inserting " << n << " records into T1." << std::endl; 28 | for (int i = 0; i < n; i++) { 29 | tS1.insert(); 30 | tS1.set_int("A", i); 31 | tS1.set_string("B", "aaa" + std::to_string(i)); 32 | } 33 | tS1.close(); 34 | 35 | tS2.before_first(); 36 | std::cout << "Inserting " << n << " records into T2." << std::endl; 37 | for (int i = 0; i < n; i++) { 38 | tS2.insert(); 39 | tS2.set_int("C", n - i - 1); 40 | tS2.set_string("D", "bbb" + std::to_string(n - i - 1)); 41 | } 42 | tS2.close(); 43 | 44 | auto s1 = std::static_pointer_cast( 45 | std::make_shared(tx.get(), "T1", lt1)); 46 | auto s2 = std::static_pointer_cast( 47 | std::make_shared(tx.get(), "T2", lt2)); 48 | auto s3 = 49 | std::static_pointer_cast(std::make_shared(s1, s2)); 50 | while (s3->next()) { 51 | std::cout << s3->get_string("B") << std::endl; 52 | } 53 | s3->close(); 54 | tx->commit(); 55 | } 56 | } // namespace simpledb 57 | -------------------------------------------------------------------------------- /include/parse/streamtokenizer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "parse/pushbackreader.hpp" 8 | 9 | namespace simpledb { 10 | class stream_tokenizer { 11 | public: 12 | static int mTT_EOF; 13 | static int mTT_EOL; 14 | static int mTT_NUMBER; 15 | static int mTT_WORD; 16 | static int mTT_NONE; 17 | 18 | int mTType = mTT_NONE; 19 | std::string mSVal; 20 | double mNVal; 21 | 22 | stream_tokenizer(std::istream &pIS); 23 | void comment_char(int pCh); 24 | void eol_is_significant(bool pFlag); 25 | int line_no(); 26 | void lower_case_mode(bool pFlag); 27 | int next_token(); 28 | void ordinary_char(int pCh); 29 | void ordinary_chars(int pLow, int pHi); 30 | void parse_numbers(); 31 | void push_back(); 32 | void quote_char(int pCh); 33 | void reset_syntax(); 34 | void slash_slash_comments(bool pFlag); 35 | void slash_star_comments(bool pFlag); 36 | std::string to_string(); 37 | void whitespace_chars(int pLow, int pHi); 38 | void word_chars(int pLow, int pHi); 39 | 40 | private: 41 | bool mEOLSignificant = false; 42 | bool mLowerCase = false; 43 | bool mSlashSlash = false; 44 | bool mSlashStar = false; 45 | bool mPushedBack = false; 46 | int mLineNumber = 1; 47 | 48 | push_back_reader mIn; 49 | std::vector mWhitespace; 50 | std::vector mAlphabetic; 51 | std::vector mNumeric; 52 | std::vector mQuote; 53 | std::vector mComment; 54 | 55 | bool is_whitespace(int pCh); 56 | bool is_alphabetic(int pCh); 57 | bool is_numeric(int pCh); 58 | bool is_quote(int pCh); 59 | bool is_comment(int pCh); 60 | 61 | void reset_char(int pCh); 62 | }; 63 | } // namespace simpledb 64 | -------------------------------------------------------------------------------- /src/index/hash/hashindex.cpp: -------------------------------------------------------------------------------- 1 | #include "index/hash/hashindex.hpp" 2 | #include "query/constant.hpp" 3 | #include "record/rid.hpp" 4 | 5 | namespace simpledb { 6 | int hash_index::mNumBuckets = 100; 7 | 8 | hash_index::hash_index(transaction *pTx, const std::string &pIdxName, 9 | const layout &pLt) 10 | : mTx(pTx), mIdxName(pIdxName), mLt(pLt) {} 11 | 12 | void hash_index::before_first(const constant &pSearchKey) { 13 | close(); 14 | mSearchKey = pSearchKey; 15 | int bucket = mSearchKey.hash_code() % mNumBuckets; 16 | std::string tblName = mIdxName + std::to_string(bucket); 17 | mTS = std::make_unique(mTx, tblName, mLt); 18 | } 19 | 20 | bool hash_index::next() { 21 | while (mTS->next()) { 22 | if (mTS->get_val("dataval") == mSearchKey) { 23 | return true; 24 | } 25 | } 26 | return false; 27 | } 28 | 29 | rid hash_index::get_data_rid() { 30 | int blkNum = mTS->get_int("block"); 31 | int id = mTS->get_int("id"); 32 | return rid(blkNum, id); 33 | } 34 | 35 | void hash_index::insert(const constant &pVal, const rid &pRID) { 36 | before_first(pVal); 37 | mTS->insert(); 38 | mTS->set_int("block", pRID.block_number()); 39 | mTS->set_int("id", pRID.slot()); 40 | mTS->set_val("dataval", pVal); 41 | } 42 | 43 | void hash_index::remove(const constant &pVal, const rid &pRID) { 44 | before_first(pVal); 45 | while (next()) { 46 | if (get_data_rid() == pRID) { 47 | mTS->remove(); 48 | return; 49 | } 50 | } 51 | } 52 | 53 | void hash_index::close() { 54 | if (mTS) { 55 | mTS->close(); 56 | } 57 | } 58 | 59 | int hash_index::search_cost(int pNumBlocks, int pRPB) { 60 | return pNumBlocks / mNumBuckets; 61 | } 62 | } // namespace simpledb 63 | -------------------------------------------------------------------------------- /test/scantest1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "query/projectscan.hpp" 5 | #include "query/selectscan.hpp" 6 | #include "server/simpledb.hpp" 7 | #include "tx/transaction.hpp" 8 | #include "gtest/gtest.h" 9 | 10 | namespace simpledb { 11 | TEST(query, scantest1_test) { 12 | simpledb db("scantest1"); 13 | auto tx = db.new_tx(); 14 | 15 | schema sch1; 16 | sch1.add_int_field("A"); 17 | sch1.add_string_field("B", 9); 18 | layout lt(sch1); 19 | auto s1 = std::static_pointer_cast( 20 | std::make_shared(tx.get(), "T", lt)); 21 | 22 | s1->before_first(); 23 | int n = 200; 24 | std::cout << "Inserting " << n << " random records." << std::endl; 25 | 26 | std::random_device rd; 27 | std::mt19937 gen(rd()); 28 | std::uniform_real_distribution d(0, 1); 29 | 30 | for (int i = 0; i < n; i++) { 31 | s1->insert(); 32 | int k = round(d(gen) * 50); 33 | s1->set_int("A", k); 34 | s1->set_string("B", "rec" + std::to_string(k)); 35 | } 36 | s1->close(); 37 | 38 | auto s2 = std::static_pointer_cast( 39 | std::make_shared(tx.get(), "T", lt)); 40 | constant c(10); 41 | term t(expression("A"), expression(c)); 42 | predicate pred(t); 43 | 44 | std::cout << "The predicate is " << pred.to_string() << std::endl; 45 | auto s3 = 46 | std::static_pointer_cast(std::make_shared(s2, pred)); 47 | std::vector fields = {"B"}; 48 | auto s4 = std::static_pointer_cast( 49 | std::make_shared(s3, fields)); 50 | while (s4->next()) { 51 | std::cout << s4->get_string("B") << std::endl; 52 | } 53 | s4->close(); 54 | tx->commit(); 55 | } 56 | } // namespace simpledb 57 | -------------------------------------------------------------------------------- /src/record/layout.cpp: -------------------------------------------------------------------------------- 1 | #include "record/layout.hpp" 2 | #include "file/page.hpp" 3 | 4 | namespace simpledb { 5 | layout::layout() {} 6 | 7 | layout::layout(const layout &pLt) 8 | : mSchema(pLt.mSchema), mOffsets(pLt.mOffsets), mSlotSize(pLt.mSlotSize) {} 9 | 10 | layout::layout(const schema &pSchema) : mSchema(pSchema) { 11 | int pos = sizeof(int); // space for the emtpy/inuse flag 12 | for (const std::string &fldName : mSchema.fields()) { 13 | mOffsets[fldName] = pos; 14 | pos += length_in_bytes(fldName); 15 | } 16 | mSlotSize = pos; 17 | } 18 | 19 | layout::layout(const schema &pSchema, 20 | const std::map &pOffsets, int pSlotSize) 21 | : mSchema(pSchema), mOffsets(pOffsets), mSlotSize(pSlotSize) {} 22 | 23 | layout &layout::operator=(const layout &pLt) { 24 | if (this != &pLt) { 25 | mSchema = pLt.mSchema; 26 | mOffsets = pLt.mOffsets; 27 | mSlotSize = pLt.mSlotSize; 28 | } 29 | return *this; 30 | } 31 | 32 | schema layout::get_schema() const { return mSchema; } 33 | 34 | int layout::offset(const std::string &pFldName) { 35 | if (mOffsets.find(pFldName) == mOffsets.end()) { 36 | throw std::runtime_error("field name " + pFldName + " not found in schema"); 37 | } else { 38 | return mOffsets[pFldName]; 39 | } 40 | } 41 | 42 | int layout::slot_size() const { return mSlotSize; } 43 | 44 | int layout::length_in_bytes(const std::string &pFldName) { 45 | int fldType = mSchema.type(pFldName); 46 | if (fldType == schema::integer) { 47 | return sizeof(int); 48 | } else if (fldType == schema::varchar) { 49 | return page::max_length(mSchema.length(pFldName)); 50 | } else { 51 | throw std::runtime_error("field type not defined"); 52 | } 53 | } 54 | } // namespace simpledb 55 | -------------------------------------------------------------------------------- /test/logtest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "file/page.hpp" 4 | #include "log/logmanager.hpp" 5 | #include "server/simpledb.hpp" 6 | #include "gtest/gtest.h" 7 | 8 | namespace simpledb { 9 | void print_log_records(log_manager &lM, const std::string &msg) { 10 | std::cout << msg << std::endl; 11 | log_manager::log_iterator iter = lM.iterator(); 12 | while (iter.has_next()) { 13 | auto rec = std::make_shared>(iter.next()); 14 | page p(rec); 15 | std::string s = p.get_string(0); 16 | int npos = page::max_length(s.size()); 17 | int val = p.get_int(npos); 18 | std::cout << "[" << s << ", " << val << "]"; 19 | } 20 | std::cout << std::endl; 21 | } 22 | 23 | std::vector create_log_record(std::string s, int n) { 24 | int spos = 0; 25 | int npos = spos + page::max_length(s.size()); 26 | auto b = std::make_shared>(npos + sizeof(int)); 27 | page p(b); 28 | p.set_string(spos, s); 29 | p.set_int(npos, n); 30 | return *b; 31 | } 32 | 33 | void create_records(log_manager &lM, int start, int end) { 34 | std::cout << "Creating records: "; 35 | for (int i = start; i <= end; i++) { 36 | std::vector rec = 37 | create_log_record("record" + std::to_string(i), i + 100); 38 | int lsn = lM.append(rec); 39 | std::cout << lsn << " "; 40 | } 41 | std::cout << std::endl; 42 | } 43 | 44 | TEST(log, log_test) { 45 | simpledb db("logtest", 400, 8); 46 | log_manager &lM = db.log_mgr(); 47 | print_log_records(lM, "The initial empty log file: "); 48 | std::cout << "done" << std::endl; 49 | create_records(lM, 1, 35); 50 | print_log_records(lM, "The log file now has these records:"); 51 | create_records(lM, 36, 70); 52 | lM.flush(65); 53 | print_log_records(lM, "The log file now has these records:"); 54 | } 55 | } // namespace simpledb 56 | -------------------------------------------------------------------------------- /src/jdbc/embedded/embeddedresultset.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "jdbc/embedded/embeddedconnection.hpp" 7 | #include "jdbc/embedded/embeddedmetadata.hpp" 8 | #include "jdbc/embedded/embeddedresultset.hpp" 9 | 10 | namespace simpledb { 11 | EmbeddedResultSet::EmbeddedResultSet(plan &pPlan, EmbeddedConnection &pConn) 12 | : mConn(pConn), mS(pPlan.open()), mSch(pPlan.get_schema()) {} 13 | 14 | bool EmbeddedResultSet::next() { 15 | try { 16 | return mS->next(); 17 | } catch (const std::exception &e) { 18 | mConn.rollback(); 19 | throw sql::SQLException(e.what()); 20 | } 21 | } 22 | 23 | int32_t EmbeddedResultSet::getInt(const sql::SQLString &pColumnLabel) const { 24 | try { 25 | std::string fldName = pColumnLabel.asStdString(); 26 | std::transform(fldName.begin(), fldName.end(), fldName.begin(), 27 | [](unsigned char c) { return std::tolower(c); }); 28 | return mS->get_int(fldName); 29 | } catch (const std::exception &e) { 30 | mConn.rollback(); 31 | throw sql::SQLException(e.what()); 32 | } 33 | } 34 | 35 | sql::SQLString 36 | EmbeddedResultSet::getString(const sql::SQLString &pColumnLabel) const { 37 | try { 38 | std::string fldName = pColumnLabel.asStdString(); 39 | std::transform(fldName.begin(), fldName.end(), fldName.begin(), 40 | [](unsigned char c) { return std::tolower(c); }); 41 | return mS->get_string(fldName); 42 | } catch (const std::exception &e) { 43 | mConn.rollback(); 44 | throw sql::SQLException(e.what()); 45 | } 46 | } 47 | 48 | sql::ResultSetMetaData *EmbeddedResultSet::getMetaData() const { 49 | return new EmbeddedMetaData(mSch); 50 | } 51 | 52 | void EmbeddedResultSet::close() { 53 | mS->close(); 54 | mConn.commit(); 55 | } 56 | } // namespace simpledb 57 | -------------------------------------------------------------------------------- /include/index/btree/btpage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "file/blockid.hpp" 6 | #include "query/constant.hpp" 7 | #include "record/layout.hpp" 8 | #include "record/rid.hpp" 9 | #include "tx/transaction.hpp" 10 | 11 | namespace simpledb { 12 | class bt_page { 13 | public: 14 | bt_page(transaction *pTx, const block_id &pCurrentBlk, const layout &pLt); 15 | int find_slot_before(const constant &pSearchKey); 16 | void close(); 17 | bool is_full(); 18 | block_id split(int pSplitPos, int pFlag); 19 | constant get_data_val(int pSlot); 20 | int get_flag(); 21 | void set_flag(int pVal); 22 | block_id append_new(int pFlag); 23 | void format(const block_id &pBlk, int pFlag); 24 | 25 | int get_child_num(int pSlot); 26 | void insert_dir(int pSlot, const constant &pVal, int pBlkNum); 27 | rid get_data_rid(int pSlot); 28 | void insert_leaf(int pSlot, const constant &pVal, const rid &pRid); 29 | void remove(int pSlot); 30 | int get_num_recs(); 31 | 32 | private: 33 | transaction *mTx; 34 | block_id mCurrentBlk; 35 | layout mLt; 36 | 37 | void make_default_record(const block_id &pBlk, int pPos); 38 | int get_int(int pSlot, const std::string &pFldName); 39 | std::string get_string(int pSlot, const std::string &pFldName); 40 | constant get_val(int pSlot, const std::string &pFldName); 41 | void set_int(int pSlot, const std::string &pFldName, int pVal); 42 | void set_string(int pSlot, const std::string &pFldName, 43 | const std::string &pVal); 44 | void set_val(int pSlot, const std::string &pFldName, const constant &pVal); 45 | void set_num_recs(int pN); 46 | void insert(int pSlot); 47 | void copy_record(int pFrom, int pTo); 48 | void transfer_recs(int pSlot, bt_page *pDest); 49 | int fld_pos(int pSlot, const std::string &pFldName); 50 | int slot_pos(int pSlot); 51 | }; 52 | } // namespace simpledb 53 | -------------------------------------------------------------------------------- /include/jdbc/resultsetmetadataadapter.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "mysql-connector-c++/cppconn/resultset_metadata.h" 3 | 4 | namespace simpledb { 5 | class ResultSetMetaDataAdapter : public sql::ResultSetMetaData { 6 | virtual sql::SQLString getCatalogName(unsigned int column) override; 7 | 8 | virtual unsigned int getColumnCount() override; 9 | 10 | virtual unsigned int getColumnDisplaySize(unsigned int column) override; 11 | 12 | virtual sql::SQLString getColumnLabel(unsigned int column) override; 13 | 14 | virtual sql::SQLString getColumnName(unsigned int column) override; 15 | 16 | virtual int getColumnType(unsigned int column) override; 17 | 18 | virtual sql::SQLString getColumnTypeName(unsigned int column) override; 19 | 20 | virtual sql::SQLString getColumnCharset(unsigned int columnIndex) override; 21 | 22 | virtual sql::SQLString getColumnCollation(unsigned int columnIndex) override; 23 | 24 | virtual unsigned int getPrecision(unsigned int column) override; 25 | 26 | virtual unsigned int getScale(unsigned int column) override; 27 | 28 | virtual sql::SQLString getSchemaName(unsigned int column) override; 29 | 30 | virtual sql::SQLString getTableName(unsigned int column) override; 31 | 32 | virtual bool isAutoIncrement(unsigned int column) override; 33 | 34 | virtual bool isCaseSensitive(unsigned int column) override; 35 | 36 | virtual bool isCurrency(unsigned int column) override; 37 | 38 | virtual bool isDefinitelyWritable(unsigned int column) override; 39 | 40 | virtual int isNullable(unsigned int column) override; 41 | 42 | virtual bool isNumeric(unsigned int column) override; 43 | 44 | virtual bool isReadOnly(unsigned int column) override; 45 | 46 | virtual bool isSearchable(unsigned int column) override; 47 | 48 | virtual bool isSigned(unsigned int column) override; 49 | 50 | virtual bool isWritable(unsigned int column) override; 51 | 52 | virtual bool isZerofill(unsigned int column) override; 53 | }; 54 | } // namespace simpledb 55 | -------------------------------------------------------------------------------- /src/materialize/mergejoinplan.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "materialize/mergejoinplan.hpp" 4 | #include "materialize/mergejoinscan.hpp" 5 | #include "materialize/sortplan.hpp" 6 | 7 | namespace simpledb { 8 | merge_join_plan::merge_join_plan(transaction *pTx, 9 | const std::shared_ptr &pP1, 10 | const std::shared_ptr &pP2, 11 | const std::string &pFldName1, 12 | const std::string &pFldName2) 13 | : mFldName1(pFldName1), mFldName2(pFldName2) { 14 | std::vector sortList1 = {mFldName1}; 15 | mP1 = std::static_pointer_cast( 16 | std::make_shared(pTx, pP1, sortList1)); 17 | std::vector sortList2 = {mFldName2}; 18 | mP2 = std::static_pointer_cast( 19 | std::make_shared(pTx, mP2, sortList2)); 20 | mSch.add_all(mP1->get_schema()); 21 | mSch.add_all(mP2->get_schema()); 22 | } 23 | 24 | std::shared_ptr merge_join_plan::open() { 25 | std::shared_ptr s1 = mP1->open(); 26 | auto s2 = std::static_pointer_cast(mP2->open()); 27 | return std::static_pointer_cast( 28 | std::make_shared(s1, s2, mFldName1, mFldName2)); 29 | } 30 | 31 | int merge_join_plan::blocks_accessed() { 32 | return mP1->blocks_accessed() + mP2->blocks_accessed(); 33 | } 34 | 35 | int merge_join_plan::records_output() { 36 | int maxVals = std::max(mP1->distinct_values(mFldName1), 37 | mP2->distinct_values(mFldName2)); 38 | return (mP1->records_output() * mP2->records_output()) / maxVals; 39 | } 40 | 41 | int merge_join_plan::distinct_values(const std::string &pFldName) { 42 | if (mP1->get_schema().has_field(pFldName)) { 43 | return mP1->distinct_values(pFldName); 44 | } else { 45 | return mP2->distinct_values(pFldName); 46 | } 47 | } 48 | 49 | schema merge_join_plan::get_schema() { return mSch; } 50 | } // namespace simpledb 51 | -------------------------------------------------------------------------------- /src/multibuffer/chunkscan.cpp: -------------------------------------------------------------------------------- 1 | #include "multibuffer/chunkscan.hpp" 2 | #include "record/schema.hpp" 3 | 4 | namespace simpledb { 5 | chunk_scan::chunk_scan(transaction *pTx, const std::string &pFileName, 6 | const layout &pLt, int pStartBNum, int pEndBNum) 7 | : mTx(pTx), mFileName(pFileName), mLt(pLt), mStartBNum(pStartBNum), 8 | mEndBNum(pEndBNum) { 9 | for (int i = mStartBNum; i <= mEndBNum; i++) { 10 | block_id blk(mFileName, i); 11 | auto rP = std::make_unique(mTx, blk, mLt); 12 | mBuffs.emplace_back(std::move(rP)); 13 | } 14 | move_to_block(mStartBNum); 15 | } 16 | 17 | void chunk_scan::before_first() { move_to_block(mStartBNum); } 18 | 19 | void chunk_scan::close() { 20 | for (int i = 0; i < mBuffs.size(); i++) { 21 | block_id blk(mFileName, mStartBNum + i); 22 | mTx->unpin(blk); 23 | } 24 | } 25 | 26 | bool chunk_scan::next() { 27 | mCurrentSlot = mRP->next_after(mCurrentSlot); 28 | while (mCurrentSlot < 0) { 29 | if (mCurrentBNum == mEndBNum) { 30 | return false; 31 | } 32 | move_to_block(mRP->block().number() + 1); 33 | mCurrentSlot = mRP->next_after(mCurrentSlot); 34 | } 35 | return true; 36 | } 37 | 38 | int chunk_scan::get_int(const std::string &pFldName) { 39 | return mRP->get_int(mCurrentSlot, pFldName); 40 | } 41 | 42 | std::string chunk_scan::get_string(const std::string &pFldName) { 43 | return mRP->get_string(mCurrentSlot, pFldName); 44 | } 45 | 46 | constant chunk_scan::get_val(const std::string &pFldName) { 47 | if (mLt.get_schema().type(pFldName) == schema::integer) { 48 | return constant(get_int(pFldName)); 49 | } else { 50 | return constant(get_string(pFldName)); 51 | } 52 | } 53 | 54 | bool chunk_scan::has_field(const std::string &pFldName) { 55 | return mLt.get_schema().has_field(pFldName); 56 | } 57 | 58 | void chunk_scan::move_to_block(int pBlkNum) { 59 | mCurrentBNum = pBlkNum; 60 | mRP = mBuffs[mCurrentBNum - mStartBNum].get(); 61 | mCurrentSlot = -1; 62 | } 63 | } // namespace simpledb 64 | -------------------------------------------------------------------------------- /src/index/query/indexjoinscan.cpp: -------------------------------------------------------------------------------- 1 | #include "index/query/indexjoinscan.hpp" 2 | 3 | namespace simpledb { 4 | index_join_scan::index_join_scan(const std::shared_ptr &pLhs, 5 | const std::shared_ptr &pIdx, 6 | const std::string &pJoinFld, 7 | const std::shared_ptr &pRhs) 8 | : mLhs(pLhs), mIdx(pIdx), mJoinField(pJoinFld), mRhs(pRhs) 9 | 10 | { 11 | mLhs->before_first(); 12 | mLhs->next(); 13 | reset_index(); 14 | } 15 | 16 | void index_join_scan::before_first() { 17 | mLhs->before_first(); 18 | mLhs->next(); 19 | reset_index(); 20 | } 21 | 22 | bool index_join_scan::next() { 23 | while (true) { 24 | if (mIdx->next()) { 25 | mRhs->move_to_rid(mIdx->get_data_rid()); 26 | return true; 27 | } 28 | if (!mLhs->next()) { 29 | return false; 30 | } 31 | reset_index(); 32 | } 33 | } 34 | 35 | int index_join_scan::get_int(const std::string &pFldName) { 36 | if (mRhs->has_field(pFldName)) { 37 | return mRhs->get_int(pFldName); 38 | } else { 39 | return mLhs->get_int(pFldName); 40 | } 41 | } 42 | 43 | std::string index_join_scan::get_string(const std::string &pFldName) { 44 | if (mRhs->has_field(pFldName)) { 45 | return mRhs->get_string(pFldName); 46 | } else { 47 | return mLhs->get_string(pFldName); 48 | } 49 | } 50 | 51 | constant index_join_scan::get_val(const std::string &pFldName) { 52 | if (mRhs->has_field(pFldName)) { 53 | return mRhs->get_val(pFldName); 54 | } else { 55 | return mLhs->get_val(pFldName); 56 | } 57 | } 58 | 59 | bool index_join_scan::has_field(const std::string &pFldName) { 60 | return mRhs->has_field(pFldName) || mLhs->has_field(pFldName); 61 | } 62 | 63 | void index_join_scan::close() { 64 | mLhs->close(); 65 | mIdx->close(); 66 | mRhs->close(); 67 | } 68 | 69 | void index_join_scan::reset_index() { 70 | constant searchKey = mLhs->get_val(mJoinField); 71 | mIdx->before_first(searchKey); 72 | } 73 | } // namespace simpledb 74 | -------------------------------------------------------------------------------- /third_party/mysql-connector-c++/cppconn/version_info.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License, version 2.0, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is also distributed with certain software (including 9 | * but not limited to OpenSSL) that is licensed under separate terms, 10 | * as designated in a particular file or component or in included license 11 | * documentation. The authors of MySQL hereby grant you an 12 | * additional permission to link the program and your derivative works 13 | * with the separately licensed software that they have included with 14 | * MySQL. 15 | * 16 | * Without limiting anything contained in the foregoing, this file, 17 | * which is part of MySQL Connector/C++, is also subject to the 18 | * Universal FOSS Exception, version 1.0, a copy of which can be found at 19 | * http://oss.oracle.com/licenses/universal-foss-exception. 20 | * 21 | * This program is distributed in the hope that it will be useful, but 22 | * WITHOUT ANY WARRANTY; without even the implied warranty of 23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 24 | * See the GNU General Public License, version 2.0, for more details. 25 | * 26 | * You should have received a copy of the GNU General Public License 27 | * along with this program; if not, write to the Free Software Foundation, Inc., 28 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 29 | */ 30 | 31 | /* */ 32 | 33 | #define MYCPPCONN_DM_MAJOR_VERSION 8 34 | #define MYCPPCONN_DM_MINOR_VERSION 0 35 | #define MYCPPCONN_DM_PATCH_VERSION 23 36 | 37 | #define MYCPPCONN_DM_VERSION "8.00.0023" 38 | #define MYCPPCONN_DM_VERSION_ID 8000023 39 | 40 | 41 | /* Driver version info */ 42 | 43 | #define MYCPPCONN_STATIC_MYSQL_VERSION "8.0.23" 44 | #define MYCPPCONN_STATIC_MYSQL_VERSION_ID 80023 45 | 46 | #define MYCPPCONN_BOOST_VERSION 47 | -------------------------------------------------------------------------------- /test/transactiontest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "buffer/buffermanager.hpp" 4 | #include "file/blockid.hpp" 5 | #include "file/filemanager.hpp" 6 | #include "file/page.hpp" 7 | #include "log/logmanager.hpp" 8 | #include "server/simpledb.hpp" 9 | #include "gtest/gtest.h" 10 | 11 | namespace simpledb { 12 | TEST(tx, transaction_test) { 13 | simpledb db("txtest", 400, 8); 14 | file_manager &fM = db.file_mgr(); 15 | log_manager &lM = db.log_mgr(); 16 | buffer_manager &bM = db.buffer_mgr(); 17 | 18 | auto tx1 = std::make_unique(&fM, &lM, &bM); 19 | block_id blk("testfile", 1); 20 | tx1->pin(blk); 21 | 22 | // The block initially contains unkown bytes 23 | // so don't log those values here 24 | tx1->set_int(blk, 80, 1, false); 25 | tx1->set_string(blk, 40, "one", false); 26 | tx1->commit(); 27 | 28 | auto tx2 = std::make_unique(&fM, &lM, &bM); 29 | tx2->pin(blk); 30 | int iVal = tx2->get_int(blk, 80); 31 | std::string sVal = tx2->get_string(blk, 40); 32 | std::cout << "inital value at location 80 = " << iVal << std::endl; 33 | std::cout << "inital value at location 40 =" << sVal << std::endl; 34 | int newIVal = iVal + 1; 35 | std::string newSVal = sVal + "!"; 36 | tx2->set_int(blk, 80, newIVal, true); 37 | tx2->set_string(blk, 40, newSVal, true); 38 | tx2->commit(); 39 | 40 | auto tx3 = std::make_unique(&fM, &lM, &bM); 41 | tx3->pin(blk); 42 | std::cout << "new value at location 80 = " << tx3->get_int(blk, 80) 43 | << std::endl; 44 | std::cout << "new value at location 40 = " << tx3->get_string(blk, 40) 45 | << std::endl; 46 | tx3->set_int(blk, 80, 9999, true); 47 | std::cout << "pre-rollback value at location 80 = " << tx3->get_int(blk, 80) 48 | << std::endl; 49 | tx3->rollback(); 50 | 51 | auto tx4 = std::make_unique(&fM, &lM, &bM); 52 | tx4->pin(blk); 53 | std::cout << "post-rollback at location 80 = " << tx4->get_int(blk, 80) 54 | << std::endl; 55 | tx4->commit(); 56 | } 57 | } // namespace simpledb 58 | -------------------------------------------------------------------------------- /test/tablescantest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "record/tablescan.hpp" 5 | #include "server/simpledb.hpp" 6 | #include "gtest/gtest.h" 7 | 8 | namespace simpledb { 9 | TEST(record, tablescan_test) { 10 | simpledb db("tabletest", 400, 8); 11 | auto tx = db.new_tx(); 12 | schema sch; 13 | sch.add_int_field("A"); 14 | sch.add_string_field("B", 9); 15 | layout lt(sch); 16 | 17 | for (const std::string &fldName : lt.get_schema().fields()) { 18 | int offset = lt.offset(fldName); 19 | std::cout << fldName + " has offset " << offset << std::endl; 20 | } 21 | 22 | std::cout << "filling the page with 50 random records." << std::endl; 23 | table_scan tS(tx.get(), "T", lt); 24 | 25 | std::random_device rd; 26 | std::mt19937 gen(rd()); 27 | std::uniform_real_distribution d(0, 1); 28 | 29 | for (int i = 0; i < 50; i++) { 30 | tS.insert(); 31 | int n = round(d(gen) * 50); 32 | tS.set_int("A", n); 33 | tS.set_string("B", "rec" + std::to_string(n)); 34 | std::cout << "inserting into slot " << tS.get_rid().to_string() << ": {" 35 | << n << ", rec" << n << "}" << std::endl; 36 | } 37 | 38 | std::cout << "deleted these records with A-values < 25." << std::endl; 39 | int count = 0; 40 | tS.before_first(); 41 | while (tS.next()) { 42 | int a = tS.get_int("A"); 43 | std::string b = tS.get_string("B"); 44 | if (a < 25) { 45 | count++; 46 | std::cout << "slot " << tS.get_rid().to_string() << ": {" << a << ", " 47 | << b << "}" << std::endl; 48 | tS.remove(); 49 | } 50 | } 51 | 52 | std::cout << count << " values under 25 were deleted" << std::endl; 53 | std::cout << " here are the remaining records" << std::endl; 54 | tS.before_first(); 55 | while (tS.next()) { 56 | int a = tS.get_int("A"); 57 | std::string b = tS.get_string("B"); 58 | std::cout << "slot " << tS.get_rid().to_string() << ": {" << a << ", " << b 59 | << "}" << std::endl; 60 | } 61 | tS.close(); 62 | tx->commit(); 63 | } 64 | } // namespace simpledb 65 | -------------------------------------------------------------------------------- /test/indexselecttest.cpp: -------------------------------------------------------------------------------- 1 | #include "index/planner/indexselectplan.hpp" 2 | #include "metadata/indexmanager.hpp" 3 | #include "metadata/metadatamanager.hpp" 4 | #include "plan/plan.hpp" 5 | #include "plan/tableplan.hpp" 6 | #include "record/rid.hpp" 7 | #include "server/simpledb.hpp" 8 | #include "tx/transaction.hpp" 9 | #include "gtest/gtest.h" 10 | 11 | namespace simpledb { 12 | void use_index_manually(const index_info &iI, const std::shared_ptr &p, 13 | const constant &c) { 14 | std::shared_ptr s = 15 | std::static_pointer_cast(p->open()); 16 | std::shared_ptr idx = iI.open(); 17 | 18 | idx->before_first(c); 19 | while (idx->next()) { 20 | rid dataRID = idx->get_data_rid(); 21 | s->move_to_rid(dataRID); 22 | std::cout << s->get_string("grade") << std::endl; 23 | } 24 | idx->close(); 25 | s->close(); 26 | } 27 | 28 | void use_index_scan(const index_info &iI, const std::shared_ptr &p, 29 | const constant &c) { 30 | std::shared_ptr idxPlan = std::static_pointer_cast( 31 | std::make_shared(p, iI, c)); 32 | std::shared_ptr s = idxPlan->open(); 33 | 34 | while (s->next()) { 35 | std::cout << s->get_string("grade") << std::endl; 36 | } 37 | s->close(); 38 | } 39 | 40 | TEST(index_query, indexselect_test) { 41 | simpledb db("root:password@localhost"); 42 | metadata_manager &mM = db.md_mgr(); 43 | auto tx = db.new_tx(); 44 | 45 | // Find the index on studentid. 46 | std::map indexes = 47 | mM.get_index_info("enroll", tx.get()); 48 | index_info sIdIdx = indexes.at("studentid"); 49 | 50 | // get the plan for the enroll table 51 | std::shared_ptr enrollPlan = std::static_pointer_cast( 52 | std::make_shared(tx.get(), "enroll", &mM)); 53 | 54 | // create the selection constant 55 | constant c(6); 56 | 57 | // two different ways to use the index in simpledb: 58 | use_index_manually(sIdIdx, enrollPlan, c); 59 | use_index_scan(sIdIdx, enrollPlan, c); 60 | 61 | tx->commit(); 62 | } 63 | } // namespace simpledb 64 | -------------------------------------------------------------------------------- /src/tx/concurrency/locktable.cpp: -------------------------------------------------------------------------------- 1 | #include "tx/concurrency/locktable.hpp" 2 | 3 | namespace simpledb { 4 | lock_table::lock_table() {} 5 | void lock_table::slock(const block_id &pBlockId) { 6 | std::unique_lock lock(mMutex); 7 | auto start = std::chrono::high_resolution_clock::now(); 8 | while (has_xlock(pBlockId) && !waiting_too_long(start)) { 9 | mCondVar.wait_for(lock, std::chrono::milliseconds(mMaxTime)); 10 | } 11 | if (has_xlock(pBlockId)) { 12 | throw std::runtime_error("lock abort exception"); 13 | } 14 | int val = get_lock_val(pBlockId); 15 | mLocks[pBlockId] = val + 1; 16 | } 17 | 18 | void lock_table::xlock(const block_id &pBlockId) { 19 | std::unique_lock lock(mMutex); 20 | auto start = std::chrono::high_resolution_clock::now(); 21 | while (has_other_slocks(pBlockId) && !waiting_too_long(start)) { 22 | mCondVar.wait_for(lock, std::chrono::milliseconds(mMaxTime)); 23 | } 24 | if (has_other_slocks(pBlockId)) { 25 | throw std::runtime_error("lock abort exception"); 26 | } 27 | mLocks[pBlockId] = -1; 28 | } 29 | 30 | void lock_table::unlock(const block_id &pBlockId) { 31 | std::unique_lock lock(mMutex); 32 | int val = get_lock_val(pBlockId); 33 | if (val > 1) { 34 | mLocks[pBlockId]--; 35 | } else { 36 | mLocks.erase(pBlockId); 37 | mCondVar.notify_all(); 38 | } 39 | } 40 | 41 | bool lock_table::has_xlock(const block_id &pBlockId) { 42 | return get_lock_val(pBlockId) < 0; 43 | } 44 | 45 | bool lock_table::has_other_slocks(const block_id &pBlockId) { 46 | return get_lock_val(pBlockId) > 1; 47 | } 48 | 49 | bool lock_table::waiting_too_long( 50 | std::chrono::time_point pStartTime) { 51 | auto end = std::chrono::high_resolution_clock::now(); 52 | double elapsed = 53 | std::chrono::duration_cast(end - pStartTime) 54 | .count(); 55 | return elapsed > mMaxTime; 56 | } 57 | 58 | int lock_table::get_lock_val(const block_id &pBlockId) { 59 | auto iter = mLocks.find(pBlockId); 60 | return ((iter == mLocks.end()) ? 0 : iter->second); 61 | } 62 | } // namespace simpledb 63 | -------------------------------------------------------------------------------- /src/server/simpledb.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "index/planner/indexupdateplanner.hpp" 6 | #include "opt/heuristicqueryplanner.hpp" 7 | #include "plan/basicqueryplanner.hpp" 8 | #include "plan/basicupdateplanner.hpp" 9 | #include "server/simpledb.hpp" 10 | 11 | namespace simpledb { 12 | int simpledb::mBlockSize = 400; 13 | int simpledb::mBufferSize = 8; 14 | std::string simpledb::mLogFile = "simpledb.log"; 15 | 16 | simpledb::simpledb(const std::string &pDirName, int pBlockSize, int pBuffSize) { 17 | auto path = std::filesystem::current_path() / pDirName; 18 | mFM = std::make_unique(path, pBlockSize); 19 | mLM = std::make_unique(mFM.get(), mLogFile); 20 | mBM = std::make_unique(mFM.get(), mLM.get(), pBuffSize); 21 | } 22 | 23 | simpledb::simpledb(const std::string &pDirName) 24 | : simpledb(pDirName, mBlockSize, mBufferSize) { 25 | auto tx = std::make_unique(mFM.get(), mLM.get(), mBM.get()); 26 | bool isNew = mFM->is_new(); 27 | if (isNew) { 28 | std::cout << "creating new database" << std::endl; 29 | } else { 30 | std::cout << "recovering existing database" << std::endl; 31 | tx->recover(); 32 | } 33 | mMM = std::make_unique(isNew, tx.get()); 34 | // auto qP = std::make_unique(mMM.get()); 35 | auto qP = std::make_unique(*mMM); 36 | // auto uP = std::make_unique(mMM.get()); 37 | auto uP = std::make_unique(mMM.get()); 38 | mP = std::make_unique(std::move(qP), std::move(uP)); 39 | tx->commit(); 40 | } 41 | 42 | std::unique_ptr simpledb::new_tx() { 43 | auto txPtr = std::make_unique(mFM.get(), mLM.get(), mBM.get()); 44 | return txPtr; 45 | } 46 | 47 | metadata_manager &simpledb::md_mgr() { return *mMM; } 48 | 49 | file_manager &simpledb::file_mgr() { return *mFM; } 50 | 51 | planner &simpledb::plnr() { return *mP; } 52 | 53 | log_manager &simpledb::log_mgr() { return *mLM; } 54 | 55 | buffer_manager &simpledb::buffer_mgr() { return *mBM; } 56 | } // namespace simpledb 57 | -------------------------------------------------------------------------------- /third_party/mysql-connector-c++/mysql_error.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License, version 2.0, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is also distributed with certain software (including 9 | * but not limited to OpenSSL) that is licensed under separate terms, 10 | * as designated in a particular file or component or in included license 11 | * documentation. The authors of MySQL hereby grant you an 12 | * additional permission to link the program and your derivative works 13 | * with the separately licensed software that they have included with 14 | * MySQL. 15 | * 16 | * Without limiting anything contained in the foregoing, this file, 17 | * which is part of MySQL Connector/C++, is also subject to the 18 | * Universal FOSS Exception, version 1.0, a copy of which can be found at 19 | * http://oss.oracle.com/licenses/universal-foss-exception. 20 | * 21 | * This program is distributed in the hope that it will be useful, but 22 | * WITHOUT ANY WARRANTY; without even the implied warranty of 23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 24 | * See the GNU General Public License, version 2.0, for more details. 25 | * 26 | * You should have received a copy of the GNU General Public License 27 | * along with this program; if not, write to the Free Software Foundation, Inc., 28 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 29 | */ 30 | 31 | 32 | 33 | #ifndef _MYSQL_ERROR_H_ 34 | #define _MYSQL_ERROR_H_ 35 | 36 | namespace sql 37 | { 38 | namespace mysql 39 | { 40 | /* Driver specific errors */ 41 | enum DRIVER_ERROR { 42 | /* Underlying client library(cl) can't deal with expired password. 43 | Raised when password actually expires */ 44 | deCL_CANT_HANDLE_EXP_PWD= 820 45 | }; 46 | } /* namespace mysql */ 47 | } /* namespace sql */ 48 | 49 | #endif /* _MYSQL_ERROR_H_ */ 50 | 51 | /* 52 | * Local variables: 53 | * tab-width: 4 54 | * c-basic-offset: 4 55 | * End: 56 | * vim600: noet sw=4 ts=4 fdm=marker 57 | * vim<600: noet sw=4 ts=4 58 | */ 59 | -------------------------------------------------------------------------------- /src/file/blockid.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "file/blockid.hpp" 4 | 5 | namespace simpledb { 6 | bool operator==(const block_id &pLhs, const block_id &pRhs) { 7 | return (pLhs.mFileName == pRhs.mFileName) && 8 | (pLhs.mBlockNum == pRhs.mBlockNum); 9 | } 10 | 11 | bool operator!=(const block_id &pLhs, const block_id &pRhs) { 12 | if (pLhs == pRhs) { 13 | return false; 14 | } else { 15 | return true; 16 | } 17 | } 18 | 19 | bool operator<(const block_id &pLhs, const block_id &pRhs) { 20 | if (pLhs.mFileName == pRhs.mFileName) { 21 | return pLhs.mBlockNum < pRhs.mBlockNum; 22 | } else { 23 | return pLhs.mFileName < pRhs.mFileName; 24 | } 25 | } 26 | 27 | bool operator>(const block_id &pLhs, const block_id &pRhs) { 28 | if (pLhs.mFileName == pRhs.mFileName) { 29 | return pLhs.mBlockNum > pRhs.mBlockNum; 30 | } else { 31 | return pLhs.mFileName > pRhs.mFileName; 32 | } 33 | } 34 | 35 | bool operator<=(const block_id &pLhs, const block_id &pRhs) { 36 | if (pLhs > pRhs) { 37 | return false; 38 | } else { 39 | return true; 40 | } 41 | } 42 | 43 | bool operator>=(const block_id &pLhs, const block_id &pRhs) { 44 | if (pLhs < pRhs) { 45 | return false; 46 | } else { 47 | return true; 48 | } 49 | } 50 | 51 | block_id::block_id() {} 52 | 53 | block_id::block_id(const block_id &pBlk) 54 | : mFileName(pBlk.mFileName), mBlockNum(pBlk.mBlockNum) {} 55 | 56 | block_id::block_id(const std::string &pFileName, int pBlockNum) 57 | : mFileName(pFileName), mBlockNum(pBlockNum) {} 58 | 59 | bool block_id::is_null() { return mFileName.empty(); } 60 | 61 | block_id &block_id::operator=(const block_id &pBlk) { 62 | if (this != &pBlk) { 63 | mFileName = pBlk.mFileName; 64 | mBlockNum = pBlk.mBlockNum; 65 | } 66 | return *this; 67 | } 68 | 69 | std::string block_id::file_name() const { return mFileName; } 70 | 71 | int block_id::number() const { return mBlockNum; } 72 | 73 | bool block_id::equals(const block_id &obj) const { 74 | return (obj.file_name() == mFileName) && (obj.number() == mBlockNum); 75 | } 76 | 77 | std::string block_id::to_string() const { 78 | return mFileName + ", " + std::to_string(mBlockNum); 79 | } 80 | } // namespace simpledb 81 | -------------------------------------------------------------------------------- /src/materialize/groupbyscan.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "materialize/groupbyscan.hpp" 4 | 5 | namespace simpledb { 6 | group_by_scan::group_by_scan( 7 | const std::shared_ptr &pS, 8 | const std::vector &pGroupFields, 9 | const std::vector> &pAggFns) 10 | : mS(pS), mGroupFields(pGroupFields), mAggFns(pAggFns) { 11 | mS->before_first(); 12 | mMoreGroups = mS->next(); 13 | } 14 | 15 | void group_by_scan::before_first() { 16 | mS->before_first(); 17 | mMoreGroups = mS->next(); 18 | } 19 | 20 | bool group_by_scan::next() { 21 | if (!mMoreGroups) { 22 | return false; 23 | } 24 | for (const auto &fn : mAggFns) { 25 | fn->process_first(mS.get()); 26 | } 27 | mGroupVal = std::make_unique(mS.get(), mGroupFields); 28 | while ((mMoreGroups = mS->next())) { 29 | auto gv = std::make_unique(mS.get(), mGroupFields); 30 | if (*mGroupVal != *gv) { 31 | break; 32 | } 33 | for (const auto &fn : mAggFns) { 34 | fn->process_next(mS.get()); 35 | } 36 | } 37 | return true; 38 | } 39 | 40 | void group_by_scan::close() { mS->close(); } 41 | 42 | constant group_by_scan::get_val(const std::string &pFldName) { 43 | if (std::find(mGroupFields.begin(), mGroupFields.end(), pFldName) != 44 | mGroupFields.end()) { 45 | return mGroupVal->get_val(pFldName); 46 | } 47 | for (const auto &fn : mAggFns) { 48 | if (fn->field_name() == pFldName) { 49 | return fn->value(); 50 | } 51 | } 52 | throw std::runtime_error("field " + pFldName + " not found."); 53 | } 54 | 55 | int group_by_scan::get_int(const std::string &pFldName) { 56 | return get_val(pFldName).as_int(); 57 | } 58 | 59 | std::string group_by_scan::get_string(const std::string &pFldName) { 60 | return get_val(pFldName).as_string(); 61 | } 62 | 63 | bool group_by_scan::has_field(const std::string &pFldName) { 64 | if (std::find(mGroupFields.begin(), mGroupFields.end(), pFldName) != 65 | mGroupFields.end()) { 66 | return true; 67 | } 68 | for (const auto &fn : mAggFns) { 69 | if (fn->field_name() == pFldName) { 70 | return true; 71 | } 72 | } 73 | return false; 74 | } 75 | } // namespace simpledb 76 | -------------------------------------------------------------------------------- /src/materialize/sortscan.cpp: -------------------------------------------------------------------------------- 1 | #include "materialize/sortscan.hpp" 2 | 3 | namespace simpledb { 4 | sort_scan::sort_scan(const std::vector> &pRuns, 5 | record_comparator &pComp) 6 | : mComp(pComp), mHasMore2(false) { 7 | mS1 = std::static_pointer_cast(pRuns[0]->open()); 8 | mHasMore1 = mS1->next(); 9 | if (pRuns.size() > 1) { 10 | mS2 = std::static_pointer_cast(pRuns[1]->open()); 11 | mHasMore2 = mS2->next(); 12 | } 13 | } 14 | 15 | void sort_scan::before_first() { 16 | mS1->before_first(); 17 | mHasMore1 = mS1->next(); 18 | if (mS2) { 19 | mS2->before_first(); 20 | mHasMore2 = mS2->next(); 21 | } 22 | } 23 | 24 | bool sort_scan::next() { 25 | if (mCurrentScan == mS1) { 26 | mHasMore1 = mS1->next(); 27 | } else if (mCurrentScan == mS2) { 28 | mHasMore2 = mS2->next(); 29 | } 30 | 31 | if (!mHasMore1 && !mHasMore2) { 32 | return false; 33 | } else if (mHasMore1 && mHasMore2) { 34 | if (mComp.compare(mS1.get(), mS2.get()) < 0) { 35 | mCurrentScan = mS1; 36 | } else { 37 | mCurrentScan = mS2; 38 | } 39 | } else if (mHasMore1) { 40 | mCurrentScan = mS1; 41 | } else if (mHasMore2) { 42 | mCurrentScan = mS2; 43 | } 44 | return true; 45 | } 46 | 47 | void sort_scan::close() { 48 | mS1->close(); 49 | if (mS2) { 50 | mS2->close(); 51 | } 52 | } 53 | 54 | constant sort_scan::get_val(const std::string &pFldName) { 55 | return mCurrentScan->get_val(pFldName); 56 | } 57 | 58 | int sort_scan::get_int(const std::string &pFldName) { 59 | return mCurrentScan->get_int(pFldName); 60 | } 61 | 62 | std::string sort_scan::get_string(const std::string &pFldName) { 63 | return mCurrentScan->get_string(pFldName); 64 | } 65 | 66 | bool sort_scan::has_field(const std::string &pFldName) { 67 | return mCurrentScan->has_field(pFldName); 68 | } 69 | 70 | void sort_scan::save_position() { 71 | rid r1 = mS1->get_rid(); 72 | rid r2 = mS2->get_rid(); 73 | mSavedPosition = std::vector{r1, r2}; 74 | } 75 | 76 | void sort_scan::restore_position() { 77 | rid r1 = mSavedPosition[0]; 78 | rid r2 = mSavedPosition[1]; 79 | mS1->move_to_rid(r1); 80 | mS2->move_to_rid(r2); 81 | } 82 | 83 | } // namespace simpledb 84 | -------------------------------------------------------------------------------- /src/multibuffer/multibufferproductplan.cpp: -------------------------------------------------------------------------------- 1 | #include "multibuffer/multibufferproductplan.hpp" 2 | #include "materialize/materializeplan.hpp" 3 | #include "multibuffer/multibufferproductscan.hpp" 4 | 5 | namespace simpledb { 6 | multibuffer_product_plan::multibuffer_product_plan( 7 | transaction &pTx, const std::shared_ptr &pLhs, 8 | const std::shared_ptr &pRhs) 9 | : mTx(pTx) { 10 | mLhs = std::make_shared(&mTx, pLhs); 11 | mRhs = pRhs; 12 | mSch.add_all(mLhs->get_schema()); 13 | mSch.add_all(mRhs->get_schema()); 14 | } 15 | 16 | std::shared_ptr multibuffer_product_plan::open() { 17 | std::shared_ptr leftScan = mLhs->open(); 18 | std::shared_ptr tT = copy_records_from(*mRhs); 19 | return std::static_pointer_cast( 20 | std::make_shared( 21 | &mTx, leftScan, tT->table_name(), tT->get_layout())); 22 | } 23 | 24 | int multibuffer_product_plan::blocks_accessed() { 25 | int avail = mTx.available_buffers(); 26 | int size = std::make_unique(&mTx, mRhs)->blocks_accessed(); 27 | int numChunks = size / avail; 28 | return mRhs->blocks_accessed() + (mLhs->blocks_accessed() * numChunks); 29 | } 30 | 31 | int multibuffer_product_plan::records_output() { 32 | return mLhs->records_output() * mRhs->records_output(); 33 | } 34 | 35 | int multibuffer_product_plan::distinct_values(const std::string &pFldName) { 36 | if (mLhs->get_schema().has_field(pFldName)) { 37 | return mLhs->distinct_values(pFldName); 38 | } else { 39 | return mRhs->distinct_values(pFldName); 40 | } 41 | } 42 | 43 | schema multibuffer_product_plan::get_schema() { return mSch; } 44 | 45 | std::shared_ptr 46 | multibuffer_product_plan::copy_records_from(plan &p) { 47 | std::shared_ptr src = p.open(); 48 | schema sch = p.get_schema(); 49 | auto t = std::make_shared(&mTx, sch); 50 | auto dest = std::static_pointer_cast(t->open()); 51 | while (src->next()) { 52 | dest->insert(); 53 | for (const std::string &fldName : sch.fields()) { 54 | dest->set_val(fldName, src->get_val(fldName)); 55 | } 56 | } 57 | src->close(); 58 | dest->close(); 59 | return t; 60 | } 61 | } // namespace simpledb 62 | -------------------------------------------------------------------------------- /test/recordtest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "record/tablescan.hpp" 5 | #include "server/simpledb.hpp" 6 | #include "gtest/gtest.h" 7 | 8 | namespace simpledb { 9 | TEST(record, record_test) { 10 | simpledb db("recordtest", 400, 8); 11 | auto tx = db.new_tx(); 12 | schema sch; 13 | sch.add_int_field("A"); 14 | sch.add_string_field("B", 9); 15 | layout lt(sch); 16 | 17 | for (const std::string &fldName : lt.get_schema().fields()) { 18 | int offset = lt.offset(fldName); 19 | std::cout << fldName + " has offset " << offset << std::endl; 20 | } 21 | 22 | block_id blk = tx->append("testfile"); 23 | tx->pin(blk); 24 | record_page rP(tx.get(), blk, lt); 25 | rP.format(); 26 | 27 | std::cout << "filling the page with random records." << std::endl; 28 | std::random_device rd; 29 | std::mt19937 gen(rd()); 30 | std::uniform_real_distribution d(0, 1); 31 | 32 | int slot = rP.insert_after(-1); 33 | while (slot >= 0) { 34 | int n = round(d(gen) * 50); 35 | rP.set_int(slot, "A", n); 36 | rP.set_string(slot, "B", "rec" + std::to_string(n)); 37 | std::cout << "inserting into slot " << slot << ": {" << n << ", rec" << n 38 | << "}" << std::endl; 39 | slot = rP.insert_after(slot); 40 | } 41 | 42 | std::cout << "deleted these records with A-values < 25." << std::endl; 43 | int count = 0; 44 | slot = rP.next_after(-1); 45 | while (slot >= 0) { 46 | int a = rP.get_int(slot, "A"); 47 | std::string b = rP.get_string(slot, "B"); 48 | if (a < 25) { 49 | count++; 50 | std::cout << "slot " << slot << ": {" << a << ", " << b << "}" 51 | << std::endl; 52 | rP.remove(slot); 53 | } 54 | slot = rP.next_after(slot); 55 | } 56 | 57 | std::cout << count << " values under 25 were deleted" << std::endl; 58 | std::cout << " here are the remaining records" << std::endl; 59 | slot = rP.next_after(-1); 60 | while (slot >= 0) { 61 | int a = rP.get_int(slot, "A"); 62 | std::string b = rP.get_string(slot, "B"); 63 | std::cout << "slot " << slot << ": {" << a << ", " << b << "}" << std::endl; 64 | slot = rP.next_after(slot); 65 | } 66 | tx->unpin(blk); 67 | tx->commit(); 68 | } 69 | } // namespace simpledb 70 | -------------------------------------------------------------------------------- /src/record/schema.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "record/schema.hpp" 4 | 5 | namespace simpledb { 6 | schema::schema() {} 7 | 8 | schema::schema(const schema &pSch) { 9 | mFields = pSch.mFields; 10 | mInfo = pSch.mInfo; 11 | } 12 | 13 | schema &schema::operator=(const schema &pSch) { 14 | if (this != &pSch) { 15 | mFields = pSch.mFields; 16 | mInfo = pSch.mInfo; 17 | } 18 | return *this; 19 | } 20 | 21 | void schema::add_field(const std::string &pFldName, int pType, int pLength) { 22 | mFields.emplace_back(pFldName); 23 | mInfo[pFldName] = schema::field_info(pType, pLength); 24 | } 25 | 26 | void schema::add_int_field(const std::string &pFldName) { 27 | add_field(pFldName, integer, 0); 28 | } 29 | 30 | void schema::add_string_field(const std::string &pFldName, int length) { 31 | add_field(pFldName, varchar, length); 32 | } 33 | 34 | void schema::add(const std::string &pFldName, const schema &pSchema) { 35 | int type = pSchema.type(pFldName); 36 | int length = pSchema.length(pFldName); 37 | add_field(pFldName, type, length); 38 | } 39 | 40 | void schema::add_all(const schema &pSchema) { 41 | for (const std::string &fldName : pSchema.fields()) { 42 | add(fldName, pSchema); 43 | } 44 | } 45 | 46 | std::vector schema::fields() const { return mFields; } 47 | 48 | bool schema::has_field(const std::string &fldName) const { 49 | return (std::find(mFields.begin(), mFields.end(), fldName) != mFields.end()); 50 | } 51 | 52 | int schema::type(const std::string &pFldName) const { 53 | if (mInfo.find(pFldName) == mInfo.end()) { 54 | throw std::runtime_error("field info (" + pFldName + ") not found"); 55 | } else { 56 | return mInfo.at(pFldName).type(); 57 | } 58 | } 59 | 60 | int schema::length(const std::string &pFldName) const { 61 | if (mInfo.find(pFldName) == mInfo.end()) { 62 | throw std::runtime_error("field info (" + pFldName + ") not found"); 63 | } else { 64 | return mInfo.at(pFldName).length(); 65 | } 66 | } 67 | 68 | schema::field_info::field_info(int pType, int pLength) 69 | : mType(pType), mLength(pLength) {} 70 | 71 | int schema::field_info::type() const { return mType; } 72 | 73 | int schema::field_info::length() const { return mLength; } 74 | 75 | }; // namespace simpledb 76 | -------------------------------------------------------------------------------- /src/multibuffer/multibufferproductscan.cpp: -------------------------------------------------------------------------------- 1 | #include "multibuffer/multibufferproductscan.hpp" 2 | #include "multibuffer/bufferneeds.hpp" 3 | #include "multibuffer/chunkscan.hpp" 4 | #include "query/productscan.hpp" 5 | 6 | namespace simpledb { 7 | multibuffer_product_scan::multibuffer_product_scan( 8 | transaction *pTx, const std::shared_ptr &pLhsScan, 9 | const std::string &pTableName, const layout &pLt) 10 | : mTx(pTx), mLhsScan(pLhsScan), mFileName(pTableName + ".tbl"), mLt(pLt) { 11 | mFileSize = mTx->size(mFileName); 12 | int available = mTx->available_buffers(); 13 | mChunkSize = buffer_needs::best_factor(available, mFileSize); 14 | 15 | mNextBlkNum = 0; 16 | use_next_chunk(); 17 | } 18 | 19 | void multibuffer_product_scan::before_first() { 20 | mNextBlkNum = 0; 21 | use_next_chunk(); 22 | } 23 | 24 | bool multibuffer_product_scan::next() { 25 | while (!mProdScan->next()) { 26 | if (!use_next_chunk()) { 27 | return false; 28 | } 29 | } 30 | return true; 31 | } 32 | 33 | void multibuffer_product_scan::close() { mProdScan->close(); } 34 | 35 | constant multibuffer_product_scan::get_val(const std::string &pFldName) { 36 | return mProdScan->get_val(pFldName); 37 | } 38 | 39 | int multibuffer_product_scan::get_int(const std::string &pFldName) { 40 | return mProdScan->get_int(pFldName); 41 | } 42 | 43 | std::string multibuffer_product_scan::get_string(const std::string &pFldName) { 44 | return mProdScan->get_string(pFldName); 45 | } 46 | 47 | bool multibuffer_product_scan::has_field(const std::string &pFldName) { 48 | return mProdScan->has_field(pFldName); 49 | } 50 | 51 | bool multibuffer_product_scan::use_next_chunk() { 52 | if (mNextBlkNum >= mFileSize) { 53 | return false; 54 | } 55 | if (mRhsScan) { 56 | mRhsScan->close(); 57 | } 58 | int end = mNextBlkNum + mChunkSize - 1; 59 | if (end >= mFileSize) { 60 | end = mFileSize - 1; 61 | } 62 | mRhsScan = std::static_pointer_cast( 63 | std::make_shared(mTx, mFileName, mLt, mNextBlkNum, end)); 64 | mLhsScan->before_first(); 65 | mProdScan = std::static_pointer_cast( 66 | std::make_shared(mLhsScan, mRhsScan)); 67 | mNextBlkNum = end + 1; 68 | return true; 69 | } 70 | } // namespace simpledb 71 | -------------------------------------------------------------------------------- /src/materialize/mergejoinscan.cpp: -------------------------------------------------------------------------------- 1 | #include "materialize/mergejoinscan.hpp" 2 | 3 | namespace simpledb { 4 | merge_join_scan::merge_join_scan(const std::shared_ptr &pS1, 5 | const std::shared_ptr &pS2, 6 | const std::string &pFldName1, 7 | const std::string &pFldName2) 8 | : mS1(pS1), mS2(pS2), mFldName1(pFldName1), mFldName2(pFldName2) { 9 | mS1->before_first(); 10 | mS2->before_first(); 11 | } 12 | 13 | void merge_join_scan::close() { 14 | mS1->close(); 15 | mS2->close(); 16 | } 17 | 18 | void merge_join_scan::before_first() { 19 | mS1->before_first(); 20 | mS2->before_first(); 21 | } 22 | 23 | bool merge_join_scan::next() { 24 | bool hasMore2 = mS2->next(); 25 | if (hasMore2 && mS2->get_val(mFldName2) == mJoinVal) { 26 | return true; 27 | } 28 | bool hasMore1 = mS1->next(); 29 | if (hasMore1 && mS1->get_val(mFldName1) == mJoinVal) { 30 | mS2->restore_position(); 31 | return true; 32 | } 33 | 34 | while (hasMore1 && hasMore2) { 35 | constant v1 = mS1->get_val(mFldName1); 36 | constant v2 = mS2->get_val(mFldName2); 37 | if (v1 < v2) { 38 | hasMore1 = mS1->next(); 39 | } else if (v2 < v1) { 40 | hasMore2 = mS2->next(); 41 | } else { 42 | mS2->save_position(); 43 | mJoinVal = mS2->get_val(mFldName2); 44 | return true; 45 | } 46 | } 47 | 48 | return false; 49 | } 50 | 51 | int merge_join_scan::get_int(const std::string &pFldName) { 52 | if (mS1->has_field(pFldName)) { 53 | return mS1->get_int(pFldName); 54 | } else { 55 | return mS2->get_int(pFldName); 56 | } 57 | } 58 | 59 | std::string merge_join_scan::get_string(const std::string &pFldName) { 60 | if (mS1->has_field(pFldName)) { 61 | return mS1->get_string(pFldName); 62 | } else { 63 | return mS2->get_string(pFldName); 64 | } 65 | } 66 | 67 | constant merge_join_scan::get_val(const std::string &pFldName) { 68 | if (mS1->has_field(pFldName)) { 69 | return mS1->get_val(pFldName); 70 | } else { 71 | return mS2->get_val(pFldName); 72 | } 73 | } 74 | 75 | bool merge_join_scan::has_field(const std::string &pFldName) { 76 | return mS1->has_field(pFldName) || mS2->has_field(pFldName); 77 | } 78 | } // namespace simpledb 79 | -------------------------------------------------------------------------------- /third_party/mysql-connector-c++/cppconn/datatype.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License, version 2.0, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is also distributed with certain software (including 9 | * but not limited to OpenSSL) that is licensed under separate terms, 10 | * as designated in a particular file or component or in included license 11 | * documentation. The authors of MySQL hereby grant you an 12 | * additional permission to link the program and your derivative works 13 | * with the separately licensed software that they have included with 14 | * MySQL. 15 | * 16 | * Without limiting anything contained in the foregoing, this file, 17 | * which is part of MySQL Connector/C++, is also subject to the 18 | * Universal FOSS Exception, version 1.0, a copy of which can be found at 19 | * http://oss.oracle.com/licenses/universal-foss-exception. 20 | * 21 | * This program is distributed in the hope that it will be useful, but 22 | * WITHOUT ANY WARRANTY; without even the implied warranty of 23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 24 | * See the GNU General Public License, version 2.0, for more details. 25 | * 26 | * You should have received a copy of the GNU General Public License 27 | * along with this program; if not, write to the Free Software Foundation, Inc., 28 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 29 | */ 30 | 31 | 32 | 33 | #ifndef _SQL_DATATYPE_H_ 34 | #define _SQL_DATATYPE_H_ 35 | 36 | namespace sql 37 | { 38 | 39 | class DataType 40 | { 41 | DataType(); 42 | public: 43 | enum { 44 | UNKNOWN = 0, 45 | BIT, 46 | TINYINT, 47 | SMALLINT, 48 | MEDIUMINT, 49 | INTEGER, 50 | BIGINT, 51 | REAL, 52 | DOUBLE, 53 | DECIMAL, 54 | NUMERIC, 55 | CHAR, 56 | BINARY, 57 | VARCHAR, 58 | VARBINARY, 59 | LONGVARCHAR, 60 | LONGVARBINARY, 61 | TIMESTAMP, 62 | DATE, 63 | TIME, 64 | YEAR, 65 | GEOMETRY, 66 | ENUM, 67 | SET, 68 | SQLNULL, 69 | JSON 70 | }; 71 | }; 72 | 73 | } /* namespace */ 74 | 75 | #endif /* _SQL_DATATYPE_H_ */ 76 | -------------------------------------------------------------------------------- /src/metadata/metadatamanager.cpp: -------------------------------------------------------------------------------- 1 | #include "metadata/metadatamanager.hpp" 2 | 3 | namespace simpledb { 4 | std::unique_ptr metadata_manager::mTM; 5 | std::unique_ptr metadata_manager::mVM; 6 | std::unique_ptr metadata_manager::mSM; 7 | std::unique_ptr metadata_manager::mIM; 8 | 9 | metadata_manager::metadata_manager(bool pIsNew, transaction *pTx) { 10 | mTM = std::make_unique(pIsNew, pTx); 11 | mVM = std::make_unique(pIsNew, mTM.get(), pTx); 12 | mSM = std::make_unique(mTM.get(), pTx); 13 | mIM = std::make_unique(pIsNew, mTM.get(), mSM.get(), pTx); 14 | } 15 | 16 | void metadata_manager::create_table(const std::string &pTblName, 17 | const schema &pSch, transaction *pTx) { 18 | mTM->create_table(pTblName, pSch, pTx); 19 | } 20 | 21 | layout metadata_manager::get_layout(const std::string &pTblName, 22 | transaction *pTx) { 23 | return mTM->get_layout(pTblName, pTx); 24 | } 25 | 26 | void metadata_manager::create_view(const std::string &pViewName, 27 | const std::string &pViewDef, 28 | transaction *pTx) { 29 | mVM->create_view(pViewName, pViewDef, pTx); 30 | } 31 | 32 | std::string metadata_manager::get_view_def(const std::string &pViewName, 33 | transaction *pTx) { 34 | return mVM->get_view_def(pViewName, pTx); 35 | } 36 | 37 | void metadata_manager::create_index(const std::string &pIdxName, 38 | const std::string &pTblName, 39 | const std::string &pFldName, 40 | transaction *pTx) { 41 | mIM->create_index(pIdxName, pTblName, pFldName, pTx); 42 | } 43 | 44 | std::map 45 | metadata_manager::get_index_info(const std::string &pTblName, 46 | transaction *pTx) const { 47 | return mIM->get_index_info(pTblName, pTx); 48 | } 49 | 50 | stat_info metadata_manager::get_stat_info(const std::string &pTblName, 51 | const layout &pLt, transaction *pTx) { 52 | return mSM->get_stat_info(pTblName, pLt, pTx); 53 | } 54 | } // namespace simpledb 55 | -------------------------------------------------------------------------------- /test/parsertestactions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "parse/parser.hpp" 5 | #include "gtest/gtest.h" 6 | 7 | namespace simpledb { 8 | TEST(parse, parsertestactions_test) { 9 | std::string s1 = "select C from T where A =B"; 10 | std::string s2 = "insert into T(A, B, C) values('a' , 'b', 'c')"; 11 | std::string s3 = "delete from T where A=B"; 12 | std::string s4 = "update T set A='a' where B=C"; 13 | std::string s5 = "create table T(A int, B varchar(9))"; 14 | std::string s6 = "create view V as " + s1; 15 | std::string s7 = "create index I on T(A)"; 16 | 17 | parser p1(s1); 18 | std::cout << "Case 1" << std::endl; 19 | std::cout << "In: " << s1 << std::endl; 20 | std::cout << "Out: " << p1.query()->to_string() << std::endl; 21 | 22 | parser p2(s2); 23 | std::cout << "Case 2" << std::endl; 24 | std::cout << "In: " << s2 << std::endl; 25 | std::cout << "Out op: " 26 | << static_cast(p2.update_cmd()->op()) 27 | << std::endl; 28 | ; 29 | 30 | parser p3(s3); 31 | std::cout << "Case 3" << std::endl; 32 | std::cout << "In: " << s3 << std::endl; 33 | std::cout << "Out op: " 34 | << static_cast(p3.update_cmd()->op()) 35 | << std::endl; 36 | ; 37 | 38 | parser p4(s4); 39 | std::cout << "Case 4" << std::endl; 40 | std::cout << "In: " << s4 << std::endl; 41 | std::cout << "Out op: " 42 | << static_cast(p4.update_cmd()->op()) 43 | << std::endl; 44 | ; 45 | 46 | parser p5(s5); 47 | std::cout << "Case 5" << std::endl; 48 | std::cout << "In: " << s5 << std::endl; 49 | std::cout << "Out op: " 50 | << static_cast(p5.update_cmd()->op()) 51 | << std::endl; 52 | ; 53 | 54 | parser p6(s6); 55 | std::cout << "Case 6" << std::endl; 56 | std::cout << "In: " << s6 << std::endl; 57 | std::cout << "Out op: " 58 | << static_cast(p6.update_cmd()->op()) 59 | << std::endl; 60 | ; 61 | 62 | parser p7(s7); 63 | std::cout << "Case 7" << std::endl; 64 | std::cout << "In: " << s7 << std::endl; 65 | std::cout << "Out op: " 66 | << static_cast(p7.update_cmd()->op()) 67 | << std::endl; 68 | ; 69 | } 70 | } // namespace simpledb 71 | -------------------------------------------------------------------------------- /test/scantest2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "query/productscan.hpp" 5 | #include "query/projectscan.hpp" 6 | #include "query/selectscan.hpp" 7 | #include "server/simpledb.hpp" 8 | #include "tx/transaction.hpp" 9 | #include "gtest/gtest.h" 10 | 11 | namespace simpledb { 12 | TEST(query, scantest2_test) { 13 | simpledb db("scantest2"); 14 | auto tx = db.new_tx(); 15 | 16 | schema sch1; 17 | sch1.add_int_field("A"); 18 | sch1.add_string_field("B", 9); 19 | layout lt1(sch1); 20 | auto us1 = std::static_pointer_cast( 21 | std::make_shared(tx.get(), "T1", lt1)); 22 | 23 | us1->before_first(); 24 | int n = 200; 25 | std::cout << "Inserting " << n << " records into T1." << std::endl; 26 | 27 | for (int i = 0; i < n; i++) { 28 | us1->insert(); 29 | us1->set_int("A", i); 30 | us1->set_string("B", "bbb" + std::to_string(i)); 31 | } 32 | us1->close(); 33 | 34 | schema sch2; 35 | sch2.add_int_field("C"); 36 | sch2.add_string_field("D", 9); 37 | layout lt2(sch2); 38 | auto us2 = std::static_pointer_cast( 39 | std::make_shared(tx.get(), "T2", lt2)); 40 | us2->before_first(); 41 | std::cout << "Inserting " << n << " records into T2." << std::endl; 42 | for (int i = 0; i < n; i++) { 43 | us2->insert(); 44 | us2->set_int("C", n - i - 1); 45 | us2->set_string("D", "ddd" + std::to_string(n - i - 1)); 46 | } 47 | us2->close(); 48 | 49 | auto s1 = std::static_pointer_cast( 50 | std::make_shared(tx.get(), "T1", lt1)); 51 | auto s2 = std::static_pointer_cast( 52 | std::make_shared(tx.get(), "T2", lt2)); 53 | auto s3 = 54 | std::static_pointer_cast(std::make_shared(s1, s2)); 55 | 56 | // selecting all records where A=C 57 | term t(expression("A"), expression("C")); 58 | predicate pred(t); 59 | std::cout << "The predicate is " << pred.to_string() << std::endl; 60 | auto s4 = 61 | std::static_pointer_cast(std::make_shared(s3, pred)); 62 | 63 | // projecting on [B,D] 64 | std::vector c = {"B", "D"}; 65 | auto s5 = 66 | std::static_pointer_cast(std::make_shared(s4, c)); 67 | while (s5->next()) { 68 | std::cout << s5->get_string("B") << " " << s5->get_string("D") << std::endl; 69 | } 70 | s5->close(); 71 | tx->commit(); 72 | } 73 | } // namespace simpledb 74 | -------------------------------------------------------------------------------- /src/index/btree/btreedir.cpp: -------------------------------------------------------------------------------- 1 | #include "index/btree/btreedir.hpp" 2 | 3 | namespace simpledb { 4 | btree_dir::btree_dir(transaction *pTx, const block_id &pBlk, const layout &pLt) 5 | : mTx(pTx), mLt(pLt) { 6 | mContents = std::make_unique(mTx, pBlk, mLt); 7 | mFileName = pBlk.file_name(); 8 | } 9 | 10 | void btree_dir::close() { mContents->close(); } 11 | 12 | int btree_dir::search(const constant &pSearchKey) { 13 | block_id childBlk = find_child_block(pSearchKey); 14 | while (mContents->get_flag() > 0) { 15 | mContents->close(); 16 | mContents = std::make_unique(mTx, childBlk, mLt); 17 | childBlk = find_child_block(pSearchKey); 18 | } 19 | return childBlk.number(); 20 | } 21 | 22 | void btree_dir::make_new_root(const dir_entry &pDE) { 23 | constant firstVal = mContents->get_data_val(0); 24 | int level = mContents->get_flag(); 25 | block_id newBlk = mContents->split(0, level); 26 | dir_entry oldRoot = dir_entry(firstVal, newBlk.number()); 27 | insert_entry(oldRoot); 28 | insert_entry(pDE); 29 | mContents->set_flag(level + 1); 30 | } 31 | 32 | dir_entry btree_dir::insert(const dir_entry &pDE) { 33 | if (mContents->get_flag() == 0) { 34 | return insert_entry(pDE); 35 | } 36 | block_id childBlk = find_child_block(pDE.data_val()); 37 | btree_dir child(mTx, childBlk, mLt); 38 | dir_entry myEntry = child.insert(pDE); 39 | child.close(); 40 | if (myEntry.is_null()) { 41 | return dir_entry(); 42 | } else { 43 | return insert_entry(myEntry); 44 | } 45 | } 46 | 47 | dir_entry btree_dir::insert_entry(const dir_entry &pDE) { 48 | int newSlot = 1 + mContents->find_slot_before(pDE.data_val()); 49 | mContents->insert_dir(newSlot, pDE.data_val(), pDE.block_number()); 50 | if (!mContents->is_full()) { 51 | return dir_entry(); 52 | } 53 | // else page is full, so split it 54 | int level = mContents->get_flag(); 55 | int splitPos = mContents->get_num_recs() / 2; 56 | constant splitVal = mContents->get_data_val(splitPos); 57 | block_id newBlk = mContents->split(splitPos, level); 58 | return dir_entry(splitVal, newBlk.number()); 59 | } 60 | 61 | block_id btree_dir::find_child_block(const constant &pSearchKey) { 62 | int slot = mContents->find_slot_before(pSearchKey); 63 | if (mContents->get_data_val(slot + 1) == pSearchKey) { 64 | slot++; 65 | } 66 | int blkNum = mContents->get_child_num(slot); 67 | return block_id(mFileName, blkNum); 68 | } 69 | 70 | } // namespace simpledb 71 | -------------------------------------------------------------------------------- /src/query/constant.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "query/constant.hpp" 4 | 5 | namespace simpledb { 6 | bool operator==(const constant &pLhs, const constant &pRhs) { 7 | return (pLhs.mIVal ? *(pLhs.mIVal) == *(pRhs.mIVal) 8 | : *(pLhs.mSVal) == *(pRhs.mSVal)); 9 | } 10 | 11 | bool operator!=(const constant &pLhs, const constant &pRhs) { 12 | if (pLhs == pRhs) { 13 | return false; 14 | } else { 15 | return true; 16 | } 17 | } 18 | 19 | bool operator<(const constant &pLhs, const constant &pRhs) { 20 | return (pLhs.mIVal ? *(pLhs.mIVal) < *(pRhs.mIVal) 21 | : *(pLhs.mSVal) < *(pRhs.mSVal)); 22 | } 23 | 24 | bool operator>(const constant &pLhs, const constant &pRhs) { 25 | return (pLhs.mIVal ? *(pLhs.mIVal) > *(pRhs.mIVal) 26 | : *(pLhs.mSVal) > *(pRhs.mSVal)); 27 | } 28 | 29 | bool operator<=(const constant &pLhs, const constant &pRhs) { 30 | if (pLhs > pRhs) { 31 | return false; 32 | } else { 33 | return true; 34 | } 35 | } 36 | 37 | bool operator>=(const constant &pLhs, const constant &pRhs) { 38 | if (pLhs < pRhs) { 39 | return false; 40 | } else { 41 | return true; 42 | } 43 | } 44 | 45 | constant::constant() {} 46 | 47 | constant::constant(const constant &pVal) { 48 | if (pVal.mIVal) { 49 | mIVal = std::make_unique(*(pVal.mIVal)); 50 | } 51 | if (pVal.mSVal) { 52 | mSVal = std::make_unique(*(pVal.mSVal)); 53 | } 54 | } 55 | 56 | constant::constant(int pVal) { mIVal = std::make_unique(pVal); } 57 | 58 | constant::constant(const std::string &pVal) { 59 | mSVal = std::make_unique(pVal); 60 | } 61 | 62 | constant &constant::operator=(const constant &pVal) { 63 | if (this != &pVal) { 64 | if (pVal.mIVal) { 65 | mIVal = std::make_unique(*(pVal.mIVal)); 66 | } 67 | if (pVal.mSVal) { 68 | mSVal = std::make_unique(*(pVal.mSVal)); 69 | } 70 | } 71 | return *this; 72 | } 73 | 74 | int constant::as_int() const { return *mIVal; } 75 | 76 | std::string constant::as_string() const { return *mSVal; } 77 | 78 | std::string constant::to_string() const { 79 | return (mIVal ? std::to_string(*mIVal) : *mSVal); 80 | } 81 | 82 | int constant::hash_code() const { 83 | return (mIVal ? std::hash{}(*mIVal) : std::hash{}(*mSVal)); 84 | } 85 | 86 | bool constant::is_null() const { 87 | if (mIVal || mSVal) { 88 | return false; 89 | } else { 90 | return true; 91 | } 92 | } 93 | } // namespace simpledb 94 | -------------------------------------------------------------------------------- /include/parse/parser.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "parse/createindexdata.hpp" 7 | #include "parse/createtabledata.hpp" 8 | #include "parse/createviewdata.hpp" 9 | #include "parse/deletedata.hpp" 10 | #include "parse/insertdata.hpp" 11 | #include "parse/lexer.hpp" 12 | #include "parse/modifydata.hpp" 13 | #include "parse/object.hpp" 14 | #include "parse/querydata.hpp" 15 | #include "query/constant.hpp" 16 | #include "query/expression.hpp" 17 | #include "query/predicate.hpp" 18 | #include "query/term.hpp" 19 | #include "record/schema.hpp" 20 | 21 | namespace simpledb { 22 | class parser { 23 | public: 24 | parser(const std::string &pS); 25 | 26 | std::string new_field(); 27 | constant new_constant(); 28 | expression new_expression(); 29 | term new_term(); 30 | predicate new_predicate(); 31 | 32 | // methods for parsing queries 33 | std::unique_ptr query(); 34 | 35 | // methods for parsing the varioud update commands 36 | std::unique_ptr update_cmd(); 37 | 38 | // methods for parsing remove commands 39 | std::unique_ptr remove(); 40 | 41 | // methods for parsing insert commands 42 | std::unique_ptr insert(); 43 | 44 | // methods for parsing modify commands 45 | std::unique_ptr modify(); 46 | 47 | // method for parsing create table commands 48 | std::unique_ptr create_table(); 49 | 50 | // method for parsing create view commands 51 | std::unique_ptr create_view(); 52 | 53 | // method for parsing creaete index commands 54 | std::unique_ptr create_index(); 55 | 56 | private: 57 | lexer lex; 58 | 59 | // methods for parsing queries 60 | std::vector select_list(); 61 | std::set table_list(); 62 | 63 | // methods for parsing the various update commands 64 | std::unique_ptr create(); 65 | 66 | // methods for parsing insert commands 67 | std::vector field_list(); 68 | std::vector const_list(); 69 | 70 | // method for parsing create table commands 71 | schema field_defs(); 72 | schema field_def(); 73 | schema field_type(const std::string &pFldName); 74 | 75 | template 76 | std::unique_ptr static_unique_pointer_cast(std::unique_ptr &&old) { 77 | return std::unique_ptr{static_cast(old.release())}; 78 | // conversion: unique_ptr->FROM*->TO*->unique_ptr 79 | } 80 | }; 81 | } // namespace simpledb 82 | -------------------------------------------------------------------------------- /src/metadata/statmanager.cpp: -------------------------------------------------------------------------------- 1 | #include "metadata/statmanager.hpp" 2 | #include "record/tablescan.hpp" 3 | 4 | namespace simpledb { 5 | stat_info::stat_info() {} 6 | 7 | stat_info::stat_info(const stat_info &pSI) { 8 | mNumBlocks = pSI.mNumBlocks; 9 | mNumRecs = pSI.mNumRecs; 10 | } 11 | 12 | stat_info::stat_info(int pNumBlocks, int pNumRecs) 13 | : mNumBlocks(pNumBlocks), mNumRecs(pNumRecs) {} 14 | 15 | stat_info &stat_info::operator=(const stat_info &pSI) { 16 | if (this != &pSI) { 17 | mNumBlocks = pSI.mNumBlocks; 18 | mNumRecs = pSI.mNumRecs; 19 | } 20 | return *this; 21 | } 22 | 23 | int stat_info::blocks_accessed() { return mNumBlocks; } 24 | 25 | int stat_info::records_output() { return mNumRecs; } 26 | 27 | int stat_info::distinct_values(const std::string &pFldName) { 28 | return 1 + (mNumRecs / 3); // this is wildly inaccurate 29 | } 30 | 31 | stat_manager::stat_manager(table_manager *pTM, transaction *pTx) : mTM(pTM) { 32 | refresh_statistics(pTx); 33 | } 34 | 35 | stat_info stat_manager::get_stat_info(const std::string &pTblName, 36 | const layout &pLt, transaction *pTx) { 37 | std::unique_lock lock(mMutex); 38 | mNumCalls++; 39 | if (mNumCalls > 100) { 40 | refresh_statistics(pTx); 41 | } 42 | stat_info sI; 43 | if (mTableStats.find(pTblName) == mTableStats.end()) { 44 | sI = calc_table_stats(pTblName, pLt, pTx); 45 | mTableStats[pTblName] = sI; 46 | } else { 47 | sI = mTableStats[pTblName]; 48 | } 49 | return sI; 50 | } 51 | 52 | void stat_manager::refresh_statistics(transaction *pTx) { 53 | std::unique_lock lock(mMutex); 54 | mTableStats.clear(); 55 | mNumCalls = 0; 56 | layout tCatLayout = mTM->get_layout("tblcat", pTx); 57 | table_scan tCat(pTx, "tblcat", tCatLayout); 58 | while (tCat.next()) { 59 | std::string tblName = tCat.get_string("tblname"); 60 | layout lt = mTM->get_layout(tblName, pTx); 61 | stat_info sI = calc_table_stats(tblName, lt, pTx); 62 | mTableStats[tblName] = sI; 63 | } 64 | tCat.close(); 65 | } 66 | 67 | stat_info stat_manager::calc_table_stats(const std::string &pTblName, 68 | const layout &pLt, transaction *pTx) { 69 | int numRecs = 0; 70 | int numBlocks = 0; 71 | 72 | table_scan tS(pTx, pTblName, pLt); 73 | while (tS.next()) { 74 | numRecs++; 75 | numBlocks = tS.get_rid().block_number() + 1; 76 | } 77 | tS.close(); 78 | return stat_info(numBlocks, numRecs); 79 | } 80 | 81 | } // namespace simpledb 82 | -------------------------------------------------------------------------------- /test/indexjointest.cpp: -------------------------------------------------------------------------------- 1 | #include "index/planner/indexjoinplan.hpp" 2 | #include "metadata/indexmanager.hpp" 3 | #include "metadata/metadatamanager.hpp" 4 | #include "plan/plan.hpp" 5 | #include "plan/tableplan.hpp" 6 | #include "record/rid.hpp" 7 | #include "server/simpledb.hpp" 8 | #include "tx/transaction.hpp" 9 | #include "gtest/gtest.h" 10 | 11 | namespace simpledb { 12 | void use_index_manually(const std::shared_ptr &p1, 13 | const std::shared_ptr &p2, const index_info &iI, 14 | const std::string &joinField) { 15 | std::shared_ptr s1 = p1->open(); 16 | std::shared_ptr s2 = 17 | std::static_pointer_cast(p2->open()); 18 | std::shared_ptr idx = iI.open(); 19 | 20 | while (s1->next()) { 21 | constant c = s1->get_val(joinField); 22 | idx->before_first(c); 23 | while (idx->next()) { 24 | rid dataRID = idx->get_data_rid(); 25 | s2->move_to_rid(dataRID); 26 | std::cout << s2->get_string("grade") << std::endl; 27 | } 28 | } 29 | 30 | idx->close(); 31 | s1->close(); 32 | s2->close(); 33 | } 34 | 35 | void use_index_scan(const std::shared_ptr &p1, 36 | const std::shared_ptr &p2, const index_info &iI, 37 | const std::string &joinField) { 38 | std::shared_ptr idxPlan = std::static_pointer_cast( 39 | std::make_shared(p1, p2, iI, joinField)); 40 | std::shared_ptr s = idxPlan->open(); 41 | while (s->next()) { 42 | std::cout << s->get_string("grade") << std::endl; 43 | } 44 | s->close(); 45 | } 46 | 47 | TEST(index_query, indexjoin_test) { 48 | simpledb db("root:password@localhost"); 49 | metadata_manager &mM = db.md_mgr(); 50 | auto tx = db.new_tx(); 51 | 52 | // find the index on studentid 53 | std::map indexes = 54 | mM.get_index_info("enroll", tx.get()); 55 | index_info sIdIdx = indexes.at("studentid"); 56 | 57 | // get plans for the student and enroll tables 58 | std::shared_ptr studentPlan = std::static_pointer_cast( 59 | std::make_shared(tx.get(), "student", &mM)); 60 | std::shared_ptr enrollPlan = std::static_pointer_cast( 61 | std::make_shared(tx.get(), "enroll", &mM)); 62 | 63 | // two different ways to use the index in simpledb: 64 | use_index_manually(studentPlan, enrollPlan, sIdIdx, "sid"); 65 | use_index_scan(studentPlan, enrollPlan, sIdIdx, "sid"); 66 | 67 | tx->commit(); 68 | } 69 | } // namespace simpledb 70 | -------------------------------------------------------------------------------- /test/indexupdatetest.cpp: -------------------------------------------------------------------------------- 1 | #include "metadata/indexmanager.hpp" 2 | #include "metadata/metadatamanager.hpp" 3 | #include "plan/plan.hpp" 4 | #include "plan/tableplan.hpp" 5 | #include "record/rid.hpp" 6 | #include "server/simpledb.hpp" 7 | #include "tx/transaction.hpp" 8 | #include "gtest/gtest.h" 9 | 10 | namespace simpledb { 11 | TEST(index, indexupdate_test) { 12 | simpledb db("root:password@localhost"); 13 | auto tx = db.new_tx(); 14 | metadata_manager &mM = db.md_mgr(); 15 | std::shared_ptr studentPlan = std::static_pointer_cast( 16 | std::make_shared(tx.get(), "student", &mM)); 17 | std::shared_ptr studentScan = 18 | std::static_pointer_cast(studentPlan->open()); 19 | 20 | // create a map containing all indexes for STUDENT 21 | std::map> indexes; 22 | std::map idxInfo = 23 | mM.get_index_info("student", tx.get()); 24 | for (const auto &[fldName, iI] : idxInfo) { 25 | indexes[fldName] = idxInfo.at(fldName).open(); 26 | } 27 | 28 | // Task1: Insert a new STUDENT record for Sam. 29 | // First, insert the record into STUDENT 30 | studentScan->insert(); 31 | studentScan->set_int("sid", 1); 32 | studentScan->set_string("sname", "sam"); 33 | studentScan->set_int("gradyear", 2023); 34 | studentScan->set_int("majorid", 30); 35 | 36 | rid dataRID = studentScan->get_rid(); 37 | for (const auto &[fldName, idx] : indexes) { 38 | constant dataVal = studentScan->get_val(fldName); 39 | idx->insert(dataVal, dataRID); 40 | } 41 | 42 | // Task 2: Find and delete Joe's record 43 | studentScan->before_first(); 44 | while (studentScan->next()) { 45 | if (studentScan->get_string("sname") == "joe") { 46 | // First, delete the index records for Joe. 47 | rid joeRID = studentScan->get_rid(); 48 | for (const auto &[fldName, idx] : indexes) { 49 | constant dataVal = studentScan->get_val(fldName); 50 | idx->remove(dataVal, joeRID); 51 | } 52 | // Then delete Joe's record in student 53 | studentScan->remove(); 54 | break; 55 | } 56 | } 57 | 58 | // print the records to verify the updates 59 | studentScan->before_first(); 60 | while (studentScan->next()) { 61 | std::cout << studentScan->get_string("sname") << " " 62 | << studentScan->get_int("sid") << std::endl; 63 | } 64 | studentScan->close(); 65 | for (const auto &[fldName, idx] : indexes) { 66 | idx->close(); 67 | } 68 | tx->commit(); 69 | } 70 | } // namespace simpledb 71 | --------------------------------------------------------------------------------