From 45f8069ac34ba1b4b07c7759ed822f44397f6f44 Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 21 Jul 2017 00:30:26 -0700 Subject: [PATCH] Add TRUNCATE TABLE syntax Recreate dictionary structure after truncate Add test --- Catalog/Catalog.cpp | 73 ++++++++++++++++++++++++++++++++++++++++ Catalog/Catalog.h | 2 ++ Parser/ParserNode.cpp | 11 ++++++ Parser/ParserNode.h | 14 ++++++++ Parser/ParserWrapper.cpp | 2 +- Parser/parser.y | 9 ++++- Parser/scanner.l | 1 + Tests/ExecuteTest.cpp | 12 +++++++ 8 files changed, 122 insertions(+), 2 deletions(-) diff --git a/Catalog/Catalog.cpp b/Catalog/Catalog.cpp index 7d85453eaf..36d682032f 100644 --- a/Catalog/Catalog.cpp +++ b/Catalog/Catalog.cpp @@ -1123,6 +1123,79 @@ void Catalog::createShardedTable(TableDescriptor& td, } } +void Catalog::truncateTable(const TableDescriptor* td) { + const auto physicalTableIt = logicalToPhysicalTableMapById_.find(td->tableId); + if (physicalTableIt != logicalToPhysicalTableMapById_.end()) { + // truncate all corresponding physical tables if this is a logical table + const auto physicalTables = physicalTableIt->second; + CHECK(!physicalTables.empty()); + for (size_t i = 0; i < physicalTables.size(); i++) { + int32_t physical_tb_id = physicalTables[i]; + const TableDescriptor* phys_td = getMetadataForTable(physical_tb_id); + CHECK(phys_td); + doTruncateTable(phys_td); + } + } + doTruncateTable(td); +} + +void Catalog::doTruncateTable(const TableDescriptor* td) { + const int tableId = td->tableId; + + // must destroy fragmenter before deleteChunks is called. + if (td->fragmenter != nullptr) { + auto tableDescIt = tableDescriptorMapById_.find(tableId); + delete td->fragmenter; + tableDescIt->second->fragmenter = nullptr; // get around const-ness + } + ChunkKey chunkKeyPrefix = {currentDB_.dbId, tableId}; + // assuming deleteChunksWithPrefix is atomic + dataMgr_->deleteChunksWithPrefix(chunkKeyPrefix); + // MAT TODO fix this + // NOTE This is unsafe , if there are updates occuring at same time + dataMgr_->checkpoint(currentDB_.dbId, tableId); + dataMgr_->removeTableRelatedDS(currentDB_.dbId, tableId); + + std::unique_ptr client; + if (g_aggregator) { + CHECK(!string_dict_hosts_.empty()); + client.reset(new StringDictionaryClient(string_dict_hosts_.front(), -1, true)); + } + // clean up any dictionaries + // delete all column descriptors for the table + for (int i = 1; i <= td->nColumns; i++) { + ColumnIdKey cidKey(tableId, i); + ColumnDescriptorMapById::iterator colDescIt = columnDescriptorMapById_.find(cidKey); + ColumnDescriptor* cd = colDescIt->second; + const int dictId = cd->columnType.get_comp_param(); + // Dummy dictionaries created for a shard of a logical table have the id set to zero. + if (cd->columnType.get_compression() == kENCODING_DICT && dictId) { + const auto dictIt = dictDescriptorMapById_.find(dictId); + CHECK(dictIt != dictDescriptorMapById_.end()); + const auto& dd = dictIt->second; + CHECK_GE(dd->refcount, 1); + // if this is the only table using this dict reset the dict + if (dd->refcount == 1) { + boost::filesystem::remove_all(dd->dictFolderPath); + if (client) { + client->drop(dd->dictId, currentDB_.dbId); + } + boost::filesystem::create_directory(dd->dictFolderPath); + } + + DictDescriptor* new_dd = new DictDescriptor( + dd->dictId, dd->dictName, dd->dictNBits, dd->dictIsShared, dd->refcount, dd->dictFolderPath); + dictDescriptorMapById_.erase(dictIt); + // now create new Dict -- need to figure out what to do here for temp tables + if (client) { + client->create(new_dd->dictId, currentDB_.dbId); + } + dictDescriptorMapById_[dictId].reset(new_dd); + getMetadataForDict(dictId); + } + } +} + void Catalog::dropTable(const TableDescriptor* td) { const auto physicalTableIt = logicalToPhysicalTableMapById_.find(td->tableId); if (physicalTableIt != logicalToPhysicalTableMapById_.end()) { diff --git a/Catalog/Catalog.h b/Catalog/Catalog.h index 0c2947942f..2541270f60 100644 --- a/Catalog/Catalog.h +++ b/Catalog/Catalog.h @@ -212,6 +212,7 @@ class Catalog { void createFrontendView(FrontendViewDescriptor& vd); std::string createLink(LinkDescriptor& ld, size_t min_length); void dropTable(const TableDescriptor* td); + void truncateTable(const TableDescriptor* td); void renameTable(const TableDescriptor* td, const std::string& newTableName); void renameColumn(const TableDescriptor* td, const ColumnDescriptor* cd, const std::string& newColumnName); @@ -288,6 +289,7 @@ class Catalog { void addLinkToMap(LinkDescriptor& ld); void removeTableFromMap(const std::string& tableName, int tableId); void doDropTable(const TableDescriptor* td); + void doTruncateTable(const TableDescriptor* td); void renamePhysicalTable(const TableDescriptor* td, const std::string& newTableName); void instantiateFragmenter(TableDescriptor* td) const; void getAllColumnMetadataForTable(const TableDescriptor* td, diff --git a/Parser/ParserNode.cpp b/Parser/ParserNode.cpp index c79bc6e194..37604a1142 100644 --- a/Parser/ParserNode.cpp +++ b/Parser/ParserNode.cpp @@ -2110,6 +2110,17 @@ void DropTableStmt::execute(const Catalog_Namespace::SessionInfo& session) { catalog.dropTable(td); } +void TruncateTableStmt::execute(const Catalog_Namespace::SessionInfo& session) { + auto& catalog = session.get_catalog(); + const TableDescriptor* td = catalog.getMetadataForTable(*table); + if (td == nullptr) { + throw std::runtime_error("Table " + *table + " does not exist."); + } + if (td->isView) + throw std::runtime_error(*table + " is a view. Cannot Truncate."); + catalog.truncateTable(td); +} + void RenameTableStmt::execute(const Catalog_Namespace::SessionInfo& session) { auto& catalog = session.get_catalog(); const TableDescriptor* td = catalog.getMetadataForTable(*table); diff --git a/Parser/ParserNode.h b/Parser/ParserNode.h index 2f5db043c0..ab93d9effa 100644 --- a/Parser/ParserNode.h +++ b/Parser/ParserNode.h @@ -938,6 +938,20 @@ class DropTableStmt : public DDLStmt { bool if_exists; }; +/* + * @type TruncateTableStmt + * @brief TRUNCATE TABLE statement + */ +class TruncateTableStmt : public DDLStmt { + public: + TruncateTableStmt(std::string* tab) : table(tab) {} + const std::string* get_table() const { return table.get(); } + virtual void execute(const Catalog_Namespace::SessionInfo& session); + + private: + std::unique_ptr table; +}; + class RenameTableStmt : public DDLStmt { public: RenameTableStmt(std::string* tab, std::string* new_tab_name) : table(tab), new_table_name(new_tab_name) {} diff --git a/Parser/ParserWrapper.cpp b/Parser/ParserWrapper.cpp index 3a2b54c61e..dbd30fe9be 100644 --- a/Parser/ParserWrapper.cpp +++ b/Parser/ParserWrapper.cpp @@ -30,7 +30,7 @@ using namespace std; -const std::vector ParserWrapper::ddl_cmd = {"ALTER", "COPY", "GRANT", "CREATE", "DROP"}; +const std::vector ParserWrapper::ddl_cmd = {"ALTER", "COPY", "GRANT", "CREATE", "DROP", "TRUNCATE"}; const std::vector ParserWrapper::update_dml_cmd = { "INSERT", diff --git a/Parser/parser.y b/Parser/parser.y index d852e679c1..6d1e0507b4 100644 --- a/Parser/parser.y +++ b/Parser/parser.y @@ -104,7 +104,7 @@ using namespace Parser; %token IS LANGUAGE LAST LENGTH LIKE LIMIT MOD NOW NULLX NUMERIC OF OFFSET ON OPEN OPTION %token ORDER PARAMETER PRECISION PRIMARY PRIVILEGES PROCEDURE %token PUBLIC REAL REFERENCES RENAME ROLLBACK SCHEMA SELECT SET SHARD SHARED SHOW -%token SMALLINT SOME TABLE TEXT THEN TIME TIMESTAMP TO UNION +%token SMALLINT SOME TABLE TEXT THEN TIME TIMESTAMP TO TRUNCATE UNION %token UNIQUE UPDATE USER VALUES VIEW WHEN WHENEVER WHERE WITH WORK %start sql_list @@ -127,6 +127,7 @@ sql: /* schema { $$ = $1; } */ /* | prvililege_def { $$ = $1; } */ | drop_view_statement { $$ = $1; } | drop_table_statement { $$ = $1; } + | truncate_table_statement { $$ = $1; } | rename_table_statement { $$ = $1; } | rename_column_statement { $$ = $1; } | copy_table_statement { $$ = $1; } @@ -238,6 +239,12 @@ drop_table_statement: $$ = new DropTableStmt($4, $3); } ; +truncate_table_statement: + TRUNCATE TABLE table + { + $$ = new TruncateTableStmt($3); + } + ; rename_table_statement: ALTER TABLE table RENAME TO table { diff --git a/Parser/scanner.l b/Parser/scanner.l index 0779930361..3b27701444 100644 --- a/Parser/scanner.l +++ b/Parser/scanner.l @@ -121,6 +121,7 @@ THEN TOK(THEN) TIME TOK(TIME) TIMESTAMP TOK(TIMESTAMP) TO TOK(TO) +TRUNCATE TOK(TRUNCATE) UNION TOK(UNION) UNIQUE TOK(UNIQUE) UPDATE TOK(UPDATE) diff --git a/Tests/ExecuteTest.cpp b/Tests/ExecuteTest.cpp index 43409354a6..5370ec758e 100644 --- a/Tests/ExecuteTest.cpp +++ b/Tests/ExecuteTest.cpp @@ -3323,6 +3323,18 @@ TEST(Select, WatchdogTest) { } } +TEST(Truncate, Count) { + run_ddl_statement("create table trunc_test (i1 integer, t1 text);"); + run_multiple_agg("insert into trunc_test values(1, '1');", ExecutorDeviceType::CPU); + run_multiple_agg("insert into trunc_test values(2, '2');", ExecutorDeviceType::CPU); + ASSERT_EQ(int64_t(3), v(run_simple_agg("SELECT SUM(i1) FROM trunc_test;", ExecutorDeviceType::CPU))); + run_ddl_statement("truncate table trunc_test;"); + run_multiple_agg("insert into trunc_test values(3, '3');", ExecutorDeviceType::CPU); + run_multiple_agg("insert into trunc_test values(4, '4');", ExecutorDeviceType::CPU); + ASSERT_EQ(int64_t(7), v(run_simple_agg("SELECT SUM(i1) FROM trunc_test;", ExecutorDeviceType::CPU))); + run_ddl_statement("drop table trunc_test;"); +} + namespace { struct ShardInfo {