|
| 1 | +//===----------------------------------------------------------------------===// |
| 2 | +// |
| 3 | +// Peloton |
| 4 | +// |
| 5 | +// plan_util_test.cpp |
| 6 | +// |
| 7 | +// Identification: test/planner/plan_util_test.cpp |
| 8 | +// |
| 9 | +// Copyright (c) 2015-18, Carnegie Mellon University Database Group |
| 10 | +// |
| 11 | +//===----------------------------------------------------------------------===// |
| 12 | + |
| 13 | +#include "common/harness.h" |
| 14 | + |
| 15 | +#include "catalog/catalog.h" |
| 16 | +#include "catalog/database_catalog.h" |
| 17 | +#include "catalog/index_catalog.h" |
| 18 | +#include "catalog/table_catalog.h" |
| 19 | +#include "common/statement.h" |
| 20 | +#include "concurrency/transaction_manager_factory.h" |
| 21 | +#include "executor/testing_executor_util.h" |
| 22 | +#include "parser/postgresparser.h" |
| 23 | +#include "storage/data_table.h" |
| 24 | + |
| 25 | +#include "planner/plan_util.h" |
| 26 | + |
| 27 | +namespace peloton { |
| 28 | +namespace test { |
| 29 | + |
| 30 | +#define TEST_DB_NAME "test_db" |
| 31 | + |
| 32 | +class PlanUtilTests : public PelotonTest {}; |
| 33 | + |
| 34 | +TEST_F(PlanUtilTests, GetAffectedIndexesTest) { |
| 35 | + auto catalog = catalog::Catalog::GetInstance(); |
| 36 | + catalog->Bootstrap(); |
| 37 | + |
| 38 | + auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); |
| 39 | + auto txn = txn_manager.BeginTransaction(); |
| 40 | + |
| 41 | + catalog->CreateDatabase(TEST_DB_NAME, txn); |
| 42 | + auto db = catalog->GetDatabaseWithName(TEST_DB_NAME, txn); |
| 43 | + // Insert a table first |
| 44 | + auto id_column = catalog::Column( |
| 45 | + type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), |
| 46 | + "id", true); |
| 47 | + auto fname_column = |
| 48 | + catalog::Column(type::TypeId::VARCHAR, 32, "first_name", false); |
| 49 | + auto lname_column = |
| 50 | + catalog::Column(type::TypeId::VARCHAR, 32, "last_name", false); |
| 51 | + |
| 52 | + std::unique_ptr<catalog::Schema> table_schema( |
| 53 | + new catalog::Schema({id_column, fname_column, lname_column})); |
| 54 | + txn_manager.CommitTransaction(txn); |
| 55 | + |
| 56 | + txn = txn_manager.BeginTransaction(); |
| 57 | + catalog->CreateTable(TEST_DB_NAME, "test_table", std::move(table_schema), |
| 58 | + txn); |
| 59 | + txn_manager.CommitTransaction(txn); |
| 60 | + |
| 61 | + txn = txn_manager.BeginTransaction(); |
| 62 | + auto source_table = db->GetTableWithName("test_table"); |
| 63 | + oid_t col_id = source_table->GetSchema()->GetColumnID(id_column.column_name); |
| 64 | + LOG_INFO("id: %d", static_cast<int>(col_id)); |
| 65 | + std::vector<oid_t> source_col_ids; |
| 66 | + source_col_ids.push_back(col_id); |
| 67 | + |
| 68 | + // create index on 'id' |
| 69 | + catalog->CreateIndex(TEST_DB_NAME, "test_table", source_col_ids, |
| 70 | + "test_id_idx", false, IndexType::BWTREE, txn); |
| 71 | + |
| 72 | + // create index on 'id' and 'first_name' |
| 73 | + col_id = source_table->GetSchema()->GetColumnID(fname_column.column_name); |
| 74 | + LOG_INFO("fname: %d", static_cast<int>(col_id)); |
| 75 | + source_col_ids.push_back(col_id); |
| 76 | + |
| 77 | + catalog->CreateIndex(TEST_DB_NAME, "test_table", source_col_ids, |
| 78 | + "test_fname_idx", false, IndexType::BWTREE, txn); |
| 79 | + txn_manager.CommitTransaction(txn); |
| 80 | + |
| 81 | + // dummy txn to get the catalog_cache object |
| 82 | + txn = txn_manager.BeginTransaction(); |
| 83 | + |
| 84 | + // This is also required so that database objects are cached |
| 85 | + auto db_object = catalog->GetDatabaseObject(TEST_DB_NAME, txn); |
| 86 | + EXPECT_EQ(static_cast<int>(db_object->GetTableObjects().size()), 1); |
| 87 | + |
| 88 | + // Till now, we have a table : id, first_name, last_name |
| 89 | + // And two indexes on following columns: |
| 90 | + // 1) id |
| 91 | + // 2) id and first_name |
| 92 | + auto table_object = db_object->GetTableObject("test_table"); |
| 93 | + oid_t id_idx_oid = table_object->GetIndexObject("test_id_idx")->GetIndexOid(); |
| 94 | + oid_t fname_idx_oid = |
| 95 | + table_object->GetIndexObject("test_fname_idx")->GetIndexOid(); |
| 96 | + |
| 97 | + // An update query affecting both indexes |
| 98 | + std::string query_string = "UPDATE test_table SET id = 0;"; |
| 99 | + std::unique_ptr<Statement> stmt = |
| 100 | + std::make_unique<Statement>("UPDATE", query_string); |
| 101 | + auto &peloton_parser = parser::PostgresParser::GetInstance(); |
| 102 | + auto sql_stmt_list = peloton_parser.BuildParseTree(query_string); |
| 103 | + auto sql_stmt = sql_stmt_list->GetStatement(0); |
| 104 | + static_cast<parser::UpdateStatement *>(sql_stmt)->TryBindDatabaseName( |
| 105 | + TEST_DB_NAME); |
| 106 | + std::set<oid_t> affected_indexes = |
| 107 | + planner::PlanUtil::GetAffectedIndexes(txn->catalog_cache, *sql_stmt); |
| 108 | + |
| 109 | + // id and first_name are affected |
| 110 | + EXPECT_EQ(static_cast<int>(affected_indexes.size()), 2); |
| 111 | + std::set<oid_t> expected_oids{id_idx_oid, fname_idx_oid}; |
| 112 | + EXPECT_EQ(expected_oids, affected_indexes); |
| 113 | + |
| 114 | + // Update query affecting only one index |
| 115 | + query_string = "UPDATE test_table SET first_name = '';"; |
| 116 | + stmt = std::make_unique<Statement>("UPDATE", query_string); |
| 117 | + sql_stmt_list = peloton_parser.BuildParseTree(query_string); |
| 118 | + sql_stmt = sql_stmt_list->GetStatement(0); |
| 119 | + static_cast<parser::UpdateStatement *>(sql_stmt)->TryBindDatabaseName( |
| 120 | + TEST_DB_NAME); |
| 121 | + affected_indexes = |
| 122 | + planner::PlanUtil::GetAffectedIndexes(txn->catalog_cache, *sql_stmt); |
| 123 | + |
| 124 | + // only first_name is affected |
| 125 | + EXPECT_EQ(static_cast<int>(affected_indexes.size()), 1); |
| 126 | + expected_oids = std::set<oid_t>({fname_idx_oid}); |
| 127 | + EXPECT_EQ(expected_oids, affected_indexes); |
| 128 | + |
| 129 | + // ====== DELETE statements check === |
| 130 | + query_string = "DELETE FROM test_table;"; |
| 131 | + stmt = std::make_unique<Statement>("DELETE", query_string); |
| 132 | + sql_stmt_list = peloton_parser.BuildParseTree(query_string); |
| 133 | + sql_stmt = sql_stmt_list->GetStatement(0); |
| 134 | + static_cast<parser::DeleteStatement *>(sql_stmt)->TryBindDatabaseName( |
| 135 | + TEST_DB_NAME); |
| 136 | + affected_indexes = |
| 137 | + planner::PlanUtil::GetAffectedIndexes(txn->catalog_cache, *sql_stmt); |
| 138 | + |
| 139 | + // all indexes are affected |
| 140 | + EXPECT_EQ(static_cast<int>(affected_indexes.size()), 2); |
| 141 | + expected_oids = std::set<oid_t>({id_idx_oid, fname_idx_oid}); |
| 142 | + EXPECT_EQ(expected_oids, affected_indexes); |
| 143 | + |
| 144 | + // ========= INSERT statements check == |
| 145 | + query_string = "INSERT INTO test_table VALUES (1, 'pel', 'ton');"; |
| 146 | + stmt = std::make_unique<Statement>("INSERT", query_string); |
| 147 | + sql_stmt_list = peloton_parser.BuildParseTree(query_string); |
| 148 | + sql_stmt = sql_stmt_list->GetStatement(0); |
| 149 | + static_cast<parser::InsertStatement *>(sql_stmt)->TryBindDatabaseName( |
| 150 | + TEST_DB_NAME); |
| 151 | + affected_indexes = |
| 152 | + planner::PlanUtil::GetAffectedIndexes(txn->catalog_cache, *sql_stmt); |
| 153 | + |
| 154 | + // all indexes are affected |
| 155 | + EXPECT_EQ(static_cast<int>(affected_indexes.size()), 2); |
| 156 | + expected_oids = std::set<oid_t>({id_idx_oid, fname_idx_oid}); |
| 157 | + EXPECT_EQ(expected_oids, affected_indexes); |
| 158 | +} |
| 159 | +} |
| 160 | +} |
0 commit comments