From 898219f9fe6e1d2b6901ea3797caac5c93850213 Mon Sep 17 00:00:00 2001 From: Kazuhiro Saito <32720872+ksaito7@users.noreply.github.com> Date: Tue, 3 Jul 2018 13:29:59 -0400 Subject: [PATCH] Constraint refactoring (#1415) * Add pg_constraint catalog table * Reconstruct constraints --- src/catalog/abstract_catalog.cpp | 31 +- src/catalog/catalog.cpp | 707 +++++++++++++--- src/catalog/column.cpp | 26 +- src/catalog/column_catalog.cpp | 218 +++-- src/catalog/constraint.cpp | 33 +- src/catalog/constraint_catalog.cpp | 428 ++++++++++ src/catalog/database_catalog.cpp | 22 +- src/catalog/index_catalog.cpp | 49 +- src/catalog/layout_catalog.cpp | 28 +- src/catalog/manager.cpp | 1 - src/catalog/multi_constraint.cpp | 39 - src/catalog/schema.cpp | 24 +- src/catalog/schema_catalog.cpp | 26 +- src/catalog/system_catalogs.cpp | 26 +- src/catalog/table_catalog.cpp | 129 ++- src/common/internal_types.cpp | 88 +- src/executor/create_executor.cpp | 201 +++-- src/executor/update_executor.cpp | 3 +- src/include/catalog/catalog.h | 83 +- src/include/catalog/catalog_defaults.h | 36 +- src/include/catalog/column.h | 72 +- src/include/catalog/column_catalog.h | 31 +- src/include/catalog/constraint.h | 115 ++- src/include/catalog/constraint_catalog.h | 156 ++++ src/include/catalog/foreign_key.h | 76 -- src/include/catalog/layout_catalog.h | 3 +- src/include/catalog/multi_constraint.h | 70 -- src/include/catalog/schema.h | 176 +++- src/include/catalog/system_catalogs.h | 10 + src/include/catalog/table_catalog.h | 40 +- src/include/common/internal_types.h | 27 +- src/include/planner/create_plan.h | 40 +- src/include/storage/abstract_table.h | 10 - src/include/storage/data_table.h | 57 +- src/include/storage/temp_table.h | 6 - .../stats/column_stats_collector.cpp | 9 +- src/optimizer/stats/stats_storage.cpp | 2 +- src/planner/create_plan.cpp | 145 ++-- src/planner/update_plan.cpp | 12 +- src/storage/data_table.cpp | 248 ++---- src/storage/database.cpp | 11 +- test/brain/query_logger_test.cpp | 6 +- test/catalog/catalog_test.cpp | 413 +++++++++- test/catalog/constraints_test.cpp | 773 +++++++++--------- test/codegen/testing_codegen_util.cpp | 33 +- test/common/internal_types_test.cpp | 8 +- test/concurrency/testing_transaction_util.cpp | 43 +- test/executor/drop_test.cpp | 2 +- test/executor/testing_executor_util.cpp | 21 +- test/executor/update_test.cpp | 27 +- test/gc/garbage_collection_test.cpp | 13 +- test/gc/transaction_level_gc_manager_test.cpp | 18 +- .../catalog/testing_constraints_util.h | 55 +- test/include/codegen/testing_codegen_util.h | 3 +- .../concurrency/testing_transaction_util.h | 2 +- test/optimizer/stats_storage_test.cpp | 2 +- test/planner/plan_util_test.cpp | 16 +- test/planner/planner_test.cpp | 6 +- test/sql/optimizer_sql_test.cpp | 2 +- test/statistics/stats_test.cpp | 15 +- test/statistics/testing_stats_util.cpp | 34 +- 61 files changed, 3415 insertions(+), 1591 deletions(-) create mode 100644 src/catalog/constraint_catalog.cpp delete mode 100644 src/catalog/multi_constraint.cpp create mode 100644 src/include/catalog/constraint_catalog.h delete mode 100644 src/include/catalog/foreign_key.h delete mode 100644 src/include/catalog/multi_constraint.h diff --git a/src/catalog/abstract_catalog.cpp b/src/catalog/abstract_catalog.cpp index 5ce2bceaedc..4ddad1c61ca 100644 --- a/src/catalog/abstract_catalog.cpp +++ b/src/catalog/abstract_catalog.cpp @@ -29,6 +29,7 @@ #include "planner/seq_scan_plan.h" #include "executor/executor_context.h" +#include "executor/create_executor.h" #include "executor/delete_executor.h" #include "executor/index_scan_executor.h" #include "executor/insert_executor.h" @@ -60,30 +61,24 @@ AbstractCatalog::AbstractCatalog(storage::Database *pg_catalog, AbstractCatalog::AbstractCatalog(concurrency::TransactionContext *txn, const std::string &catalog_table_ddl) { - // get catalog table schema + // Execute create catalog table auto &peloton_parser = parser::PostgresParser::GetInstance(); + std::unique_ptr context( + new executor::ExecutorContext(txn)); auto create_plan = std::dynamic_pointer_cast( optimizer::Optimizer().BuildPelotonPlanTree( peloton_parser.BuildParseTree(catalog_table_ddl), txn)); - auto catalog_table_schema = create_plan->GetSchema(); - auto catalog_table_name = create_plan->GetTableName(); - auto catalog_schema_name = create_plan->GetSchemaName(); - auto catalog_database_name = create_plan->GetDatabaseName(); - PELOTON_ASSERT(catalog_schema_name == std::string(CATALOG_SCHEMA_NAME)); - // create catalog table - Catalog::GetInstance()->CreateTable(txn, - catalog_database_name, - catalog_schema_name, - std::unique_ptr( - catalog_table_schema), - catalog_table_name, - true); + executor::CreateExecutor executor(create_plan.get(), context.get()); + + executor.Init(); + executor.Execute(); // get catalog table oid - auto catalog_table_object = Catalog::GetInstance()->GetTableCatalogEntry(txn, - catalog_database_name, - catalog_schema_name, - catalog_table_name); + auto catalog_table_object = + Catalog::GetInstance()->GetTableCatalogEntry(txn, + create_plan->GetDatabaseName(), + create_plan->GetSchemaName(), + create_plan->GetTableName()); // set catalog_table_ try { diff --git a/src/catalog/catalog.cpp b/src/catalog/catalog.cpp index b3dcd815ac3..99f58aeb53a 100644 --- a/src/catalog/catalog.cpp +++ b/src/catalog/catalog.cpp @@ -13,6 +13,7 @@ #include "catalog/catalog.h" #include "catalog/column_catalog.h" +#include "catalog/constraint_catalog.h" #include "catalog/database_catalog.h" #include "catalog/database_metrics_catalog.h" #include "catalog/index_catalog.h" @@ -232,6 +233,49 @@ void Catalog::BootstrapSystemCatalogs(concurrency::TransactionContext *txn, {TableCatalog::ColumnId::DATABASE_OID}, pool_.get()); + system_catalogs->GetIndexCatalog()->InsertIndex(txn, + CATALOG_SCHEMA_NAME, + LAYOUT_CATALOG_OID, + LAYOUT_CATALOG_PKEY_OID, + LAYOUT_CATALOG_NAME "_pkey", + IndexType::BWTREE, + IndexConstraintType::PRIMARY_KEY, + true, + {LayoutCatalog::ColumnId::TABLE_OID, + LayoutCatalog::ColumnId::LAYOUT_OID}, + pool_.get()); + system_catalogs->GetIndexCatalog()->InsertIndex(txn, + CATALOG_SCHEMA_NAME, + LAYOUT_CATALOG_OID, + LAYOUT_CATALOG_SKEY0_OID, + LAYOUT_CATALOG_NAME "_skey0", + IndexType::BWTREE, + IndexConstraintType::DEFAULT, + true, + {LayoutCatalog::ColumnId::TABLE_OID}, + pool_.get()); + + system_catalogs->GetIndexCatalog()->InsertIndex(txn, + CATALOG_SCHEMA_NAME, + CONSTRAINT_CATALOG_OID, + CONSTRAINT_CATALOG_PKEY_OID, + CONSTRAINT_CATALOG_NAME "_pkey", + IndexType::BWTREE, + IndexConstraintType::PRIMARY_KEY, + true, + {ConstraintCatalog::ColumnId::CONSTRAINT_OID}, + pool_.get()); + system_catalogs->GetIndexCatalog()->InsertIndex(txn, + CATALOG_SCHEMA_NAME, + CONSTRAINT_CATALOG_OID, + CONSTRAINT_CATALOG_SKEY0_OID, + CONSTRAINT_CATALOG_NAME "_skey0", + IndexType::BWTREE, + IndexConstraintType::DEFAULT, + true, + {ConstraintCatalog::ColumnId::TABLE_OID}, + pool_.get()); + // Insert records(default + pg_catalog namespace) into pg_namespace system_catalogs->GetSchemaCatalog()->InsertSchema(txn, CATALOG_SCHEMA_OID, @@ -286,6 +330,13 @@ void Catalog::BootstrapSystemCatalogs(concurrency::TransactionContext *txn, LAYOUT_CATALOG_NAME, ROW_STORE_LAYOUT_OID, pool_.get()); + system_catalogs->GetTableCatalog()->InsertTable(txn, + database_oid, + CATALOG_SCHEMA_NAME, + CONSTRAINT_CATALOG_OID, + CONSTRAINT_CATALOG_NAME, + ROW_STORE_LAYOUT_OID, + pool_.get()); } void Catalog::Bootstrap() { @@ -403,11 +454,13 @@ ResultType Catalog::CreateSchema(concurrency::TransactionContext *txn, } /*@brief create table + * @param txn TransactionContext * @param database_name the database which the table belongs to * @param schema_name name of schema the table belongs to - * @param table_name name of the table * @param schema schema, a.k.a metadata of the table - * @param txn TransactionContext + * @param table_name name of the table + * @param is_catalog table is built as catalog or not(useful in + * catalog table Initialization) * @return TransactionContext ResultType(SUCCESS or FAILURE) */ ResultType Catalog::CreateTable(concurrency::TransactionContext *txn, @@ -488,40 +541,24 @@ ResultType Catalog::CreateTable(concurrency::TransactionContext *txn, table_name, table->GetDefaultLayout()->GetOid(), pool_.get()); + + // Insert column info into each catalog oid_t column_id = 0; for (const auto &column : table->GetSchema()->GetColumns()) { pg_attribute->InsertColumn(txn, table_oid, - column_id, column.GetName(), + column_id, column.GetOffset(), column.GetType(), column.GetLength(), - column.GetConstraints(), column.IsInlined(), + column.IsNotNull(), + column.HasDefault(), + column.GetDefaultValue(), pool_.get()); - - // Create index on unique single column - if (column.IsUnique()) { - std::string col_name = column.GetName(); - std::string index_name = table->GetName() + "_" + col_name + "_UNIQ"; - CreateIndex(txn, - database_name, - schema_name, - table_name, - index_name, - {column_id}, - true, - IndexType::BWTREE); - LOG_DEBUG("Added a UNIQUE index on %s in %s.", col_name.c_str(), - table_name.c_str()); - } column_id++; } - CreatePrimaryIndex(txn, - database_object->GetDatabaseOid(), - schema_name, - table_oid); // Create layout as default layout auto pg_layout = @@ -534,93 +571,15 @@ ResultType Catalog::CreateTable(concurrency::TransactionContext *txn, return ResultType::SUCCESS; } -/*@brief create primary index on table - * Note that this is a catalog helper function only called within catalog.cpp - * If you want to create index on table outside, call CreateIndex() instead - * @param database_oid the database which the indexed table belongs to - * @param table_oid oid of the table to add index on - * @param schema_name the schema which the indexed table belongs to - * @param txn TransactionContext - * @return TransactionContext ResultType(SUCCESS or FAILURE) - */ -ResultType Catalog::CreatePrimaryIndex(concurrency::TransactionContext *txn, - oid_t database_oid, - const std::string &schema_name, - oid_t table_oid) { - LOG_TRACE("Trying to create primary index for table %d", table_oid); - - auto storage_manager = storage::StorageManager::GetInstance(); - - auto database = storage_manager->GetDatabaseWithOid(database_oid); - - auto table = database->GetTableWithOid(table_oid); - - std::vector key_attrs; - catalog::Schema *key_schema = nullptr; - index::IndexMetadata *index_metadata = nullptr; - auto schema = table->GetSchema(); - - // Find primary index attributes - int column_idx = 0; - auto &schema_columns = schema->GetColumns(); - for (auto &column : schema_columns) { - if (column.IsPrimary()) { - key_attrs.push_back(column_idx); - } - column_idx++; - } - - if (key_attrs.empty()) return ResultType::FAILURE; - - key_schema = catalog::Schema::CopySchema(schema, key_attrs); - key_schema->SetIndexedColumns(key_attrs); - - std::string index_name = table->GetName() + "_pkey"; - - bool unique_keys = true; - auto pg_index = catalog_map_[database_oid]->GetIndexCatalog(); - oid_t index_oid = pg_index->GetNextOid(); - - index_metadata = new index::IndexMetadata( - index_name, index_oid, table_oid, database_oid, IndexType::BWTREE, - IndexConstraintType::PRIMARY_KEY, schema, key_schema, key_attrs, - unique_keys); - - std::shared_ptr pkey_index( - index::IndexFactory::GetIndex(index_metadata)); - table->AddIndex(pkey_index); - - // put index object into rw_object_set - txn->RecordCreate(database_oid, table_oid, index_oid); - // insert index record into index_catalog(pg_index) table - pg_index->InsertIndex(txn, - schema_name, - table_oid, - index_oid, - index_name, - IndexType::BWTREE, - IndexConstraintType::PRIMARY_KEY, - unique_keys, - key_attrs, - pool_.get()); - - LOG_TRACE("Successfully created primary key index '%s' for table '%s'", - index_name.c_str(), table->GetName().c_str()); - - return ResultType::SUCCESS; -} - /*@brief create index on table + * @param txn TransactionContext * @param database_name the database which the indexed table belongs to * @param schema_name the namespace which the indexed table belongs to * @param table_name name of the table to add index on - * @param index_attr collection of the indexed attribute(column) name * @param index_name name of the table to add index on + * @param key_attrs collection of the indexed attribute(column) name * @param unique_keys index supports duplicate key or not * @param index_type the type of index(default value is BWTREE) - * @param txn TransactionContext - * @param is_catalog index is built on catalog table or not(useful in - * catalog table Initialization) * @return TransactionContext ResultType(SUCCESS or FAILURE) */ ResultType Catalog::CreateIndex(concurrency::TransactionContext *txn, @@ -655,6 +614,9 @@ ResultType Catalog::CreateIndex(concurrency::TransactionContext *txn, throw CatalogException("Can't find table " + schema_name + "." + table_name + " to create index"); + auto pg_index = + catalog_map_[database_object->GetDatabaseOid()]->GetIndexCatalog(); + oid_t index_oid = pg_index->GetNextOid(); IndexConstraintType index_constraint = unique_keys ? IndexConstraintType::UNIQUE : IndexConstraintType::DEFAULT; @@ -663,6 +625,7 @@ ResultType Catalog::CreateIndex(concurrency::TransactionContext *txn, schema_name, table_object->GetTableOid(), false, + index_oid, index_name, key_attrs, unique_keys, @@ -672,11 +635,27 @@ ResultType Catalog::CreateIndex(concurrency::TransactionContext *txn, return success; } +/*@brief create index on table + * @param txn TransactionContext + * @param database_oid the database which the indexed table belongs to + * @param schema_name the namespace which the indexed table belongs to + * @param table_oid name of the table to add index on + * @param is_catalog index is built on catalog table or not(useful in + * catalog table Initialization) + * @param index_oid oid of the index to be added + * @param index_name index name to be added + * @param key_attrs collection of the indexed attribute(column) name + * @param unique_keys index supports duplicate key or not + * @param index_type the type of index + * @param index_constraint the constraint type of index + * @return TransactionContext ResultType(SUCCESS or FAILURE) + */ ResultType Catalog::CreateIndex(concurrency::TransactionContext *txn, oid_t database_oid, const std::string &schema_name, oid_t table_oid, bool is_catalog, + oid_t index_oid, const std::string &index_name, const std::vector &key_attrs, bool unique_keys, @@ -711,8 +690,6 @@ ResultType Catalog::CreateIndex(concurrency::TransactionContext *txn, // Passed all checks, now get all index metadata LOG_TRACE("Trying to create index %s on table %d", index_name.c_str(), table_oid); - auto pg_index = catalog_map_[database_oid]->GetIndexCatalog(); - oid_t index_oid = pg_index->GetNextOid(); auto key_schema = catalog::Schema::CopySchema(schema, key_attrs); key_schema->SetIndexedColumns(key_attrs); @@ -729,6 +706,7 @@ ResultType Catalog::CreateIndex(concurrency::TransactionContext *txn, // Put index object into rw_object_set txn->RecordCreate(database_oid, table_oid, index_oid); // Insert index record into pg_index + auto pg_index = catalog_map_[database_oid]->GetIndexCatalog(); pg_index->InsertIndex(txn, schema_name, table_oid, @@ -789,6 +767,371 @@ std::shared_ptr Catalog::CreateDefaultLayout(concurrency: return new_layout; } +//===--------------------------------------------------------------------===// +// SET FUNCTIONS FOR COLUMN CONSTRAINT +//===--------------------------------------------------------------------===// + +/** + * @brief Set not null constraint for a column + * @param txn TransactionContext + * @param database_oid Database to which the table belongs to + * @param table_oid Table to which the constraint has to be set + * @param column_id Column that the constraint affects + * @return ResultType(SUCCESS or FAILURE) + */ +ResultType Catalog::SetNotNullConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, + oid_t table_oid, + oid_t column_id) { + auto table_object = catalog_map_[database_oid] + ->GetTableCatalog() + ->GetTableCatalogEntry(txn, table_oid); + auto schema = storage::StorageManager::GetInstance() + ->GetTableWithOid(database_oid, table_oid) + ->GetSchema(); + auto column = schema->GetColumn(column_id); + + // Check not null + if (column.IsNotNull()) { + throw CatalogException("Column " + column.GetName() + " in table " + + table_object->GetTableName() + + " is already NOT NULL."); + } + + // Update pg_column to set constraint of the column + auto pg_column = catalog_map_[database_oid]->GetColumnCatalog(); + pg_column->UpdateNotNullConstraint(txn, + table_oid, + column.GetName(), + true); + + // Set not null constraint in the schema + { + std::lock_guard lock(catalog_mutex); + schema->SetNotNull(column_id); + } + + LOG_TRACE("Added a NOT NULL constraint to column %s in %s.", + column.GetName().c_str(), table_object->GetTableName().c_str()); + + return ResultType::SUCCESS; +} + +/** + * @brief Set default constraint for a column + * @param txn TransactionContext + * @param database_oid Database to which the table belongs to + * @param table_oid Table to which the constraint has to be set + * @param column_id Column that the constraint affects + * @param default_value Value for the default constraint + * @return ResultType(SUCCESS or FAILURE) + */ +ResultType Catalog::SetDefaultConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, + oid_t table_oid, + oid_t column_id, + const type::Value &default_value) { + auto table_object = catalog_map_[database_oid]->GetTableCatalog() + ->GetTableCatalogEntry(txn, table_oid); + auto schema = storage::StorageManager::GetInstance() + ->GetTableWithOid(database_oid, table_oid) + ->GetSchema(); + auto column = schema->GetColumn(column_id); + + // Check default + if (column.HasDefault()) { + throw CatalogException("Column " + column.GetName() + " in table" + + table_object->GetTableName() + + " is already set default value '" + + column.GetDefaultValue()->ToString() + "'."); + } + + // Update pg_column to set constraint of the column + auto pg_column = catalog_map_[database_oid]->GetColumnCatalog(); + pg_column->UpdateDefaultConstraint(txn, + table_oid, + column.GetName(), + true, + &default_value); + + // Set default constraint in the schema + { + std::lock_guard lock(catalog_mutex); + schema->SetDefaultValue(column_id, default_value); + } + + LOG_TRACE("Added a DEFAULT constraint to column %s in %s.", + column.GetName().c_str(), table_object->GetTableName().c_str()); + + return ResultType::SUCCESS; +} + +//===--------------------------------------------------------------------===// +// ADD FUNCTIONS FOR TABLE CONSTRAINT +//===--------------------------------------------------------------------===// + +/** + * @brief Add a new primary constraint for a table + * @param txn TransactionContext + * @param database_oid Database to which the table belongs to + * @param table_oid Table to which the constraint has to be added + * @param column_ids Columns that the constraint affects + * @param constraint_name constraint name + * @return ResultType(SUCCESS or FAILURE) + */ +ResultType Catalog::AddPrimaryKeyConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, + oid_t table_oid, + const std::vector &column_ids, + const std::string &constraint_name) { + auto table_object = + catalog_map_[database_oid]->GetTableCatalog() + ->GetTableCatalogEntry(txn,table_oid); + auto schema = storage::StorageManager::GetInstance() + ->GetTableWithOid(database_oid, table_oid) + ->GetSchema(); + + // Check primary key in the table + if (schema->HasPrimary()) { + throw CatalogException("Table " + table_object->GetTableName() + + " already has primary key."); + } + + // Create index + std::string index_name = table_object->GetTableName() + "_pkey"; + auto index_oid = catalog_map_[database_oid]->GetIndexCatalog()->GetNextOid(); + CreateIndex(txn, + database_oid, + table_object->GetSchemaName(), + table_oid, + false, + index_oid, + index_name, + column_ids, + true, + IndexType::BWTREE, + IndexConstraintType::PRIMARY_KEY); + + // Insert constraint into pg_constraint + auto pg_constraint = catalog_map_[database_oid]->GetConstraintCatalog(); + std::shared_ptr constraint( + new Constraint(pg_constraint->GetNextOid(), + ConstraintType::PRIMARY, + constraint_name, + table_oid, + column_ids, + index_oid)); + pg_constraint->InsertConstraint(txn, constraint, pool_.get()); + + // Add constraint into the schema + { + std::lock_guard lock(catalog_mutex); + schema->AddConstraint(constraint); + } + + LOG_TRACE("Added a PRIMARY KEY constraint in %s.", + table_object->GetTableName().c_str()); + + return ResultType::SUCCESS; +} + +/** + * @brief Add a new unique constraint for a table + * @param txn TransactionContext + * @param database_oid Database to which the table belongs to + * @param table_oid Table to which the constraint has to be added + * @param column_ids Columns that the constraint affects + * @param constraint_name constraint name + * @return ResultType(SUCCESS or FAILURE) + * note: if add a new foreign key constraint, use AddForeignKeyConstraint + */ +ResultType Catalog::AddUniqueConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, + oid_t table_oid, + const std::vector &column_ids, + const std::string &constraint_name) { + auto table_object = + catalog_map_[database_oid]->GetTableCatalog() + ->GetTableCatalogEntry(txn, table_oid); + auto schema = storage::StorageManager::GetInstance() + ->GetTableWithOid(database_oid, table_oid) + ->GetSchema(); + + // Create index + std::stringstream index_name(table_object->GetTableName()); + for (auto column_id : column_ids) + index_name << "_" + schema->GetColumn(column_id).GetName(); + index_name << "_UNIQ"; + auto index_oid = catalog_map_[database_oid]->GetIndexCatalog()->GetNextOid(); + CreateIndex(txn, + database_oid, + table_object->GetSchemaName(), + table_oid, + false, + index_oid, + index_name.str(), + column_ids, + true, + IndexType::BWTREE, + IndexConstraintType::UNIQUE); + + // Insert constraint into pg_constraint + auto pg_constraint = catalog_map_[database_oid]->GetConstraintCatalog(); + std::shared_ptr constraint( + new Constraint(pg_constraint->GetNextOid(), + ConstraintType::UNIQUE, + constraint_name, + table_oid, + column_ids, + index_oid)); + pg_constraint->InsertConstraint(txn, constraint, pool_.get()); + + // Add constraint into the schema + { + std::lock_guard lock(catalog_mutex); + schema->AddConstraint(constraint); + } + + LOG_TRACE("Added a UNIQUE constraint in %s.", + table_object->GetTableName().c_str()); + + return ResultType::SUCCESS; +} + +/** + * @brief Add a new foreign key constraint for a table + * @param txn TransactionContext + * @param database_oid database to which the table belongs to + * @param src_table_oid table to which the constraint has to be added + * @param src_col_ids Columns that the constraint affects + * @param sink_table_oid sink table + * @param sink_col_ids Columns that limit the source columns + * @param upd_action foreign key constraint action when update + * @param del_action foreign key constraint action when delete + * @param constraint_name constraint name + * @return ResultType(SUCCESS or FAILURE) + */ +ResultType Catalog::AddForeignKeyConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, oid_t src_table_oid, + const std::vector &src_col_ids, + oid_t sink_table_oid, + const std::vector &sink_col_ids, + FKConstrActionType upd_action, + FKConstrActionType del_action, + const std::string &constraint_name) { + auto pg_constraint = catalog_map_[database_oid]->GetConstraintCatalog(); + auto constraint_oid = pg_constraint->GetNextOid(); + auto storage_manager = storage::StorageManager::GetInstance(); + auto src_table = + storage_manager->GetTableWithOid(database_oid, src_table_oid); + auto sink_table = + storage_manager->GetTableWithOid(database_oid, sink_table_oid); + + // Add a non-unique index on the source table if needed + auto src_table_object = + catalog_map_[database_oid]->GetTableCatalog() + ->GetTableCatalogEntry(txn, src_table_oid); + auto src_schema = src_table->GetSchema(); + + std::stringstream index_name(src_table_object->GetTableName()); + for (auto col_id : src_col_ids) + index_name << "_" << src_schema->GetColumn(col_id).GetName(); + index_name << "_fkey"; + oid_t index_oid = catalog_map_[database_oid]->GetIndexCatalog()->GetNextOid(); + CreateIndex(txn, + database_oid, + src_table_object->GetSchemaName(), + src_table_oid, + false, + index_oid, + index_name.str(), + src_col_ids, + false, + IndexType::BWTREE, + IndexConstraintType::DEFAULT); + + // Insert constraint into pg_constraint + std::shared_ptr constraint( + new Constraint(constraint_oid, + ConstraintType::FOREIGN, + constraint_name, + src_table_oid, + src_col_ids, + index_oid, + sink_table_oid, + sink_col_ids, + upd_action, + del_action)); + pg_constraint->InsertConstraint(txn, constraint, pool_.get()); + + // add constraint into schema in source table and sink table + { + std::lock_guard lock(catalog_mutex); + src_schema->AddConstraint(constraint); + sink_table->GetSchema()->RegisterForeignKeySource(constraint); + } + + LOG_TRACE("Added a FOREIGN KEY constraint in %s to %s.", + src_table_object->GetTableName().c_str(), + catalog_map_[database_oid] + ->GetTableCatalog() + ->GetTableCatalogEntry(txn, sink_table_oid) + ->GetTableName() + .c_str()); + + return ResultType::SUCCESS; +} + +/** + * @brief Add a new check constraint for a table + * @param txn TransactionContext + * @param database_oid Database to which the table belongs to + * @param table_oid Table to which the constraint has to be added + * @param column_ids Columns that the constraint affects + * @param cmd Command string for check constraint + * @param exp Expression for check constraint + * @param constraint_name constraint name + * @return ResultType(SUCCESS or FAILURE) + * note: if add a new foreign key constraint, use AddForeignKeyConstraint + */ +ResultType Catalog::AddCheckConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, + oid_t table_oid, + const std::vector &column_ids, + const std::pair &exp, + const std::string &constraint_name) { + auto table_object = + catalog_map_[database_oid]->GetTableCatalog() + ->GetTableCatalogEntry(txn, table_oid); + auto schema = storage::StorageManager::GetInstance() + ->GetTableWithOid(database_oid, table_oid) + ->GetSchema(); + + // Insert constraint into pg_constraint + auto pg_constraint = catalog_map_[database_oid]->GetConstraintCatalog(); + std::shared_ptr constraint( + new Constraint(pg_constraint->GetNextOid(), + ConstraintType::CHECK, + constraint_name, + table_oid, + column_ids, + INVALID_OID, + exp)); + pg_constraint->InsertConstraint(txn, constraint, pool_.get()); + + // Add constraint into the schema + { + std::lock_guard lock(catalog_mutex); + schema->AddConstraint(constraint); + } + + LOG_TRACE("Added a CHECK constraint in %s.", + table_object->GetTableName().c_str()); + + return ResultType::SUCCESS; +} + //===----------------------------------------------------------------------===// // DROP FUNCTIONS //===----------------------------------------------------------------------===// @@ -963,6 +1306,11 @@ ResultType Catalog::DropTable(concurrency::TransactionContext *txn, table_oid, trigger_lists->Get(i)->GetTriggerName()); + // delete record in pg_constraint + auto pg_constraint = + catalog_map_[database_object->GetDatabaseOid()]->GetConstraintCatalog(); + pg_constraint->DeleteConstraints(txn, table_oid); + // delete index and records pg_index for (auto it : index_objects) DropIndex(txn, database_oid, it.second->GetIndexOid()); @@ -1063,6 +1411,153 @@ ResultType Catalog::DropLayout(concurrency::TransactionContext *txn, return ResultType::SUCCESS; } +/** + * @brief Drop not null constraint for a column + * @param txn TransactionContext + * @param database_oid the database to which the table belongs to + * @param table_oid the table to which the column belongs to + * @param column_id the column which has the not null constraint + * @return ResultType(SUCCESS or FAILURE) + */ +ResultType Catalog::DropNotNullConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, + oid_t table_oid, + oid_t column_id) { + auto table_object = + catalog_map_[database_oid]->GetTableCatalog() + ->GetTableCatalogEntry(txn, table_oid); + auto schema = storage::StorageManager::GetInstance() + ->GetTableWithOid(database_oid, table_oid) + ->GetSchema(); + auto column = schema->GetColumn(column_id); + + // Check not null + if (!column.IsNotNull()) { + throw CatalogException("Column " + column.GetName() + " in table " + + table_object->GetTableName() + " isn't NOT NULL."); + } + + // Update pg_column to set constraint of the column + auto pg_column = catalog_map_[database_oid]->GetColumnCatalog(); + pg_column->UpdateNotNullConstraint(txn, + table_oid, + column.GetName(), + false); + + // Set not null constraint in the schema + { + std::lock_guard lock(catalog_mutex); + schema->DropNotNull(column_id); + } + + return ResultType::SUCCESS; +} + +/** + * @brief Drop default constraint for a column + * @param txn TransactionContext + * @param database_oid the database to which the table belongs to + * @param table_oid the table to which the column belongs to + * @param column_id the column which has the default constraint + * @return ResultType(SUCCESS or FAILURE) + */ +ResultType Catalog::DropDefaultConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, + oid_t table_oid, + oid_t column_id) { + auto table_object = + catalog_map_[database_oid]->GetTableCatalog() + ->GetTableCatalogEntry(txn, table_oid); + auto schema = storage::StorageManager::GetInstance() + ->GetTableWithOid(database_oid, table_oid) + ->GetSchema(); + auto column = schema->GetColumn(column_id); + + // Check default + if (!column.HasDefault()) { + throw CatalogException("Column " + column.GetName() + " in table" + + table_object->GetTableName() + + " doesn't have default value."); + } + + // Update pg_column to set constraint of the column + auto pg_column = catalog_map_[database_oid]->GetColumnCatalog(); + pg_column->UpdateDefaultConstraint(txn, + table_oid, + column.GetName(), + false, + nullptr); + + // Set default constraint in the schema + { + std::lock_guard lock(catalog_mutex); + schema->DropDefaultValue(column_id); + } + + return ResultType::SUCCESS; +} + +/** + * @brief Drop a constraint for a table + * @param txn TransactionContext + * @param database_oid the database to which the table belongs to + * @param table_oid the table which has the constraint + * @param constraint_oid the constraint to be dropped + * @return ResultType(SUCCESS or FAILURE) + */ +ResultType Catalog::DropConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, + oid_t table_oid, + oid_t constraint_oid) { + auto pg_constraint = catalog_map_[database_oid]->GetConstraintCatalog(); + auto constraint_object = + pg_constraint->GetConstraintCatalogEntry(txn, + table_oid, + constraint_oid); + + // delete constraint object from pg_constraint + if (!pg_constraint->DeleteConstraint(txn, table_oid, constraint_oid)) { + throw CatalogException("Failed to delete the constraint: " + + std::to_string(constraint_oid)); + } + + // delete index if exists + if (constraint_object->GetIndexOid() != INVALID_OID) { + DropIndex(txn, database_oid, constraint_object->GetIndexOid()); + } + + // delete constraint from table + auto storage_manager = storage::StorageManager::GetInstance(); + auto table = storage_manager->GetTableWithOid(database_oid, table_oid); + { + std::lock_guard lock(catalog_mutex); + table->GetSchema()->DropConstraint(constraint_oid); + } + + // delete foreign key info from sink table + if (constraint_object->GetConstraintType() == ConstraintType::FOREIGN) { + auto sink_table = + storage_manager->GetTableWithOid(database_oid, + constraint_object->GetFKSinkTableOid()); + { + std::lock_guard lock(catalog_mutex); + sink_table->GetSchema() + ->DeleteForeignKeySource(constraint_object->GetConstraintOid()); + } + } + + LOG_TRACE( + "Drop a %s constraint in %s.", + ConstraintTypeToString(constraint_object->GetConstraintType()).c_str(), + catalog_map_[database_oid] + ->GetTableCatalog() + ->GetTableCatalogEntry(txn, table_oid) + ->GetTableName() + .c_str()); + + return ResultType::SUCCESS; +} + //===--------------------------------------------------------------------===// // GET WITH NAME - CHECK FROM CATALOG TABLES, USING TRANSACTION //===--------------------------------------------------------------------===// diff --git a/src/catalog/column.cpp b/src/catalog/column.cpp index 3195de231d4..a4c8e2f5acf 100644 --- a/src/catalog/column.cpp +++ b/src/catalog/column.cpp @@ -45,7 +45,9 @@ void Column::SetInlined() { const std::string Column::GetInfo() const { std::ostringstream os; - os << "Column[" << column_name << ", " << TypeIdToString(column_type_) << ", " + os << "Column[" << column_name_ << ", " + << TypeIdToString(column_type_) << ", " + << "Offset:" << column_offset_ << ", "; if (is_inlined_) { @@ -54,19 +56,17 @@ const std::string Column::GetInfo() const { os << "VarLength:" << variable_length_; } - if (constraints_.empty() == false) { - os << ", {"; - bool first = true; - for (auto constraint : constraints_) { - if (first) { - first = false; - } else { - os << ", "; - } - os << constraint.GetInfo(); - } - os << "}"; + if (is_not_null_ && has_default_) { + os << ", {NOT NULL, DEFAULT:" + << default_value_->ToString() << "}"; + } else if (is_not_null_) { + os << ", {NOT NULL}"; + } else if (has_default_) { + os << ", {DEFAULT:" + << default_value_->ToString() << "}"; + } + os << "]"; return (os.str()); diff --git a/src/catalog/column_catalog.cpp b/src/catalog/column_catalog.cpp index 6d4e7b717c1..5bc3a1d7902 100644 --- a/src/catalog/column_catalog.cpp +++ b/src/catalog/column_catalog.cpp @@ -18,6 +18,7 @@ #include "concurrency/transaction_context.h" #include "storage/data_table.h" #include "storage/database.h" +#include "type/ephemeral_pool.h" #include "type/value_factory.h" namespace peloton { @@ -38,14 +39,22 @@ ColumnCatalogEntry::ColumnCatalogEntry(executor::LogicalTile *tile, tile->GetValue(tupleId, ColumnCatalog::ColumnId::COLUMN_TYPE) .ToString())), column_length_( - tile->GetValue(tupleId, ColumnCatalog::ColumnId::COLUMN_LENGTH) - .GetAs()), + tile->GetValue(tupleId, ColumnCatalog::ColumnId::COLUMN_LENGTH) + .GetAs()), is_inlined_(tile->GetValue(tupleId, ColumnCatalog::ColumnId::IS_INLINED) .GetAs()), - is_primary_(tile->GetValue(tupleId, ColumnCatalog::ColumnId::IS_PRIMARY) - .GetAs()), is_not_null_(tile->GetValue(tupleId, ColumnCatalog::ColumnId::IS_NOT_NULL) - .GetAs()) {} + .GetAs()), + has_default_(tile->GetValue(tupleId, ColumnCatalog::ColumnId::HAS_DEFAULT) + .GetAs()) { + // deserialize default value if the column has default constraint + if (has_default_) { + auto dv_val = + tile->GetValue(tupleId, ColumnCatalog::ColumnId::DEFAULT_VALUE_BIN); + CopySerializeInput input_buffer(dv_val.GetData(), dv_val.GetLength()); + default_value_ = type::Value::DeserializeFrom(input_buffer, column_type_); + } +} ColumnCatalog::ColumnCatalog(concurrency::TransactionContext *txn, storage::Database *pg_catalog, @@ -73,13 +82,15 @@ ColumnCatalog::ColumnCatalog(concurrency::TransactionContext *txn, for (auto column : catalog_table_->GetSchema()->GetColumns()) { InsertColumn(txn, COLUMN_CATALOG_OID, - column_id, column.GetName(), + column_id, column.GetOffset(), column.GetType(), column.GetLength(), - column.GetConstraints(), column.IsInlined(), + column.IsNotNull(), + column.HasDefault(), + column.GetDefaultValue(), pool); column_id++; } @@ -91,82 +102,90 @@ ColumnCatalog::~ColumnCatalog() {} * @return unqiue pointer to schema */ std::unique_ptr ColumnCatalog::InitializeSchema() { - const std::string primary_key_constraint_name = "primary_key"; - const std::string not_null_constraint_name = "not_null"; - auto table_id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "table_oid", true); - table_id_column.AddConstraint(catalog::Constraint( - ConstraintType::PRIMARY, primary_key_constraint_name)); - table_id_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + table_id_column.SetNotNull(); auto column_name_column = catalog::Column( type::TypeId::VARCHAR, max_name_size_, "column_name", false); - column_name_column.AddConstraint(catalog::Constraint( - ConstraintType::PRIMARY, primary_key_constraint_name)); - column_name_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + column_name_column.SetNotNull(); auto column_id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "column_id", true); - column_id_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + column_id_column.SetNotNull(); auto column_offset_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "column_offset", true); - column_offset_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + column_offset_column.SetNotNull(); auto column_type_column = catalog::Column( type::TypeId::VARCHAR, max_name_size_, "column_type", false); - column_type_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + column_type_column.SetNotNull(); + auto column_length_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "column_length", true); - column_length_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + column_length_column.SetNotNull(); auto is_inlined_column = catalog::Column( type::TypeId::BOOLEAN, type::Type::GetTypeSize(type::TypeId::BOOLEAN), "is_inlined", true); - is_inlined_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); - - auto is_primary_column = catalog::Column( - type::TypeId::BOOLEAN, type::Type::GetTypeSize(type::TypeId::BOOLEAN), - "is_primary", true); - is_primary_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + is_inlined_column.SetNotNull(); auto is_not_null_column = catalog::Column( type::TypeId::BOOLEAN, type::Type::GetTypeSize(type::TypeId::BOOLEAN), "is_not_null", true); - is_not_null_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + is_not_null_column.SetNotNull(); + + auto has_default_column = catalog::Column( + type::TypeId::BOOLEAN, type::Type::GetTypeSize(type::TypeId::BOOLEAN), + "has_default", true); + has_default_column.SetNotNull(); + + auto default_value_src_column = catalog::Column( + type::TypeId::VARCHAR, type::Type::GetTypeSize(type::TypeId::VARCHAR), + "default_value_src", false); + + auto default_value_bin_column = catalog::Column( + type::TypeId::VARBINARY, type::Type::GetTypeSize(type::TypeId::VARBINARY), + "default_value_bin", false); std::unique_ptr column_catalog_schema(new catalog::Schema( {table_id_column, column_name_column, column_id_column, column_offset_column, column_type_column, column_length_column, - is_inlined_column, is_primary_column, is_not_null_column})); + is_inlined_column, is_not_null_column, has_default_column, + default_value_src_column, default_value_bin_column})); + + column_catalog_schema->AddConstraint(std::make_shared( + COLUMN_CATALOG_CON_PKEY_OID, ConstraintType::PRIMARY, "con_primary", + COLUMN_CATALOG_OID, + std::vector{ColumnId::TABLE_OID, ColumnId::COLUMN_NAME}, + COLUMN_CATALOG_PKEY_OID)); + + column_catalog_schema->AddConstraint(std::make_shared( + COLUMN_CATALOG_CON_UNI0_OID, ConstraintType::UNIQUE, "con_unique", + COLUMN_CATALOG_OID, + std::vector{ColumnId::TABLE_OID, ColumnId::COLUMN_ID}, + COLUMN_CATALOG_SKEY0_OID)); return column_catalog_schema; } bool ColumnCatalog::InsertColumn(concurrency::TransactionContext *txn, oid_t table_oid, - oid_t column_id, const std::string &column_name, + oid_t column_id, oid_t column_offset, type::TypeId column_type, size_t column_length, - const std::vector &constraints, bool is_inlined, + bool is_not_null, + bool is_default, + const std::shared_ptr default_value, type::AbstractPool *pool) { // Create the tuple first std::unique_ptr tuple( @@ -180,17 +199,8 @@ bool ColumnCatalog::InsertColumn(concurrency::TransactionContext *txn, type::ValueFactory::GetVarcharValue(TypeIdToString(column_type), nullptr); auto val5 = type::ValueFactory::GetIntegerValue(column_length); auto val6 = type::ValueFactory::GetBooleanValue(is_inlined); - bool is_primary = false, is_not_null = false; - for (auto constraint : constraints) { - if (constraint.GetType() == ConstraintType::PRIMARY) { - is_primary = true; - } else if (constraint.GetType() == ConstraintType::NOT_NULL || - constraint.GetType() == ConstraintType::NOTNULL) { - is_not_null = true; - } - } - auto val7 = type::ValueFactory::GetBooleanValue(is_primary); - auto val8 = type::ValueFactory::GetBooleanValue(is_not_null); + auto val7 = type::ValueFactory::GetBooleanValue(is_not_null); + auto val8 = type::ValueFactory::GetBooleanValue(is_default); tuple->SetValue(ColumnId::TABLE_OID, val0, pool); tuple->SetValue(ColumnId::COLUMN_NAME, val1, pool); @@ -199,8 +209,22 @@ bool ColumnCatalog::InsertColumn(concurrency::TransactionContext *txn, tuple->SetValue(ColumnId::COLUMN_TYPE, val4, pool); tuple->SetValue(ColumnId::COLUMN_LENGTH, val5, pool); tuple->SetValue(ColumnId::IS_INLINED, val6, pool); - tuple->SetValue(ColumnId::IS_PRIMARY, val7, pool); - tuple->SetValue(ColumnId::IS_NOT_NULL, val8, pool); + tuple->SetValue(ColumnId::IS_NOT_NULL, val7, pool); + tuple->SetValue(ColumnId::HAS_DEFAULT, val8, pool); + + // set default value if the column has default constraint + if (is_default) { + auto val9 = + type::ValueFactory::GetVarcharValue(default_value->ToString(), nullptr); + CopySerializeOutput output_buffer; + default_value->SerializeTo(output_buffer); + auto val10 = type::ValueFactory::GetVarbinaryValue( + (unsigned char *)output_buffer.Data(), output_buffer.Size(), true, + pool); + + tuple->SetValue(ColumnId::DEFAULT_VALUE_SRC, val9, pool); + tuple->SetValue(ColumnId::DEFAULT_VALUE_BIN, val10, pool); + } // Insert the tuple return InsertTuple(txn, std::move(tuple)); @@ -247,11 +271,91 @@ bool ColumnCatalog::DeleteColumns(concurrency::TransactionContext *txn, oid_t ta return DeleteWithIndexScan(txn, index_offset, values); } -const std::unordered_map> -ColumnCatalog::GetColumnCatalogEntries( - concurrency::TransactionContext *txn, - oid_t table_oid) { +bool ColumnCatalog::UpdateNotNullConstraint(concurrency::TransactionContext *txn, + oid_t table_oid, + const std::string &column_name, + bool is_not_null) { + std::vector update_columns({ColumnId::IS_NOT_NULL}); + oid_t index_offset = + IndexId::PRIMARY_KEY; // Index of table_oid & column_name + // values to execute index scan + std::vector scan_values; + scan_values.push_back(type::ValueFactory::GetIntegerValue(table_oid).Copy()); + scan_values.push_back( + type::ValueFactory::GetVarcharValue(column_name, nullptr).Copy()); + + // values to update + std::vector update_values; + update_values.push_back( + type::ValueFactory::GetBooleanValue(is_not_null).Copy()); + + // delete column from cache + auto pg_table = Catalog::GetInstance() + ->GetSystemCatalogs(database_oid_) + ->GetTableCatalog(); + auto table_object = pg_table->GetTableCatalogEntry(txn, table_oid); + table_object->EvictColumnCatalogEntry(column_name); + + return UpdateWithIndexScan(txn, + index_offset, + scan_values, + update_columns, + update_values); +} + +bool ColumnCatalog::UpdateDefaultConstraint(concurrency::TransactionContext *txn, + oid_t table_oid, + const std::string &column_name, + bool has_default, + const type::Value *default_value) { + std::vector update_columns({ColumnId::HAS_DEFAULT, + ColumnId::DEFAULT_VALUE_SRC, + ColumnId::DEFAULT_VALUE_BIN}); + oid_t index_offset = + IndexId::PRIMARY_KEY; // Index of table_oid & column_name + // values to execute index scan + std::vector scan_values; + scan_values.push_back(type::ValueFactory::GetIntegerValue(table_oid).Copy()); + scan_values.push_back( + type::ValueFactory::GetVarcharValue(column_name, nullptr).Copy()); + + // values to update + std::vector update_values; + update_values.push_back( + type::ValueFactory::GetBooleanValue(has_default).Copy()); + if (has_default) { + PELOTON_ASSERT(default_value != nullptr); + update_values.push_back( + type::ValueFactory::GetVarcharValue(default_value->ToString()).Copy()); + CopySerializeOutput output_buffer; + default_value->SerializeTo(output_buffer); + update_values.push_back(type::ValueFactory::GetVarbinaryValue( + (unsigned char *)output_buffer.Data(), + output_buffer.Size(), true).Copy()); + } else { + update_values.push_back( + type::ValueFactory::GetNullValueByType(type::TypeId::VARCHAR)); + update_values.push_back( + type::ValueFactory::GetNullValueByType(type::TypeId::VARBINARY)); + } + + // delete column from cache + auto pg_table = Catalog::GetInstance() + ->GetSystemCatalogs(database_oid_) + ->GetTableCatalog(); + auto table_object = pg_table->GetTableCatalogEntry(txn, table_oid); + table_object->EvictColumnCatalogEntry(column_name); + + return UpdateWithIndexScan(txn, + index_offset, + scan_values, + update_columns, + update_values); +} + +const std::unordered_map> +ColumnCatalog::GetColumnCatalogEntries(concurrency::TransactionContext *txn, + oid_t table_oid) { // try get from cache auto pg_table = Catalog::GetInstance() ->GetSystemCatalogs(database_oid_) diff --git a/src/catalog/constraint.cpp b/src/catalog/constraint.cpp index f9c2e025a9e..f1de24cfba6 100644 --- a/src/catalog/constraint.cpp +++ b/src/catalog/constraint.cpp @@ -20,10 +20,37 @@ namespace catalog { const std::string Constraint::GetInfo() const { std::ostringstream os; os << "Constraint[" << GetName() << ", " - << ConstraintTypeToString(constraint_type_); + << "OID=" << constraint_oid_ << ", " + << ConstraintTypeToString(constraint_type_) << ", "; - if (GetType() == ConstraintType::CHECK) { - os << ", " << exp_.first << " " << exp_.second.GetInfo(); + os << "Column: ("; + bool first = true; + for (auto col_id : column_ids_) { + if(first) first = false; + else os << ", "; + os << std::to_string(col_id); + } + os << "), "; + + os << "index_oid:" << std::to_string(index_oid_); + + if (constraint_type_ == ConstraintType::FOREIGN) { + os << ", Foreign key: (Sink table:" + << std::to_string(fk_sink_table_oid_) << ", " + << "Column:("; + bool first = true; + for (auto col_id : fk_sink_col_ids_) { + if(first) first = false; + else os << ", "; + os << std::to_string(col_id); + } + os << "), " << FKConstrActionTypeToString(fk_update_action_) << ", " + << FKConstrActionTypeToString(fk_delete_action_) << ")"; + } + + if (constraint_type_ == ConstraintType::CHECK) { + os << ", Check: (" << check_exp_.first << " " + << check_exp_.second.GetInfo() << ")"; } os << "]"; return os.str(); diff --git a/src/catalog/constraint_catalog.cpp b/src/catalog/constraint_catalog.cpp new file mode 100644 index 00000000000..f780333e700 --- /dev/null +++ b/src/catalog/constraint_catalog.cpp @@ -0,0 +1,428 @@ +//===----------------------------------------------------------------------===// +// +// Peloton +// +// constraint_catalog.cpp +// +// Identification: src/catalog/constraint_catalog.cpp +// +// Copyright (c) 2015-17, Carnegie Mellon University Database Group +// +//===----------------------------------------------------------------------===// + +#include "catalog/constraint_catalog.h" + +#include +#include + +#include "catalog/catalog.h" +#include "catalog/system_catalogs.h" +#include "catalog/table_catalog.h" +#include "concurrency/transaction_context.h" +#include "storage/data_table.h" +#include "storage/database.h" +#include "storage/storage_manager.h" +#include "type/value_factory.h" + +namespace peloton { +namespace catalog { + +ConstraintCatalogEntry::ConstraintCatalogEntry(executor::LogicalTile *tile, + int tupleId) + : constraint_oid_( + tile->GetValue(tupleId, ConstraintCatalog::ColumnId::CONSTRAINT_OID) + .GetAs()), + constraint_name_( + tile->GetValue(tupleId, ConstraintCatalog::ColumnId::CONSTRAINT_NAME) + .ToString()), + constraint_type_(StringToConstraintType( + tile->GetValue(tupleId, ConstraintCatalog::ColumnId::CONSTRAINT_TYPE) + .ToString())), + table_oid_(tile->GetValue(tupleId, ConstraintCatalog::ColumnId::TABLE_OID) + .GetAs()), + index_oid_(tile->GetValue(tupleId, ConstraintCatalog::ColumnId::INDEX_OID) + .GetAs()) { + std::string src_column_ids_str = + tile->GetValue(tupleId, ConstraintCatalog::ColumnId::COLUMN_IDS) + .ToString(); + std::stringstream src_ss(src_column_ids_str.c_str()); + std::string src_tok; + while (std::getline(src_ss, src_tok, ' ')) { + column_ids_.push_back(std::stoi(src_tok)); + } + + // create values by type of constraint + switch (constraint_type_) { + case ConstraintType::PRIMARY: + case ConstraintType::UNIQUE: + // nothing to do more + break; + + case ConstraintType::FOREIGN: { + fk_sink_table_oid_ = + tile->GetValue(tupleId, + ConstraintCatalog::ColumnId::FK_SINK_TABLE_OID) + .GetAs(); + std::string snk_column_ids_str = + tile->GetValue(tupleId, ConstraintCatalog::ColumnId::FK_SINK_COL_IDS) + .ToString(); + std::stringstream snk_ss(snk_column_ids_str.c_str()); + std::string snk_tok; + while (std::getline(snk_ss, snk_tok, ' ')) { + fk_sink_col_ids_.push_back(std::stoi(snk_tok)); + } + fk_update_action_ = StringToFKConstrActionType( + tile->GetValue(tupleId, ConstraintCatalog::ColumnId::FK_UPDATE_ACTION) + .ToString()); + fk_delete_action_ = StringToFKConstrActionType( + tile->GetValue(tupleId, ConstraintCatalog::ColumnId::FK_DELETE_ACTION) + .ToString()); + break; + } + + case ConstraintType::CHECK: { + auto dv_val = + tile->GetValue(tupleId, ConstraintCatalog::ColumnId::CHECK_EXP_BIN); + CopySerializeInput input_buffer(dv_val.GetData(), dv_val.GetLength()); + ExpressionType exp_type = (ExpressionType)input_buffer.ReadInt(); + type::TypeId value_type = (type::TypeId)input_buffer.ReadInt(); + auto exp_value = type::Value::DeserializeFrom(input_buffer, value_type); + check_exp_ = std::make_pair(exp_type, exp_value); + break; + } + + case ConstraintType::EXCLUSION: + default: + LOG_ERROR("Invalid Constraint type from pg_constraint: %s", + ConstraintTypeToString(constraint_type_).c_str()); + break; + } +} + +ConstraintCatalog::ConstraintCatalog( + UNUSED_ATTRIBUTE concurrency::TransactionContext *txn, + storage::Database *pg_catalog, UNUSED_ATTRIBUTE type::AbstractPool *pool) + : AbstractCatalog(pg_catalog, + InitializeSchema().release(), + CONSTRAINT_CATALOG_OID, + CONSTRAINT_CATALOG_NAME) { + // Add indexes for pg_constraint + AddIndex(CONSTRAINT_CATALOG_NAME "_pkey", + CONSTRAINT_CATALOG_PKEY_OID, + {ColumnId::CONSTRAINT_OID}, + IndexConstraintType::PRIMARY_KEY); + AddIndex(CONSTRAINT_CATALOG_NAME "_skey0", + CONSTRAINT_CATALOG_SKEY0_OID, + {ColumnId::TABLE_OID}, + IndexConstraintType::DEFAULT); +} + +ConstraintCatalog::~ConstraintCatalog() {} + +/*@brief private function for initialize schema of pg_constraint + * @return unqiue pointer to schema + */ +std::unique_ptr ConstraintCatalog::InitializeSchema() { + auto constraint_oid_column = catalog::Column( + type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), + "constraint_oid", true); + constraint_oid_column.SetNotNull(); + + auto constraint_name_column = catalog::Column( + type::TypeId::VARCHAR, max_name_size_, "constraint_name_", false); + constraint_name_column.SetNotNull(); + + auto constraint_type_column = catalog::Column( + type::TypeId::VARCHAR, max_name_size_, "constraint_type", false); + constraint_type_column.SetNotNull(); + + auto table_oid_column = catalog::Column( + type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), + "table_oid", true); + table_oid_column.SetNotNull(); + + auto column_ids_column = catalog::Column( + type::TypeId::VARCHAR, type::Type::GetTypeSize(type::TypeId::VARCHAR), + "column_ids", false); + column_ids_column.SetNotNull(); + + auto index_oid_column = catalog::Column( + type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), + "index_oid", true); + index_oid_column.SetNotNull(); + + auto fk_sink_table_oid_column = catalog::Column( + type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), + "fk_sink_table_oid", true); + + auto fk_sink_col_ids_column = catalog::Column( + type::TypeId::VARCHAR, type::Type::GetTypeSize(type::TypeId::VARCHAR), + "fk_sink_col_ids", false); + + auto fk_update_action_column = catalog::Column( + type::TypeId::VARCHAR, max_name_size_, "fk_update_action", false); + + auto fk_delete_action_column = catalog::Column( + type::TypeId::VARCHAR, max_name_size_, "fk_delete_action", false); + + auto check_exp_src_column = catalog::Column( + type::TypeId::VARCHAR, type::Type::GetTypeSize(type::TypeId::VARCHAR), + "check_exp_src", false); + + auto check_exp_bin_column = catalog::Column( + type::TypeId::VARBINARY, type::Type::GetTypeSize(type::TypeId::VARBINARY), + "check_exp_bin", false); + + std::unique_ptr constraint_catalog_schema( + new catalog::Schema({constraint_oid_column, constraint_name_column, + constraint_type_column, table_oid_column, + column_ids_column, index_oid_column, + fk_sink_table_oid_column, fk_sink_col_ids_column, + fk_update_action_column, fk_delete_action_column, + check_exp_src_column, check_exp_bin_column})); + + constraint_catalog_schema->AddConstraint(std::make_shared( + CONSTRAINT_CATALOG_CON_PKEY_OID, ConstraintType::PRIMARY, "con_primary", + CONSTRAINT_CATALOG_OID, std::vector{ColumnId::CONSTRAINT_OID}, + CONSTRAINT_CATALOG_PKEY_OID)); + + return constraint_catalog_schema; +} + +/*@brief Insert a constraint into the pg_constraint table + * This targets PRIMARY KEY, FOREIGN KEY, UNIQUE or CHECK constraint + * @param txn TransactionContext for adding the constraint. + * @param constraint to be inserted into pg_constraint + * @param pool to allocate memory for the column_map column. + * @return true on success. + */ +bool ConstraintCatalog::InsertConstraint(concurrency::TransactionContext *txn, + const std::shared_ptr constraint, + type::AbstractPool *pool) { + // Create the tuple first + std::unique_ptr tuple( + new storage::Tuple(catalog_table_->GetSchema(), true)); + + // Common information of constraint + auto val0 = + type::ValueFactory::GetIntegerValue(constraint->GetConstraintOid()); + auto val1 = + type::ValueFactory::GetVarcharValue(constraint->GetName(), nullptr); + auto val2 = type::ValueFactory::GetVarcharValue( + ConstraintTypeToString(constraint->GetType()), nullptr); + auto val3 = type::ValueFactory::GetIntegerValue(constraint->GetTableOid()); + std::stringstream ss; + for (auto column_oid : constraint->GetColumnIds()) + ss << std::to_string(column_oid) << " "; + auto val4 = type::ValueFactory::GetVarcharValue(ss.str(), nullptr); + auto val5 = type::ValueFactory::GetIntegerValue(constraint->GetIndexOid()); + + tuple->SetValue(ColumnId::CONSTRAINT_OID, val0, pool); + tuple->SetValue(ColumnId::CONSTRAINT_NAME, val1, pool); + tuple->SetValue(ColumnId::CONSTRAINT_TYPE, val2, pool); + tuple->SetValue(ColumnId::TABLE_OID, val3, pool); + tuple->SetValue(ColumnId::COLUMN_IDS, val4, pool); + tuple->SetValue(ColumnId::INDEX_OID, val5, pool); + + // create values by type of constraint + switch (constraint->GetType()) { + case ConstraintType::PRIMARY: + case ConstraintType::UNIQUE: + // nothing to do more + // need to set a valid index oid + PELOTON_ASSERT(constraint->GetIndexOid() != INVALID_OID); + break; + + case ConstraintType::FOREIGN: { + // need to set a valid index oid + PELOTON_ASSERT(constraint->GetIndexOid() != INVALID_OID); + + auto val6 = + type::ValueFactory::GetIntegerValue(constraint->GetFKSinkTableOid()); + std::stringstream snk_ss; + for (auto column_oid : constraint->GetFKSinkColumnIds()) + snk_ss << std::to_string(column_oid) << " "; + auto val7 = type::ValueFactory::GetVarcharValue(snk_ss.str(), nullptr); + auto val8 = type::ValueFactory::GetVarcharValue( + FKConstrActionTypeToString(constraint->GetFKUpdateAction()), nullptr); + auto val9 = type::ValueFactory::GetVarcharValue( + FKConstrActionTypeToString(constraint->GetFKDeleteAction()), nullptr); + + tuple->SetValue(ColumnId::FK_SINK_TABLE_OID, val6, pool); + tuple->SetValue(ColumnId::FK_SINK_COL_IDS, val7, pool); + tuple->SetValue(ColumnId::FK_UPDATE_ACTION, val8, pool); + tuple->SetValue(ColumnId::FK_DELETE_ACTION, val9, pool); + break; + } + + case ConstraintType::CHECK: { + // set value of check expression + PELOTON_ASSERT(constraint->GetColumnIds().size() == 1); + auto exp = constraint->GetCheckExpression(); + auto column = + storage::StorageManager::GetInstance() + ->GetTableWithOid(database_oid_, constraint->GetTableOid()) + ->GetSchema() + ->GetColumn(constraint->GetColumnIds().at(0)); + + std::stringstream exp_ss; + exp_ss << column.GetName() << " " << ExpressionTypeToString(exp.first) + << " " << exp.second.ToString(); + auto val6 = type::ValueFactory::GetVarcharValue(exp_ss.str(), nullptr); + + CopySerializeOutput output_buffer; + output_buffer.WriteInt((int)exp.first); + output_buffer.WriteInt((int)column.GetType()); + exp.second.SerializeTo(output_buffer); + auto val7 = type::ValueFactory::GetVarbinaryValue( + (unsigned char *)output_buffer.Data(), output_buffer.Size(), true, + pool); + + tuple->SetValue(ColumnId::CHECK_EXP_SRC, val6, pool); + tuple->SetValue(ColumnId::CHECK_EXP_BIN, val7, pool); + break; + } + + case ConstraintType::EXCLUSION: + default: + // unexpected constraint type + throw CatalogException("Unexpected constraint type '" + + ConstraintTypeToString(constraint->GetType()) + + "' appears in insertion into pg_constraint "); + return false; + } + + // Insert the tuple + return InsertTuple(txn, std::move(tuple)); +} + +/* @brief delete all constraint records from the same table + * this function is useful when calling DropTable + * @param txn TransactionContext + * @param table_oid + * @return a vector of table oid + */ +bool ConstraintCatalog::DeleteConstraints(concurrency::TransactionContext *txn, + oid_t table_oid) { + oid_t index_offset = IndexId::SKEY_TABLE_OID; // Index of table_oid + std::vector values; + values.push_back(type::ValueFactory::GetIntegerValue(table_oid).Copy()); + + // delete constraints from cache + auto pg_table = Catalog::GetInstance() + ->GetSystemCatalogs(database_oid_) + ->GetTableCatalog(); + auto table_object = pg_table->GetTableCatalogEntry(txn, table_oid); + table_object->EvictAllConstraintCatalogEntries(); + + return DeleteWithIndexScan(txn, index_offset, values); +} + +/** @brief Delete a constraint from the pg_constraint table. + * @param txn TransactionContext for deleting the constraint. + * @param table_oid oid of the table to which the old constraint belongs. + * @param constraint_oid oid of the constraint to be deleted. + * @return true on success. + */ +bool ConstraintCatalog::DeleteConstraint(concurrency::TransactionContext *txn, + oid_t table_oid, + oid_t constraint_oid) { + oid_t index_offset = IndexId::PRIMARY_KEY; // Index of constraint_oid + std::vector values; + values.push_back(type::ValueFactory::GetIntegerValue(constraint_oid).Copy()); + + // delete constraint from cache + auto pg_table = Catalog::GetInstance() + ->GetSystemCatalogs(database_oid_) + ->GetTableCatalog(); + auto table_object = pg_table->GetTableCatalogEntry(txn, table_oid); + table_object->EvictConstraintCatalogEntry(constraint_oid); + + return DeleteWithIndexScan(txn, index_offset, values); +} + +/** @brief Get all constraint objects correponding to a table + * from the pg_constraint. + * @param txn TransactionContext for getting the constraints. + * @param table_oid oid of the table to fetch all constraints. + * @return unordered_map containing a constraint_oid -> + * constraint object mapping. + */ +const std::unordered_map> +ConstraintCatalog::GetConstraintCatalogEntries(concurrency::TransactionContext *txn, + oid_t table_oid) { + // try get from cache + auto pg_table = Catalog::GetInstance() + ->GetSystemCatalogs(database_oid_) + ->GetTableCatalog(); + auto table_object = pg_table->GetTableCatalogEntry(txn, table_oid); + PELOTON_ASSERT(table_object && table_object->GetTableOid() == table_oid); + + auto constraint_objects = table_object->GetConstraintCatalogEntries(true); + if (constraint_objects.size() != 0) return constraint_objects; + + // cache miss, get from pg_constraint + std::vector column_ids(all_column_ids_); + oid_t index_offset = IndexId::SKEY_TABLE_OID; // Index of table_oid + std::vector values; + values.push_back(type::ValueFactory::GetIntegerValue(table_oid).Copy()); + + auto result_tiles = + GetResultWithIndexScan(txn, column_ids, index_offset, values); + + for (auto &tile : (*result_tiles)) { + for (auto tuple_id : *tile) { + auto constraint_object = + std::make_shared(tile.get(), tuple_id); + table_object->InsertConstraintCatalogEntry(constraint_object); + } + } + + table_object->SetValidConstraintCatalogEntries(true); + return table_object->GetConstraintCatalogEntries(); +} + +/** @brief Get the constraint object by constraint_oid from + * the pg_constraint. + * @param txn TransactionContext for getting the constraint. + * @param table_oid oid of the table to fetch the constraint. + * @param constraint_oid oid of the constraint being queried. + * @return shared_ptr constraint object to the constraint_oid if found. + * nullptr otherwise. + */ +const std::shared_ptr +ConstraintCatalog::GetConstraintCatalogEntry(concurrency::TransactionContext *txn, + oid_t table_oid, + oid_t constraint_oid) { + // try get from cache + auto pg_table = Catalog::GetInstance() + ->GetSystemCatalogs(database_oid_) + ->GetTableCatalog(); + auto table_object = pg_table->GetTableCatalogEntry(txn, table_oid); + PELOTON_ASSERT(table_object && table_object->GetTableOid() == table_oid); + + auto constraint_object = + table_object->GetConstraintCatalogEntry(constraint_oid, true); + if (constraint_object != nullptr) return constraint_object; + + // cache miss, get from pg_constraint + std::vector column_ids(all_column_ids_); + oid_t index_offset = IndexId::PRIMARY_KEY; // Index of table_oid + std::vector values; + values.push_back(type::ValueFactory::GetIntegerValue(constraint_oid).Copy()); + + auto result_tiles = + GetResultWithIndexScan(txn, column_ids, index_offset, values); + + if (result_tiles->size() == 1 && (*result_tiles)[0]->GetTupleCount() == 1) { + auto constraint_object = + std::make_shared((*result_tiles)[0].get()); + table_object->InsertConstraintCatalogEntry(constraint_object); + return constraint_object; + } + + return nullptr; +} + +} // namespace catalog +} // namespace peloton diff --git a/src/catalog/database_catalog.cpp b/src/catalog/database_catalog.cpp index 555e8c9d7d6..d869b20654d 100644 --- a/src/catalog/database_catalog.cpp +++ b/src/catalog/database_catalog.cpp @@ -276,24 +276,28 @@ DatabaseCatalog::~DatabaseCatalog() {} * @return unqiue pointer to schema */ std::unique_ptr DatabaseCatalog::InitializeSchema() { - const std::string not_null_constraint_name = "not_null"; - const std::string primary_key_constraint_name = "primary_key"; - auto database_id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "database_oid", true); - database_id_column.AddConstraint(catalog::Constraint( - ConstraintType::PRIMARY, primary_key_constraint_name)); - database_id_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + database_id_column.SetNotNull(); auto database_name_column = catalog::Column( type::TypeId::VARCHAR, max_name_size_, "database_name", false); - database_name_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + database_name_column.SetNotNull(); std::unique_ptr database_catalog_schema( new catalog::Schema({database_id_column, database_name_column})); + + database_catalog_schema->AddConstraint(std::make_shared( + DATABASE_CATALOG_CON_PKEY_OID, ConstraintType::PRIMARY, "con_primary", + DATABASE_CATALOG_OID, std::vector{ColumnId::DATABASE_OID}, + DATABASE_CATALOG_PKEY_OID)); + + database_catalog_schema->AddConstraint(std::make_shared( + DATABASE_CATALOG_CON_UNI0_OID, ConstraintType::UNIQUE, "con_unique", + DATABASE_CATALOG_OID, std::vector{ColumnId::DATABASE_NAME}, + DATABASE_CATALOG_SKEY0_OID)); + return database_catalog_schema; } diff --git a/src/catalog/index_catalog.cpp b/src/catalog/index_catalog.cpp index eaab5f3cfa7..69a2633ed44 100644 --- a/src/catalog/index_catalog.cpp +++ b/src/catalog/index_catalog.cpp @@ -64,15 +64,15 @@ IndexCatalog::IndexCatalog(concurrency::TransactionContext *, // Add indexes for pg_index AddIndex(INDEX_CATALOG_NAME "_pkey", INDEX_CATALOG_PKEY_OID, - {0}, + {ColumnId::INDEX_OID}, IndexConstraintType::PRIMARY_KEY); AddIndex(INDEX_CATALOG_NAME "_skey0", INDEX_CATALOG_SKEY0_OID, - {1, 3}, + {ColumnId::INDEX_NAME, ColumnId::SCHEMA_NAME}, IndexConstraintType::UNIQUE); AddIndex(INDEX_CATALOG_NAME "_skey1", INDEX_CATALOG_SKEY1_OID, - {2}, + {ColumnId::TABLE_OID}, IndexConstraintType::DEFAULT); } @@ -82,59 +82,60 @@ IndexCatalog::~IndexCatalog() {} * @return unqiue pointer to schema */ std::unique_ptr IndexCatalog::InitializeSchema() { - const std::string not_null_constraint_name = "not_null"; - const std::string primary_key_constraint_name = "primary_key"; - auto index_id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "index_oid", true); - index_id_column.AddConstraint(catalog::Constraint( - ConstraintType::PRIMARY, primary_key_constraint_name)); - index_id_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + index_id_column.SetNotNull(); auto index_name_column = catalog::Column(type::TypeId::VARCHAR, max_name_size_, "index_name", false); - index_name_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + index_name_column.SetNotNull(); auto table_id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "table_oid", true); - table_id_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + table_id_column.SetNotNull(); auto schema_name_column = catalog::Column( type::TypeId::VARCHAR, max_name_size_, "schema_name", false); - schema_name_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + schema_name_column.SetNotNull(); + auto index_type_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "index_type", true); - index_type_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + index_type_column.SetNotNull(); auto index_constraint_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "index_constraint", true); - index_constraint_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + index_constraint_column.SetNotNull(); auto unique_keys = catalog::Column( type::TypeId::BOOLEAN, type::Type::GetTypeSize(type::TypeId::BOOLEAN), "unique_keys", true); - unique_keys.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + unique_keys.SetNotNull(); auto indexed_attributes_column = catalog::Column( type::TypeId::VARCHAR, max_name_size_, "indexed_attributes", false); - indexed_attributes_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + indexed_attributes_column.SetNotNull(); + + std::unique_ptr index_schema(new catalog::Schema( {index_id_column, index_name_column, table_id_column, schema_name_column, index_type_column, index_constraint_column, unique_keys, indexed_attributes_column})); + + index_schema->AddConstraint(std::make_shared( + INDEX_CATALOG_CON_PKEY_OID, ConstraintType::PRIMARY, "con_primary", + INDEX_CATALOG_OID, std::vector{ColumnId::INDEX_OID}, + INDEX_CATALOG_PKEY_OID)); + + index_schema->AddConstraint(std::make_shared( + INDEX_CATALOG_CON_UNI0_OID, ConstraintType::UNIQUE, "con_unique", + INDEX_CATALOG_OID, std::vector{ColumnId::INDEX_NAME, ColumnId::SCHEMA_NAME}, + INDEX_CATALOG_SKEY0_OID)); + return index_schema; } diff --git a/src/catalog/layout_catalog.cpp b/src/catalog/layout_catalog.cpp index 8db442a03e0..4d5ac563dde 100644 --- a/src/catalog/layout_catalog.cpp +++ b/src/catalog/layout_catalog.cpp @@ -50,42 +50,36 @@ LayoutCatalog::~LayoutCatalog() {} * @return unique_ptr of the schema for pg_layout. */ std::unique_ptr LayoutCatalog::InitializeSchema() { - const std::string primary_key_constraint_name = "primary_key"; - const std::string not_null_constraint_name = "not_null"; - auto table_id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "table_oid", true); - table_id_column.AddConstraint(catalog::Constraint( - ConstraintType::PRIMARY, primary_key_constraint_name)); - table_id_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + table_id_column.SetNotNull(); auto layout_oid_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "layout_oid", true); - layout_oid_column.AddConstraint(catalog::Constraint( - ConstraintType::PRIMARY, primary_key_constraint_name)); - layout_oid_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + layout_oid_column.SetNotNull(); auto num_columns_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "num_columns", true); - num_columns_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + num_columns_column.SetNotNull(); auto column_map_column = catalog::Column( type::TypeId::VARCHAR, type::Type::GetTypeSize(type::TypeId::VARCHAR), "column_map", false); - column_map_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + column_map_column.SetNotNull(); - std::unique_ptr column_catalog_schema( + std::unique_ptr layout_catalog_schema( new catalog::Schema({table_id_column, layout_oid_column, num_columns_column, column_map_column})); - return column_catalog_schema; + layout_catalog_schema->AddConstraint(std::make_shared( + LAYOUT_CATALOG_CON_PKEY_OID, ConstraintType::PRIMARY, "con_primary", + LAYOUT_CATALOG_OID, std::vector{ColumnId::TABLE_OID, ColumnId::LAYOUT_OID}, + LAYOUT_CATALOG_PKEY_OID)); + + return layout_catalog_schema; } /** @brief Insert a layout into the pg_layout table. diff --git a/src/catalog/manager.cpp b/src/catalog/manager.cpp index 7c17c53d7bc..a683d36843e 100644 --- a/src/catalog/manager.cpp +++ b/src/catalog/manager.cpp @@ -13,7 +13,6 @@ #include "common/exception.h" #include "common/logger.h" #include "catalog/manager.h" -#include "catalog/foreign_key.h" #include "storage/database.h" #include "storage/data_table.h" #include "concurrency/transaction_manager_factory.h" diff --git a/src/catalog/multi_constraint.cpp b/src/catalog/multi_constraint.cpp deleted file mode 100644 index d1e4e3d9817..00000000000 --- a/src/catalog/multi_constraint.cpp +++ /dev/null @@ -1,39 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Peloton -// -// multi_constraint.cpp -// -// Identification: src/catalog/multi_constraint.cpp -// -// Copyright (c) 2015-2017, Carnegie Mellon University Database Group -// -//===----------------------------------------------------------------------===// - -#include "catalog/multi_constraint.h" -#include "common/internal_types.h" - -#include - -namespace peloton { -namespace catalog { - -const std::string MultiConstraint::GetInfo() const { - std::ostringstream os; - os << "Constraint[" << GetName() << ", " - << ConstraintTypeToString(constraint_type_) << " , related columns: ("; - bool first = true; - for (auto id : column_ids_) { - if (first) { - os << id; - first = false; - } else { - os << " ," << id; - } - } - os << ")]"; - return os.str(); -} - -} // namespace catalog -} // namespace peloton diff --git a/src/catalog/schema.cpp b/src/catalog/schema.cpp index 66f557f2532..3024ef0a1c3 100644 --- a/src/catalog/schema.cpp +++ b/src/catalog/schema.cpp @@ -76,10 +76,14 @@ Schema::Schema(const std::vector &columns) CreateTupleSchema(column_types, column_lengths, column_names, is_inlined); - // Add constraints + // Set constraints for (oid_t column_itr = 0; column_itr < column_count; column_itr++) { - for (auto constraint : columns[column_itr].GetConstraints()) - AddConstraint(column_itr, constraint); + if (columns[column_itr].IsNotNull()) { + SetNotNull(column_itr); + } + if (columns[column_itr].HasDefault()) { + SetDefaultValue(column_itr, *(columns[column_itr].GetDefaultValue())); + } } } @@ -292,6 +296,20 @@ const std::string Schema::GetInfo() const { } os << ")"; + if (constraints.empty() == false) { + os << ", {"; + bool first = true; + for (auto constraint : constraints) { + if (first) { + first = false; + } else { + os << ", "; + } + os << constraint.second->GetInfo(); + } + os << "}"; + } + return os.str(); } diff --git a/src/catalog/schema_catalog.cpp b/src/catalog/schema_catalog.cpp index 815c6e467a6..d93f2c0f4b7 100644 --- a/src/catalog/schema_catalog.cpp +++ b/src/catalog/schema_catalog.cpp @@ -42,11 +42,11 @@ SchemaCatalog::SchemaCatalog(concurrency::TransactionContext *, // Add indexes for pg_namespace AddIndex(SCHEMA_CATALOG_NAME "_pkey", SCHEMA_CATALOG_PKEY_OID, - {0}, + {ColumnId::SCHEMA_OID}, IndexConstraintType::PRIMARY_KEY); AddIndex(SCHEMA_CATALOG_NAME "_skey0", SCHEMA_CATALOG_SKEY0_OID, - {1}, + {ColumnId::SCHEMA_NAME}, IndexConstraintType::UNIQUE); } @@ -56,24 +56,28 @@ SchemaCatalog::~SchemaCatalog() {} * @return unqiue pointer to schema */ std::unique_ptr SchemaCatalog::InitializeSchema() { - const std::string not_null_constraint_name = "not_null"; - const std::string primary_key_constraint_name = "primary_key"; - auto schema_id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "schema_oid", true); - schema_id_column.AddConstraint(catalog::Constraint( - ConstraintType::PRIMARY, primary_key_constraint_name)); - schema_id_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + schema_id_column.SetNotNull(); auto schema_name_column = catalog::Column( type::TypeId::VARCHAR, max_name_size_, "schema_name", false); - schema_name_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + schema_name_column.SetNotNull(); std::unique_ptr schema( new catalog::Schema({schema_id_column, schema_name_column})); + + schema->AddConstraint(std::make_shared( + SCHEMA_CATALOG_CON_PKEY_OID, ConstraintType::PRIMARY, "con_primary", + SCHEMA_CATALOG_OID, std::vector{ColumnId::SCHEMA_OID}, + SCHEMA_CATALOG_PKEY_OID)); + + schema->AddConstraint(std::make_shared( + SCHEMA_CATALOG_CON_UNI0_OID, ConstraintType::UNIQUE, "con_unique", + SCHEMA_CATALOG_OID, std::vector{ColumnId::SCHEMA_NAME}, + SCHEMA_CATALOG_SKEY0_OID)); + return schema; } diff --git a/src/catalog/system_catalogs.cpp b/src/catalog/system_catalogs.cpp index 7e92755c001..7d9267abfa9 100644 --- a/src/catalog/system_catalogs.cpp +++ b/src/catalog/system_catalogs.cpp @@ -35,40 +35,48 @@ SystemCatalogs::SystemCatalogs(concurrency::TransactionContext *txn, pg_index_metrics_(nullptr), pg_query_metrics_(nullptr) { oid_t database_oid = database->GetOid(); + pg_attribute_ = new ColumnCatalog(txn, database, pool); pg_namespace_ = new SchemaCatalog(txn, database, pool); pg_table_ = new TableCatalog(txn, database, pool); pg_index_ = new IndexCatalog(txn, database, pool); pg_layout_ = new LayoutCatalog(txn, database, pool); + pg_constraint_ = new ConstraintCatalog(txn, database, pool); // TODO: can we move this to BootstrapSystemCatalogs()? // insert column information into pg_attribute + // and insert constraint information into pg_constraint std::vector> shared_tables = { {CATALOG_DATABASE_OID, DATABASE_CATALOG_OID}, {database_oid, TABLE_CATALOG_OID}, {database_oid, SCHEMA_CATALOG_OID}, {database_oid, INDEX_CATALOG_OID}, - {database_oid, LAYOUT_CATALOG_OID}}; + {database_oid, LAYOUT_CATALOG_OID}, + {database_oid, CONSTRAINT_CATALOG_OID}}; for (int i = 0; i < (int)shared_tables.size(); i++) { + auto schema = storage::StorageManager::GetInstance() + ->GetTableWithOid(shared_tables[i].first, shared_tables[i].second) + ->GetSchema(); oid_t column_id = 0; - for (auto column : - storage::StorageManager::GetInstance() - ->GetTableWithOid(shared_tables[i].first, shared_tables[i].second) - ->GetSchema() - ->GetColumns()) { + for (auto column : schema->GetColumns()) { pg_attribute_->InsertColumn(txn, shared_tables[i].second, - column_id, column.GetName(), + column_id, column.GetOffset(), column.GetType(), column.GetLength(), - column.GetConstraints(), column.IsInlined(), + column.IsNotNull(), + column.HasDefault(), + column.GetDefaultValue(), pool); column_id++; } + for (auto constraint : schema->GetConstraints()) { + pg_constraint_->InsertConstraint(txn, constraint.second, pool); + } } } @@ -78,6 +86,7 @@ SystemCatalogs::~SystemCatalogs() { delete pg_table_; delete pg_attribute_; delete pg_namespace_; + delete pg_constraint_; if (pg_trigger_) delete pg_trigger_; // if (pg_proc) delete pg_proc; if (pg_table_metrics_) delete pg_table_metrics_; @@ -119,6 +128,7 @@ void SystemCatalogs::Bootstrap(concurrency::TransactionContext *txn, pg_namespace_->UpdateOid(OID_FOR_USER_OFFSET); pg_table_->UpdateOid(OID_FOR_USER_OFFSET); pg_index_->UpdateOid(OID_FOR_USER_OFFSET); + pg_constraint_->UpdateOid(OID_FOR_USER_OFFSET); pg_trigger_->UpdateOid(OID_FOR_USER_OFFSET); // pg_proc->UpdateOid(OID_FOR_USER_OFFSET); } diff --git a/src/catalog/table_catalog.cpp b/src/catalog/table_catalog.cpp index 8031fdd961e..14cdd46c7ef 100644 --- a/src/catalog/table_catalog.cpp +++ b/src/catalog/table_catalog.cpp @@ -16,6 +16,7 @@ #include "catalog/catalog.h" #include "catalog/column_catalog.h" +#include "catalog/constraint_catalog.h" #include "catalog/database_catalog.h" #include "catalog/index_catalog.h" #include "catalog/layout_catalog.h" @@ -50,6 +51,8 @@ TableCatalogEntry::TableCatalogEntry(concurrency::TransactionContext *txn, column_names_(), valid_column_catalog_entries_(false), valid_layout_catalog_entries_(false), + constraint_catalog_entries_(), + valid_constraint_catalog_entries_(false), txn_(txn) {} /* @brief insert index catalog object into cache @@ -330,15 +333,15 @@ TableCatalog::TableCatalog(concurrency::TransactionContext *, // Add indexes for pg_namespace AddIndex(TABLE_CATALOG_NAME "_pkey", TABLE_CATALOG_PKEY_OID, - {0}, + {ColumnId::TABLE_OID}, IndexConstraintType::PRIMARY_KEY); AddIndex(TABLE_CATALOG_NAME "_skey0", TABLE_CATALOG_SKEY0_OID, - {1, 2}, + {ColumnId::TABLE_NAME, ColumnId::SCHEMA_NAME}, IndexConstraintType::UNIQUE); AddIndex(TABLE_CATALOG_NAME "_skey1", TABLE_CATALOG_SKEY1_OID, - {3}, + {ColumnId::DATABASE_OID}, IndexConstraintType::DEFAULT); } @@ -423,55 +426,141 @@ bool TableCatalogEntry::EvictLayout(oid_t layout_id) { return true; } + +/** @brief Insert a constraint catalog entry into the cache. + * @param constraint_object Constraint to be inserted + * @return false if the constraint already exists in cache + */ +bool TableCatalogEntry::InsertConstraintCatalogEntry( + std::shared_ptr constraint_catalog_entry) { + // Invalid object + if (!constraint_catalog_entry + || (constraint_catalog_entry->GetConstraintOid() == INVALID_OID)) { + return false; + } + + oid_t constraint_oid = constraint_catalog_entry->GetConstraintOid(); + // layout is already present in the cache. + if (constraint_catalog_entries_.find(constraint_oid) != + constraint_catalog_entries_.end()) { + LOG_DEBUG("Constraint Object %u already exists in cache!", constraint_oid); + return false; + } + + constraint_catalog_entries_.insert(std::make_pair(constraint_oid, + constraint_catalog_entry)); + return true; +} + + +/** @brief Evict a constraint catalog entry from the cache. + * @param constraint_oid Id of the constraint to be deleted. + * @return true if constraint_oid is found and evicted; false if not found. + */ +bool TableCatalogEntry::EvictConstraintCatalogEntry(oid_t constraint_oid) { + if (!valid_constraint_catalog_entries_) return false; + + // find the constraint catalog entry from the cache + auto it = constraint_catalog_entries_.find(constraint_oid); + if (it == constraint_catalog_entries_.end()) { + return false; // constraint_oid not found in cache + } + + auto constraint_object = it->second; + PELOTON_ASSERT(constraint_object); + constraint_catalog_entries_.erase(it); + return true; +} + +/** @brief evict all constraint catalog entries from cache. */ +void TableCatalogEntry::EvictAllConstraintCatalogEntries() { + constraint_catalog_entries_.clear(); + valid_constraint_catalog_entries_ = false; +} + +/** @brief Get all constraint catalog entries of this table. + * Add it to the cache if necessary. + * @param cached_only If set to true, don't fetch the constraints. + * @return Map from constraint_oid to cached constraint object. + */ +std::unordered_map> +TableCatalogEntry::GetConstraintCatalogEntries(bool cached_only) { + if (!valid_constraint_catalog_entries_ && !cached_only) { + // get constraint catalog objects from pg_constraint + auto pg_constraint = Catalog::GetInstance() + ->GetSystemCatalogs(database_oid) + ->GetConstraintCatalog(); + pg_constraint->GetConstraintCatalogEntries(txn_, table_oid); + valid_constraint_catalog_entries_ = true; + } + return constraint_catalog_entries_; +} + +/** @brief Get a constraint catalog entry of the given constraint_oid. + * @param constraint_oid The id of the constraint to be fetched. + * @param cached_only If set to true, don't fetch the constraint. + * @return Constraint catalog object of corresponding to the oid if present. + */ +std::shared_ptr +TableCatalogEntry::GetConstraintCatalogEntry(oid_t constraint_oid, bool cached_only){ + GetConstraintCatalogEntries(cached_only); // fetch constraint in case we have not + auto it = constraint_catalog_entries_.find(constraint_oid); + if (it != constraint_catalog_entries_.end()) { + return it->second; + } + return nullptr; +} + + TableCatalog::~TableCatalog() {} /*@brief private function for initialize schema of pg_table * @return unqiue pointer to schema */ std::unique_ptr TableCatalog::InitializeSchema() { - const std::string primary_key_constraint_name = "primary_key"; - const std::string not_null_constraint_name = "not_null"; - auto table_id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "table_oid", true); - table_id_column.AddConstraint(catalog::Constraint( - ConstraintType::PRIMARY, primary_key_constraint_name)); - table_id_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + table_id_column.SetNotNull(); auto table_name_column = catalog::Column(type::TypeId::VARCHAR, max_name_size_, "table_name", false); - table_name_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + table_name_column.SetNotNull(); auto schema_name_column = catalog::Column( type::TypeId::VARCHAR, max_name_size_, "schema_name", false); - schema_name_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + schema_name_column.SetNotNull(); + auto database_id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "database_oid", true); - database_id_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + database_id_column.SetNotNull(); auto version_id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "version_id", true); - version_id_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + version_id_column.SetNotNull(); auto default_layout_id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "default_layout_oid", true); - default_layout_id_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, not_null_constraint_name)); + default_layout_id_column.SetNotNull(); std::unique_ptr table_catalog_schema(new catalog::Schema( {table_id_column, table_name_column, schema_name_column, database_id_column, version_id_column, default_layout_id_column})); + table_catalog_schema->AddConstraint(std::make_shared( + TABLE_CATALOG_CON_PKEY_OID, ConstraintType::PRIMARY, "con_primary", + TABLE_CATALOG_OID, std::vector{ColumnId::TABLE_OID}, + TABLE_CATALOG_PKEY_OID)); + + table_catalog_schema->AddConstraint(std::make_shared( + TABLE_CATALOG_CON_UNI0_OID, ConstraintType::UNIQUE, "con_unique", + TABLE_CATALOG_OID, std::vector{ColumnId::TABLE_NAME, ColumnId::SCHEMA_NAME}, + TABLE_CATALOG_SKEY0_OID)); + return table_catalog_schema; } diff --git a/src/common/internal_types.cpp b/src/common/internal_types.cpp index 855f7ef2d9b..3b0c20900df 100644 --- a/src/common/internal_types.cpp +++ b/src/common/internal_types.cpp @@ -2082,15 +2082,6 @@ std::string ConstraintTypeToString(ConstraintType type) { case ConstraintType::INVALID: { return ("INVALID"); } - case ConstraintType::NOT_NULL: { - return ("NOT_NULL"); - } - case ConstraintType::NOTNULL: { - return ("NOTNULL"); - } - case ConstraintType::DEFAULT: { - return ("DEFAULT"); - } case ConstraintType::CHECK: { return ("CHECK"); } @@ -2119,12 +2110,6 @@ ConstraintType StringToConstraintType(const std::string &str) { std::string upper_str = StringUtil::Upper(str); if (upper_str == "INVALID") { return ConstraintType::INVALID; - } else if (upper_str == "NOT_NULL") { - return ConstraintType::NOT_NULL; - } else if (upper_str == "NOTNULL") { - return ConstraintType::NOTNULL; - } else if (upper_str == "DEFAULT") { - return ConstraintType::DEFAULT; } else if (upper_str == "CHECK") { return ConstraintType::CHECK; } else if (upper_str == "PRIMARY") { @@ -2147,6 +2132,67 @@ std::ostream &operator<<(std::ostream &os, const ConstraintType &type) { return os; } +//===--------------------------------------------------------------------===// +// Foreign Key Action Type - String Utilities +//===--------------------------------------------------------------------===// + +std::string FKConstrActionTypeToString(FKConstrActionType type) { + switch (type) { + case FKConstrActionType::INVALID: { + return ("INVALID"); + } + case FKConstrActionType::NOACTION: { + return ("NOACTION"); + } + case FKConstrActionType::RESTRICT: { + return ("RESTRICT"); + } + case FKConstrActionType::CASCADE: { + return ("CASCADE"); + } + case FKConstrActionType::SETNULL: { + return ("SETNULL"); + } + case FKConstrActionType::SETDEFAULT: { + return ("SETDEFAULT"); + } + default: { + throw ConversionException(StringUtil::Format( + "No string conversion for FKConstrActionType value '%d'", + static_cast(type))); + } + } +return "INVALID"; +} + +FKConstrActionType StringToFKConstrActionType(const std::string &str){ + std::string upper_str = StringUtil::Upper(str); + if (upper_str == "INVALID") { + return FKConstrActionType::INVALID; + } else if (upper_str == "NOACTION") { + return FKConstrActionType::NOACTION; + } else if (upper_str == "RESTRICT") { + return FKConstrActionType::RESTRICT; + } else if (upper_str == "CASCADE") { + return FKConstrActionType::CASCADE; + } else if (upper_str == "SETNULL") { + return FKConstrActionType::SETNULL; + } else if (upper_str == "SETDEFAULT") { + return FKConstrActionType::SETDEFAULT; + } else { + throw ConversionException(StringUtil::Format( + "No FKConstrActionType conversion from string '%s'", + upper_str.c_str())); + } + return FKConstrActionType::INVALID; +} + + +std::ostream &operator<<(std::ostream &os, const FKConstrActionType &type) { + os << FKConstrActionTypeToString(type); + return os; +} + //===--------------------------------------------------------------------===// // SetOpType - String Utilities //===--------------------------------------------------------------------===// @@ -2782,18 +2828,6 @@ ConstraintType PostgresConstraintTypeToPelotonConstraintType( ConstraintType constraintType = ConstraintType::INVALID; switch (type) { - case PostgresConstraintType::NOT_NULL: - constraintType = ConstraintType::NOT_NULL; - break; - - case PostgresConstraintType::NOTNULL: - constraintType = ConstraintType::NOTNULL; - break; - - case PostgresConstraintType::DEFAULT: - constraintType = ConstraintType::DEFAULT; - break; - case PostgresConstraintType::CHECK: constraintType = ConstraintType::CHECK; break; diff --git a/src/executor/create_executor.cpp b/src/executor/create_executor.cpp index bbd3e773d43..9bd21ddaceb 100644 --- a/src/executor/create_executor.cpp +++ b/src/executor/create_executor.cpp @@ -13,7 +13,6 @@ #include "executor/create_executor.h" #include "catalog/catalog.h" -#include "catalog/foreign_key.h" #include "catalog/system_catalogs.h" #include "concurrency/transaction_context.h" #include "executor/executor_context.h" @@ -130,89 +129,130 @@ bool CreateExecutor::CreateTable(const planner::CreatePlan &node) { if (current_txn->GetResult() == ResultType::SUCCESS) { LOG_TRACE("Creating table succeeded!"); + auto catalog = catalog::Catalog::GetInstance(); + auto source_table = catalog->GetTableWithName(current_txn, + database_name, + schema_name, + table_name); + // Add the primary key constraint + if (node.HasPrimaryKey()) { + auto pk = node.GetPrimaryKey(); + std::vector col_ids; + for (auto col_name : pk.primary_key_cols) { + oid_t col_id = source_table->GetSchema()->GetColumnID(col_name); + if (col_id == INVALID_OID) { + std::string error = StringUtil::Format( + "Invalid key column name '%s.%s' for primary key '%s'", + table_name.c_str(), col_name.c_str(), pk.constraint_name.c_str()); + throw ExecutorException(error); + } + col_ids.push_back(col_id); + } + PELOTON_ASSERT(col_ids.size() == pk.primary_key_cols.size()); + + // Create the catalog object and shove it into the table + catalog->AddPrimaryKeyConstraint(current_txn, + source_table->GetDatabaseOid(), + source_table->GetOid(), + col_ids, + pk.constraint_name); + } - // Add the foreign key constraint (or other multi-column constraints) - if (node.GetForeignKeys().empty() == false) { - int count = 1; - auto catalog = catalog::Catalog::GetInstance(); - auto source_table = catalog->GetTableWithName(current_txn, - database_name, - schema_name, - table_name); - - for (auto fk : node.GetForeignKeys()) { - auto sink_table = catalog->GetTableWithName(current_txn, - database_name, - schema_name, - fk.sink_table_name); - // Source Column Offsets - std::vector source_col_ids; - for (auto col_name : fk.foreign_key_sources) { - oid_t col_id = source_table->GetSchema()->GetColumnID(col_name); - if (col_id == INVALID_OID) { - std::string error = StringUtil::Format( - "Invalid source column name '%s.%s' for foreign key '%s'", - table_name.c_str(), col_name.c_str(), - fk.constraint_name.c_str()); - throw ExecutorException(error); - } - source_col_ids.push_back(col_id); - } // FOR - PELOTON_ASSERT(source_col_ids.size() == fk.foreign_key_sources.size()); - - // Sink Column Offsets - std::vector sink_col_ids; - for (auto col_name : fk.foreign_key_sinks) { - oid_t col_id = sink_table->GetSchema()->GetColumnID(col_name); - if (col_id == INVALID_OID) { - std::string error = StringUtil::Format( - "Invalid sink column name '%s.%s' for foreign key '%s'", - sink_table->GetName().c_str(), col_name.c_str(), - fk.constraint_name.c_str()); - throw ExecutorException(error); - } - sink_col_ids.push_back(col_id); - } // FOR - PELOTON_ASSERT(sink_col_ids.size() == fk.foreign_key_sinks.size()); - - // Create the catalog object and shove it into the table - auto catalog_fk = new catalog::ForeignKey( - INVALID_OID, sink_table->GetOid(), sink_col_ids, source_col_ids, - fk.upd_action, fk.del_action, fk.constraint_name); - source_table->AddForeignKey(catalog_fk); - - // Register FK with the sink table for delete/update actions - catalog_fk = new catalog::ForeignKey( - source_table->GetOid(), INVALID_OID, sink_col_ids, source_col_ids, - fk.upd_action, fk.del_action, fk.constraint_name); - sink_table->RegisterForeignKeySource(catalog_fk); - - // Add a non-unique index on the source table if needed - std::vector source_col_names = fk.foreign_key_sources; - std::string index_name = table_name + "_FK_" + sink_table->GetName() + - "_" + std::to_string(count); - catalog->CreateIndex(current_txn, - database_name, - schema_name, - table_name, - index_name, - source_col_ids, - false, - IndexType::BWTREE); - count++; - -#ifdef LOG_DEBUG_ENABLED - LOG_DEBUG("Added a FOREIGN index on in %s.\n", table_name.c_str()); - LOG_DEBUG("Foreign key column names: \n"); - for (auto c : source_col_names) { - LOG_DEBUG("FK col name: %s\n", c.c_str()); + // Add the unique constraint + for (auto unique : node.GetUniques()) { + std::vector col_ids; + for (auto col_name : unique.unique_cols) { + oid_t col_id = source_table->GetSchema()->GetColumnID(col_name); + if (col_id == INVALID_OID) { + std::string error = StringUtil::Format( + "Invalid key column name '%s.%s' for unique '%s'", + table_name.c_str(), col_name.c_str(), + unique.constraint_name.c_str()); + throw ExecutorException(error); } - for (auto c : fk.foreign_key_sinks) { - LOG_DEBUG("FK sink col name: %s\n", c.c_str()); + col_ids.push_back(col_id); + } + PELOTON_ASSERT(col_ids.size() == unique.unique_cols.size()); + + // Create the catalog object and shove it into the table + catalog->AddUniqueConstraint(current_txn, + source_table->GetDatabaseOid(), + source_table->GetOid(), + col_ids, + unique.constraint_name); + } + + // Add the foreign key constraint + for (auto fk : node.GetForeignKeys()) { + auto sink_table = catalog->GetTableWithName(current_txn, + database_name, + schema_name, + fk.sink_table_name); + // Source Column Offsets + std::vector source_col_ids; + for (auto col_name : fk.foreign_key_sources) { + oid_t col_id = source_table->GetSchema()->GetColumnID(col_name); + if (col_id == INVALID_OID) { + std::string error = StringUtil::Format( + "Invalid source column name '%s.%s' for foreign key '%s'", + table_name.c_str(), col_name.c_str(), fk.constraint_name.c_str()); + throw ExecutorException(error); } -#endif + source_col_ids.push_back(col_id); + } // FOR + PELOTON_ASSERT(source_col_ids.size() == fk.foreign_key_sources.size()); + + // Sink Column Offsets + std::vector sink_col_ids; + for (auto col_name : fk.foreign_key_sinks) { + oid_t col_id = sink_table->GetSchema()->GetColumnID(col_name); + if (col_id == INVALID_OID) { + std::string error = StringUtil::Format( + "Invalid sink column name '%s.%s' for foreign key '%s'", + sink_table->GetName().c_str(), col_name.c_str(), + fk.constraint_name.c_str()); + throw ExecutorException(error); + } + sink_col_ids.push_back(col_id); + } // FOR + PELOTON_ASSERT(sink_col_ids.size() == fk.foreign_key_sinks.size()); + + // Create the catalog object and shove it into the table + catalog->AddForeignKeyConstraint(current_txn, + source_table->GetDatabaseOid(), + source_table->GetOid(), + source_col_ids, + sink_table->GetOid(), + sink_col_ids, + fk.upd_action, + fk.del_action, + fk.constraint_name); + } + + // Add the check constraint + for (auto check : node.GetChecks()) { + std::vector col_ids; + for (auto col_name : check.check_cols) { + oid_t col_id = source_table->GetSchema()->GetColumnID(col_name); + if (col_id == INVALID_OID) { + std::string error = StringUtil::Format( + "Invalid key column name '%s.%s' for unique '%s'", + table_name.c_str(), col_name.c_str(), + check.constraint_name.c_str()); + throw ExecutorException(error); + } + col_ids.push_back(col_id); } + PELOTON_ASSERT(col_ids.size() == check.check_cols.size()); + + // Create the catalog object and shove it into the table + catalog->AddCheckConstraint(current_txn, + source_table->GetDatabaseOid(), + source_table->GetOid(), + col_ids, check.exp, + check.constraint_name); } + } else if (current_txn->GetResult() == ResultType::FAILURE) { LOG_TRACE("Creating table failed!"); } else { @@ -271,8 +311,7 @@ bool CreateExecutor::CreateTrigger(const planner::CreatePlan &node) { // catalog table auto time_stamp = type::ValueFactory::GetTimestampValue( std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()) - .count()); + std::chrono::system_clock::now().time_since_epoch()).count()); CopySerializeOutput output; newTrigger.SerializeWhen(output, table_object->GetDatabaseOid(), diff --git a/src/executor/update_executor.cpp b/src/executor/update_executor.cpp index f387e674974..0c80039fc54 100644 --- a/src/executor/update_executor.cpp +++ b/src/executor/update_executor.cpp @@ -23,7 +23,6 @@ #include "storage/tile_group_header.h" #include "storage/tile.h" #include "storage/storage_manager.h" -#include "catalog/foreign_key.h" namespace peloton { namespace executor { @@ -119,7 +118,7 @@ bool UpdateExecutor::PerformUpdatePrimaryKey( } // Check the source table of any foreign key constraint - if (target_table_->GetForeignKeySrcCount() > 0) { + if (target_table_->GetSchema()->HasForeignKeySources()) { storage::Tuple prev_tuple(target_table_schema, true); // Get a copy of the old tuple for (oid_t column_itr = 0; column_itr < target_table_schema->GetColumnCount(); column_itr++) { diff --git a/src/include/catalog/catalog.h b/src/include/catalog/catalog.h index 5940f162864..03cc2a1abbb 100644 --- a/src/include/catalog/catalog.h +++ b/src/include/catalog/catalog.h @@ -20,6 +20,7 @@ namespace peloton { namespace catalog { +class Constraint; class Schema; class DatabaseCatalogEntry; class TableCatalogEntry; @@ -124,12 +125,14 @@ class Catalog { const std::string &schema_name, oid_t table_oid, bool is_catalog, + oid_t index_oid, const std::string &index_name, const std::vector &key_attrs, bool unique_keys, IndexType index_type, IndexConstraintType index_constraint); + /** * @brief create a new layout for a table * @param database_oid database to which the table belongs to @@ -159,6 +162,60 @@ class Catalog { oid_t table_oid, const column_map_type &column_map); + //===--------------------------------------------------------------------===// + // SET FUNCTIONS FOR COLUMN CONSTRAINT + //===--------------------------------------------------------------------===// + + // Set not null constraint for a column + ResultType SetNotNullConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, + oid_t table_oid, + oid_t column_id); + + // Set default constraint for a column + ResultType SetDefaultConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, + oid_t table_oid, + oid_t column_id, + const type::Value &default_value); + + //===--------------------------------------------------------------------===// + // ADD FUNCTIONS FOR TABLE CONSTRAINT + //===--------------------------------------------------------------------===// + + // Add a new primary constraint for a table + ResultType AddPrimaryKeyConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, + oid_t table_oid, + const std::vector &column_ids, + const std::string &constraint_name); + + // Add a new unique constraint for a table + ResultType AddUniqueConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, + oid_t table_oid, + const std::vector &column_ids, + const std::string &constraint_name); + + // Add a new foreign key constraint for a table + ResultType AddForeignKeyConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, + oid_t src_table_oid, + const std::vector &src_col_ids, + oid_t sink_table_oid, + const std::vector &sink_col_ids, + FKConstrActionType upd_action, + FKConstrActionType del_action, + const std::string &constraint_name); + + // Add a new check constraint for a table + ResultType AddCheckConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, + oid_t table_oid, + const std::vector &column_ids, + const std::pair &exp, + const std::string &constraint_name); + //===--------------------------------------------------------------------===// // DROP FUNCTIONS //===--------------------------------------------------------------------===// @@ -203,6 +260,25 @@ class Catalog { oid_t database_oid, oid_t table_oid, oid_t layout_oid); + + // Drop not null constraint for a column + ResultType DropNotNullConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, + oid_t table_oid, + oid_t column_id); + + // Drop default constraint for a column + ResultType DropDefaultConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, + oid_t table_oid, + oid_t column_id); + + // Drop constraint for a table + ResultType DropConstraint(concurrency::TransactionContext *txn, + oid_t database_oid, + oid_t table_oid, + oid_t constraint_oid); + //===--------------------------------------------------------------------===// // GET WITH NAME - CHECK FROM CATALOG TABLES, USING TRANSACTION //===--------------------------------------------------------------------===// @@ -296,13 +372,6 @@ class Catalog { void BootstrapSystemCatalogs(concurrency::TransactionContext *txn, storage::Database *database); - // Create the primary key index for a table, don't call this function outside - // catalog.cpp - ResultType CreatePrimaryIndex(concurrency::TransactionContext *txn, - oid_t database_oid, - const std::string &schema_name, - oid_t table_oid); - // The pool for new varlen tuple fields std::unique_ptr pool_; std::mutex catalog_mutex; diff --git a/src/include/catalog/catalog_defaults.h b/src/include/catalog/catalog_defaults.h index d8afd1a16d6..4a3a5bcd1b2 100644 --- a/src/include/catalog/catalog_defaults.h +++ b/src/include/catalog/catalog_defaults.h @@ -33,11 +33,12 @@ namespace catalog { #define INDEX_CATALOG_NAME "pg_index" #define COLUMN_CATALOG_NAME "pg_attribute" #define LAYOUT_CATALOG_NAME "pg_layout" +#define CONSTRAINT_CATALOG_NAME "pg_constraint" // Local oids from START_OID = 0 to START_OID + OID_OFFSET are reserved #define OID_OFFSET 100 #define OID_FOR_USER_OFFSET 10000 -#define CATALOG_TABLES_COUNT 9 +#define CATALOG_TABLES_COUNT 10 // Oid mask for each type #define DATABASE_OID_MASK (static_cast(catalog::CatalogType::DATABASE)) @@ -47,6 +48,7 @@ namespace catalog { #define TRIGGER_OID_MASK (static_cast(catalog::CatalogType::TRIGGER)) #define LANGUAGE_OID_MASK (static_cast(catalog::CatalogType::LANGUAGE)) #define PROC_OID_MASK (static_cast(catalog::CatalogType::PROC)) +#define CONSTRAINT_OID_MASK (static_cast(catalog::CatalogType::CONSTRAINT)) // Reserved peloton database oid #define CATALOG_DATABASE_OID (0 | DATABASE_OID_MASK) @@ -69,6 +71,7 @@ namespace catalog { #define INDEX_CATALOG_OID (3 | TABLE_OID_MASK) #define COLUMN_CATALOG_OID (4 | TABLE_OID_MASK) #define LAYOUT_CATALOG_OID (5 | TABLE_OID_MASK) +#define CONSTRAINT_CATALOG_OID (6 | TABLE_OID_MASK) // Reserved pg_column index oid #define COLUMN_CATALOG_PKEY_OID (0 | INDEX_OID_MASK) @@ -97,6 +100,36 @@ namespace catalog { #define LAYOUT_CATALOG_PKEY_OID (13 | INDEX_OID_MASK) #define LAYOUT_CATALOG_SKEY0_OID (14 | INDEX_OID_MASK) +// Reserve pg_constraint index oid +#define CONSTRAINT_CATALOG_PKEY_OID (15 | INDEX_OID_MASK) +#define CONSTRAINT_CATALOG_SKEY0_OID (16 | INDEX_OID_MASK) + +// Reserved pg_column constraint oid +#define COLUMN_CATALOG_CON_PKEY_OID (0 | CONSTRAINT_OID_MASK) +#define COLUMN_CATALOG_CON_UNI0_OID (1 | CONSTRAINT_OID_MASK) + +// Reserved pg_index index oid +#define INDEX_CATALOG_CON_PKEY_OID (2 | CONSTRAINT_OID_MASK) +#define INDEX_CATALOG_CON_UNI0_OID (3 | CONSTRAINT_OID_MASK) + +// Reserved pg_database index oid +#define DATABASE_CATALOG_CON_PKEY_OID (4 | CONSTRAINT_OID_MASK) +#define DATABASE_CATALOG_CON_UNI0_OID (5 | CONSTRAINT_OID_MASK) + +// Reserved pg_namespace index oid +#define SCHEMA_CATALOG_CON_PKEY_OID (6 | CONSTRAINT_OID_MASK) +#define SCHEMA_CATALOG_CON_UNI0_OID (7 | CONSTRAINT_OID_MASK) + +// Reserved pg_table index oid +#define TABLE_CATALOG_CON_PKEY_OID (8 | CONSTRAINT_OID_MASK) +#define TABLE_CATALOG_CON_UNI0_OID (9 | CONSTRAINT_OID_MASK) + +// Reserve pg_layout index oid +#define LAYOUT_CATALOG_CON_PKEY_OID (10 | CONSTRAINT_OID_MASK) + +// Reserve pg_constraint index oid +#define CONSTRAINT_CATALOG_CON_PKEY_OID (11 | CONSTRAINT_OID_MASK) + // Use upper 8 bits indicating catalog type #define CATALOG_TYPE_OFFSET 24 @@ -110,6 +143,7 @@ enum class CatalogType : uint32_t { TRIGGER = 6 << CATALOG_TYPE_OFFSET, LANGUAGE = 7 << CATALOG_TYPE_OFFSET, PROC = 8 << CATALOG_TYPE_OFFSET, + CONSTRAINT = 9 << CATALOG_TYPE_OFFSET, // To be added }; diff --git a/src/include/catalog/column.h b/src/include/catalog/column.h index a8741247648..7aa0fd13192 100644 --- a/src/include/catalog/column.h +++ b/src/include/catalog/column.h @@ -36,7 +36,7 @@ class Column : public Printable { Column(type::TypeId value_type, size_t column_length, std::string column_name, bool is_inlined = false, oid_t column_offset = INVALID_OID) - : column_name(column_name), + : column_name_(column_name), column_type_(value_type), fixed_length_(INVALID_OID), is_inlined_(is_inlined), @@ -61,47 +61,52 @@ class Column : public Printable { // Set the appropriate column length void SetLength(size_t column_length); - oid_t GetOffset() const { return column_offset_; } + inline oid_t GetOffset() const { return column_offset_; } - std::string GetName() const { return column_name; } + inline std::string GetName() const { return column_name_; } - size_t GetLength() const { + inline size_t GetLength() const { if (is_inlined_) return fixed_length_; else return variable_length_; } - size_t GetFixedLength() const { return fixed_length_; } + inline size_t GetFixedLength() const { return fixed_length_; } - size_t GetVariableLength() const { return variable_length_; } + inline size_t GetVariableLength() const { return variable_length_; } inline type::TypeId GetType() const { return column_type_; } inline bool IsInlined() const { return is_inlined_; } - inline bool IsPrimary() const { return is_primary_; } + // Constraint check functions for NOT NULL and DEFAULT + inline bool IsNotNull() const { return is_not_null_; } - inline bool IsUnique() const { return is_unique_; } + inline bool HasDefault() const { return has_default_; } - // Add a constraint to the column - void AddConstraint(const catalog::Constraint &constraint) { - if (constraint.GetType() == ConstraintType::DEFAULT) { - // Add the default constraint to the front - constraints_.insert(constraints_.begin(), constraint); - } else { - constraints_.push_back(constraint); - } + // Manage NOT NULL constraint + inline void SetNotNull() { is_not_null_ = true; } - if (constraint.GetType() == ConstraintType::PRIMARY) { - is_primary_ = true; - } - if (constraint.GetType() == ConstraintType::UNIQUE) { - is_unique_ = true; + inline void ClearNotNull() { is_not_null_ = false; } + + // Manage DEFAULT constraint + inline void SetDefaultValue(const type::Value &value) { + if (default_value_.get() != nullptr) { + return; } + default_value_.reset(new type::Value(value)); + has_default_ = true; } - const std::vector &GetConstraints() const { return constraints_; } + inline std::shared_ptr GetDefaultValue() const { + return default_value_; + } + + inline void ClearDefaultValue() { + default_value_.reset(); + has_default_ = false; + } hash_t Hash() const { hash_t hash = HashUtil::Hash(&column_type_); @@ -110,7 +115,8 @@ class Column : public Printable { // Compare two column objects bool operator==(const Column &other) const { - if (other.column_type_ != column_type_ || other.is_inlined_ != is_inlined_) { + if (other.column_type_ != column_type_ || + other.is_inlined_ != is_inlined_) { return false; } return true; @@ -121,14 +127,14 @@ class Column : public Printable { // Get a string representation for debugging const std::string GetInfo() const; - // name of the column - std::string column_name; - //===--------------------------------------------------------------------===// // MEMBERS //===--------------------------------------------------------------------===// private: + // name of the column + std::string column_name_; + // value type of column type::TypeId column_type_; // = type::TypeId::INVALID; @@ -143,17 +149,17 @@ class Column : public Printable { // is the column inlined ? bool is_inlined_ = false; - // is the column contained the primary key? - bool is_primary_ = false; + // is the column allowed null + bool is_not_null_ = false; + + // does the column have the default value + bool has_default_ = false; - // is the column unique - bool is_unique_ = false; + // default value + std::shared_ptr default_value_; // offset of column in tuple oid_t column_offset_ = INVALID_OID; - - // Constraints - std::vector constraints_; }; } // namespace catalog diff --git a/src/include/catalog/column_catalog.h b/src/include/catalog/column_catalog.h index 490855822f1..72b14a052f8 100644 --- a/src/include/catalog/column_catalog.h +++ b/src/include/catalog/column_catalog.h @@ -49,8 +49,9 @@ class ColumnCatalogEntry { inline type::TypeId GetColumnType() { return column_type_; } inline size_t GetColumnLength() { return column_length_; } inline bool IsInlined() { return is_inlined_; } - inline bool IsPrimary() { return is_primary_; } inline bool IsNotNull() { return is_not_null_; } + inline bool HasDefault() { return has_default_; } + inline const type::Value &GetDefaultValue() { return default_value_; } private: // member variables @@ -61,8 +62,9 @@ class ColumnCatalogEntry { type::TypeId column_type_; size_t column_length_; bool is_inlined_; - bool is_primary_; bool is_not_null_; + bool has_default_; + type::Value default_value_; }; class ColumnCatalog : public AbstractCatalog { @@ -87,13 +89,15 @@ class ColumnCatalog : public AbstractCatalog { //===--------------------------------------------------------------------===// bool InsertColumn(concurrency::TransactionContext *txn, oid_t table_oid, - oid_t column_id, const std::string &column_name, + oid_t column_id, oid_t column_offset, type::TypeId column_type, size_t column_length, - const std::vector &constraints, bool is_inlined, + bool is_not_null, + bool is_default, + const std::shared_ptr default_value, type::AbstractPool *pool); bool DeleteColumn(concurrency::TransactionContext *txn, @@ -102,6 +106,17 @@ class ColumnCatalog : public AbstractCatalog { bool DeleteColumns(concurrency::TransactionContext *txn, oid_t table_oid); + bool UpdateNotNullConstraint(concurrency::TransactionContext *txn, + oid_t table_oid, + const std::string &column_name, + bool is_not_null); + + bool UpdateDefaultConstraint(concurrency::TransactionContext *txn, + oid_t table_oid, + const std::string &column_name, + bool has_default, + const type::Value *default_value); + private: //===--------------------------------------------------------------------===// // Read Related API(only called within table catalog object) @@ -120,11 +135,13 @@ class ColumnCatalog : public AbstractCatalog { COLUMN_TYPE = 4, COLUMN_LENGTH = 5, IS_INLINED = 6, - IS_PRIMARY = 7, - IS_NOT_NULL = 8, + IS_NOT_NULL = 7, + HAS_DEFAULT = 8, + DEFAULT_VALUE_SRC = 9, + DEFAULT_VALUE_BIN = 10, // Add new columns here in creation order }; - std::vector all_column_ids_ = {0, 1, 2, 3, 4, 5, 6, 7, 8}; + std::vector all_column_ids_ = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; enum IndexId { PRIMARY_KEY = 0, diff --git a/src/include/catalog/constraint.h b/src/include/catalog/constraint.h index 7f67b1f78b6..72c5076a1ba 100644 --- a/src/include/catalog/constraint.h +++ b/src/include/catalog/constraint.h @@ -30,79 +30,108 @@ namespace catalog { class Constraint : public Printable { public: - Constraint(ConstraintType type, std::string constraint_name) - : constraint_type_(type), constraint_name_(std::move(constraint_name)) {} - Constraint(ConstraintType type, std::string constraint_name, - std::string check_cmd) - : constraint_type_(type), - constraint_name_(std::move(constraint_name)), - check_cmd_(std::move(check_cmd)) {} + // Constructor for primary key or unique + Constraint(oid_t constraint_oid, ConstraintType type, + std::string constraint_name, oid_t table_oid, + std::vector column_ids, oid_t index_oid) + : constraint_oid_(constraint_oid), constraint_name_(constraint_name), + constraint_type_(type), table_oid_(table_oid), + column_ids_(column_ids), index_oid_(index_oid) {} + + // Constructor for foreign key constraint + Constraint(oid_t constraint_oid, ConstraintType type, + std::string constraint_name, oid_t table_oid, + std::vector column_ids,oid_t index_oid, oid_t sink_table_oid, + std::vector sink_col_ids, FKConstrActionType update_action, + FKConstrActionType delete_action) + : constraint_oid_(constraint_oid), constraint_name_(constraint_name), + constraint_type_(type), table_oid_(table_oid), + column_ids_(column_ids), index_oid_(index_oid), + fk_sink_table_oid_(sink_table_oid), fk_sink_col_ids_(sink_col_ids), + fk_update_action_(update_action), fk_delete_action_(delete_action) {} + + // Constructor for check constraint + Constraint(oid_t constraint_oid, ConstraintType type, + std::string constraint_name, oid_t table_oid, + std::vector column_ids, oid_t index_oid, + std::pair exp) + : constraint_oid_(constraint_oid), constraint_name_(constraint_name), + constraint_type_(type), table_oid_(table_oid), column_ids_(column_ids), + index_oid_(index_oid), check_exp_(exp) {} //===--------------------------------------------------------------------===// // ACCESSORS //===--------------------------------------------------------------------===// - ConstraintType GetType() const { return constraint_type_; } + // Set oid for catalog + void SetConstraintOid(oid_t oid) { constraint_oid_ = oid; } - std::pair GetCheckExpression() { return exp_; } + inline oid_t GetConstraintOid() const { return constraint_oid_; } - // Offset into the list of "reference tables" in the Table. - void SetForeignKeyListOffset(oid_t offset) { fk_list_offset_ = offset; } + inline ConstraintType GetType() const { return constraint_type_; } - // Offset into the list of "unique indices" in the Table. - void SetUniqueIndexOffset(oid_t offset) { - unique_index_list_offset_ = offset; - } + // Get the table oid + inline oid_t GetTableOid() const { return table_oid_; } - // Get the offset - oid_t GetForeignKeyListOffset() const { return fk_list_offset_; } + // Get the column ids + inline const std::vector &GetColumnIds() const { return column_ids_; } - // Get the offset - oid_t GetUniqueIndexOffset() const { return unique_index_list_offset_; } + // Set index oid indicating the index constructing the constraint + void SetIndexOid(oid_t oid) { index_oid_ = oid; } - std::string GetName() const { return constraint_name_; } + // Get the index oid + inline oid_t GetIndexOid() const { return index_oid_; } + + inline std::string GetName() const { return constraint_name_; } // Get a string representation for debugging const std::string GetInfo() const override; - // Todo: default union data structure, - // For default constraint - void addDefaultValue(const type::Value &value) { - if (constraint_type_ != ConstraintType::DEFAULT - || default_value_.get() != nullptr) return; - default_value_.reset(new peloton::type::Value(value)); - } + inline oid_t GetFKSinkTableOid() const { return fk_sink_table_oid_; } + + inline const std::vector &GetFKSinkColumnIds() const { return fk_sink_col_ids_; } + + inline FKConstrActionType GetFKUpdateAction() const { return fk_update_action_; } - type::Value *getDefaultValue() { - return default_value_.get(); - } + inline FKConstrActionType GetFKDeleteAction() const { return fk_delete_action_; } - // Add check constrain - void AddCheck(ExpressionType op, peloton::type::Value val) { - exp_ = std::pair(op, val); - }; + inline std::pair GetCheckExpression() const { return check_exp_; } private: //===--------------------------------------------------------------------===// // MEMBERS //===--------------------------------------------------------------------===// + // constraint oid created by catalog + oid_t constraint_oid_; + + std::string constraint_name_; + // The type of constraint - ConstraintType constraint_type_ = ConstraintType::INVALID; + ConstraintType constraint_type_; - // Offsets into the Unique index and reference table lists in Table - oid_t fk_list_offset_ = INVALID_OID; + // Table having this constraints + oid_t table_oid_; - oid_t unique_index_list_offset_ = INVALID_OID; + // Column ids related the constraint + std::vector column_ids_; - std::string constraint_name_; + // Index constructing the constraint + oid_t index_oid_; + + // foreign key constraint information + // The reference table (sink) + oid_t fk_sink_table_oid_ = INVALID_OID; + + // Column ids in the reference table (sink) + std::vector fk_sink_col_ids_; - std::shared_ptr default_value_; + FKConstrActionType fk_update_action_ = FKConstrActionType::NOACTION; - std::string check_cmd_ = ""; + FKConstrActionType fk_delete_action_ = FKConstrActionType::NOACTION; - // key string is column name - std::pair exp_; + // key string is column name for check constraint + std::pair check_exp_; }; } // namespace catalog diff --git a/src/include/catalog/constraint_catalog.h b/src/include/catalog/constraint_catalog.h new file mode 100644 index 00000000000..a64ec5e3a75 --- /dev/null +++ b/src/include/catalog/constraint_catalog.h @@ -0,0 +1,156 @@ +//===----------------------------------------------------------------------===// +// +// Peloton +// +// constraint_catalog.h +// +// Identification: src/include/catalog/constraint_catalog.h +// +// Copyright (c) 2015-17, Carnegie Mellon University Database Group +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// pg_constraint +// +// Schema: (column offset: column_name) +// 0: constraint_oid (pkey) +// 1: constraint_name (name of the constraint, not unique!) +// 2: constraint_type (type of the constraint) +// 3: table_oid (table created for the constraint) +// 4: column_ids (list of column id related to the constraint) +// 5: index_oid (index created for the constraint) +// 6: fk_sink_table_oid (for FOREIGN KEY) +// 7: fk_sink_col_ids (for FOREIGN KEY) +// 8: fk_update_action (for FOREIGN KEY) +// 9: fk_delete_action (for FOREIGN KEY) +// 10: default_value (for DEFAULT) +// 11: check_cmd (for CHECK) +// 12: check_exp (for CHECK) +// +// Indexes: (index offset: indexed columns) +// 0: constraint_oid (unique & primary key) +// 1: table_oid (non-unique) +// +// Note: Exclusive constraint is not supported yet +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "catalog/abstract_catalog.h" +#include "executor/logical_tile.h" + +namespace peloton { +namespace catalog { + +class Constraint; + +class ConstraintCatalogEntry { + friend class ConstraintCatalog; + + public: + ConstraintCatalogEntry(executor::LogicalTile *tile, int tupleId = 0); + + inline oid_t GetConstraintOid() { return constraint_oid_; } + inline const std::string &GetConstraintName() { return constraint_name_; } + inline ConstraintType GetConstraintType() { return constraint_type_; } + inline oid_t GetTableOid() { return table_oid_; } + inline const std::vector &GetColumnIds() { return column_ids_; } + inline oid_t GetIndexOid() { return index_oid_; } + inline oid_t GetFKSinkTableOid() { return fk_sink_table_oid_; } + inline const std::vector &GetFKSinkColumnIds() { + return fk_sink_col_ids_; + } + inline FKConstrActionType GetFKUpdateAction() { return fk_update_action_; } + inline FKConstrActionType GetFKDeleteAction() { return fk_delete_action_; } + inline const std::pair &GetCheckExp() { + return check_exp_; + } + + private: + // member variables + oid_t constraint_oid_; + std::string constraint_name_; + ConstraintType constraint_type_; + oid_t table_oid_; + std::vector column_ids_; + oid_t index_oid_; + oid_t fk_sink_table_oid_; + std::vector fk_sink_col_ids_; + FKConstrActionType fk_update_action_; + FKConstrActionType fk_delete_action_; + std::pair check_exp_; +}; + +class ConstraintCatalog : public AbstractCatalog { + friend class ConstraintCatalogEntry; + friend class TableCatalogEntry; + friend class Catalog; + + public: + ConstraintCatalog(concurrency::TransactionContext *txn, + storage::Database *pg_catalog, + type::AbstractPool *pool); + + ~ConstraintCatalog(); + + inline oid_t GetNextOid() { return oid_++ | CONSTRAINT_OID_MASK; } + + void UpdateOid(oid_t add_value) { oid_ += add_value; } + + //===--------------------------------------------------------------------===// + // write Related API + //===--------------------------------------------------------------------===// + bool InsertConstraint(concurrency::TransactionContext *txn, + const std::shared_ptr constraint, + type::AbstractPool *pool); + + bool DeleteConstraints(concurrency::TransactionContext *txn, + oid_t table_oid); + + bool DeleteConstraint(concurrency::TransactionContext *txn, + oid_t table_oid, + oid_t constraint_oid); + + private: + //===--------------------------------------------------------------------===// + // Read Related API(only called within table catalog object) + //===--------------------------------------------------------------------===// + const std::unordered_map> + GetConstraintCatalogEntries(concurrency::TransactionContext *txn, + oid_t table_oid); + + const std::shared_ptr + GetConstraintCatalogEntry(concurrency::TransactionContext *txn, + oid_t table_oid, + oid_t constraint_oid); + + std::unique_ptr InitializeSchema(); + + enum ColumnId { + CONSTRAINT_OID = 0, + CONSTRAINT_NAME = 1, + CONSTRAINT_TYPE = 2, + TABLE_OID = 3, + COLUMN_IDS = 4, + INDEX_OID = 5, + FK_SINK_TABLE_OID = 6, + FK_SINK_COL_IDS = 7, + FK_UPDATE_ACTION = 8, + FK_DELETE_ACTION = 9, + CHECK_EXP_SRC = 10, + CHECK_EXP_BIN = 11, + // Add new columns here in creation order + }; + std::vector all_column_ids_ = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + + enum IndexId { + PRIMARY_KEY = 0, + SKEY_TABLE_OID = 1, + // Add new indexes here in creation order + }; +}; + +} // namespace catalog +} // namespace peloton diff --git a/src/include/catalog/foreign_key.h b/src/include/catalog/foreign_key.h deleted file mode 100644 index 1fb745560e7..00000000000 --- a/src/include/catalog/foreign_key.h +++ /dev/null @@ -1,76 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Peloton -// -// foreign_key.h -// -// Identification: src/include/catalog/foreign_key.h -// -// Copyright (c) 2015-16, Carnegie Mellon University Database Group -// -//===----------------------------------------------------------------------===// - - -#pragma once - -#include -#include - -#include "common/internal_types.h" - -namespace peloton { -namespace catalog { - -//===--------------------------------------------------------------------===// -// Foreign Key Class -//===--------------------------------------------------------------------===// - -// Stores info about foreign key constraints, like the sink table id etc. -class ForeignKey { - public: - ForeignKey(oid_t source_table_id, - oid_t sink_table_id, - std::vector sink_col_ids, - std::vector source_col_ids, - FKConstrActionType update_action, - FKConstrActionType delete_action, - std::string constraint_name) - - : source_table_id_(source_table_id), - sink_table_id_(sink_table_id), - sink_col_ids_(sink_col_ids), - source_col_ids_(source_col_ids), - update_action_(update_action), - delete_action_(delete_action), - fk_name_(constraint_name) {} - - oid_t GetSourceTableOid() const { return source_table_id_; } - oid_t GetSinkTableOid() const { return sink_table_id_; } - - std::vector GetSinkColumnIds() const { return sink_col_ids_; } - std::vector GetSourceColumnIds() const { return source_col_ids_; } - - FKConstrActionType GetUpdateAction() const { return update_action_; } - FKConstrActionType GetDeleteAction() const { return delete_action_; } - std::string &GetConstraintName() { return fk_name_; } - - private: - oid_t source_table_id_ = INVALID_OID; - oid_t sink_table_id_ = INVALID_OID; - - // Columns in the reference table (sink) - std::vector sink_col_ids_; - - // Columns in the current table (source) - // Can be a single column or multiple columns depending - // on the constraint - std::vector source_col_ids_; - - FKConstrActionType update_action_; - FKConstrActionType delete_action_; - - std::string fk_name_; -}; - -} // namespace catalog -} // namespace peloton diff --git a/src/include/catalog/layout_catalog.h b/src/include/catalog/layout_catalog.h index babdb346583..616d0335b55 100644 --- a/src/include/catalog/layout_catalog.h +++ b/src/include/catalog/layout_catalog.h @@ -23,6 +23,7 @@ class Layout; namespace catalog { class LayoutCatalog : public AbstractCatalog { + friend class Catalog; public: LayoutCatalog(concurrency::TransactionContext *txn, @@ -75,4 +76,4 @@ class LayoutCatalog : public AbstractCatalog { }; } // namespace catalog -} // namespace peloton \ No newline at end of file +} // namespace peloton diff --git a/src/include/catalog/multi_constraint.h b/src/include/catalog/multi_constraint.h deleted file mode 100644 index 46b254ed90e..00000000000 --- a/src/include/catalog/multi_constraint.h +++ /dev/null @@ -1,70 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Peloton -// -// multi_constraint.h -// -// Identification: src/include/catalog/multi_constraint.h -// -// Copyright (c) 2015-2017, Carnegie Mellon University Database Group -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include -#include -#include - -#include "common/printable.h" -#include "common/internal_types.h" -#include "type/value.h" - -namespace peloton { -namespace catalog { - -//===--------------------------------------------------------------------===// -// MultiConstraint Class -//===--------------------------------------------------------------------===// - -class MultiConstraint : public Printable { - public: - MultiConstraint(ConstraintType type, std::string constraint_name) - : constraint_type_(type), constraint_name_(constraint_name){}; - - MultiConstraint(ConstraintType type, std::string constraint_name, - std::vector column_ids) - : constraint_type_(type), constraint_name_(constraint_name) { - this->column_ids_ = column_ids; - }; - - //===--------------------------------------------------------------------===// - // ACCESSORS - //===--------------------------------------------------------------------===// - - ConstraintType GetType() const { return constraint_type_; } - - std::string GetName() const { return constraint_name_; } - - // Get a string representation for debugging - const std::string GetInfo() const; - - std::vector GetCols() const { return column_ids_; } - - private: - //===--------------------------------------------------------------------===// - // MEMBERS - //===--------------------------------------------------------------------===// - - // The type of constraint - ConstraintType constraint_type_ = ConstraintType::INVALID; - - // constraints on column set - std::vector column_ids_; - - // we do not allow duplicate constraint name in single table - std::string constraint_name_; -}; - -} // namespace catalog -} // namespace peloton diff --git a/src/include/catalog/schema.h b/src/include/catalog/schema.h index e70c7636d5d..ead95e673a5 100644 --- a/src/include/catalog/schema.h +++ b/src/include/catalog/schema.h @@ -14,7 +14,7 @@ #include #include "catalog/column.h" -#include "catalog/multi_constraint.h" +#include "catalog/constraint.h" #include "common/printable.h" #include "type/type.h" #include "boost/algorithm/string.hpp" @@ -174,58 +174,146 @@ class Schema : public Printable { return indexed_columns_; } + //===--------------------------------------------------------------------===// + // Single column constraint accessors + //===--------------------------------------------------------------------===// + // Get the nullability of the column at a given index. inline bool AllowNull(const oid_t column_id) const { - for (auto constraint : columns_[column_id].GetConstraints()) { - if (constraint.GetType() == ConstraintType::NOTNULL) return false; + if (columns_[column_id].IsNotNull()) { + return false; } return true; } - // For single column default - inline bool AllowDefault(const oid_t column_id) const { - for (auto constraint : columns_[column_id].GetConstraints()) { - if (constraint.GetType() == ConstraintType::DEFAULT) { - return true; + // Set the not null for the column + inline void SetNotNull(const oid_t column_id) { + columns_[column_id].SetNotNull(); + not_null_columns_.push_back(column_id); + } + + // Drop the not null for the column + inline void DropNotNull(const oid_t column_id) { + columns_[column_id].ClearNotNull(); + for (auto itr = not_null_columns_.begin(); itr < not_null_columns_.end(); itr++) { + if (*itr == column_id) { + not_null_columns_.erase(itr); + break; } } + } - return false; + // Get not null column list + inline std::vector GetNotNullColumns() const { + return not_null_columns_; } + // For single column default + inline bool AllowDefault(const oid_t column_id) const { + return columns_[column_id].HasDefault(); + } // Get the default value for the column - inline type::Value *GetDefaultValue(const oid_t column_id) const { - for (auto constraint : columns_[column_id].GetConstraints()) { - if (constraint.GetType() == ConstraintType::DEFAULT) { - return constraint.getDefaultValue(); - } + inline type::Value* GetDefaultValue(const oid_t column_id) const { + if (columns_[column_id].HasDefault()) { + return columns_[column_id].GetDefaultValue().get(); } - return nullptr; } - // Add constraint for column by id - inline void AddConstraint(oid_t column_id, - const catalog::Constraint &constraint) { - columns_[column_id].AddConstraint(constraint); + // Set the default value for the column + inline void SetDefaultValue(const oid_t column_id, + const type::Value &default_value) { + if (columns_[column_id].HasDefault()) { + columns_[column_id].ClearDefaultValue(); + } + columns_[column_id].SetDefaultValue(default_value); + } + + // Drop the default value for the column + inline void DropDefaultValue(const oid_t column_id) { + if (columns_[column_id].HasDefault()) { + columns_[column_id].ClearDefaultValue(); + } + } + + //===--------------------------------------------------------------------===// + // Multi-column constraint accessors + //===--------------------------------------------------------------------===// + + // Add a constraint for the table + inline void AddConstraint(const std::shared_ptr constraint) { + constraints[constraint->GetConstraintOid()] = constraint; + + if (constraint->GetType() == ConstraintType::PRIMARY) { + has_primary_key_ = true; + } else if (constraint->GetType() == ConstraintType::UNIQUE) { + unique_constraint_count_++; + } else if (constraint->GetType() == ConstraintType::FOREIGN) { + fk_constraints_.push_back(constraint->GetConstraintOid()); + } } - // Add constraint for column by name - inline void AddConstraint(std::string column_name, - const catalog::Constraint &constraint) { - for (size_t column_itr = 0; column_itr < columns_.size(); column_itr++) { - if (columns_[column_itr].GetName() == column_name) { - columns_[column_itr].AddConstraint(constraint); + // Delete a constraint by id from the table + inline void DropConstraint(oid_t constraint_oid) { + if (constraints[constraint_oid]->GetType() == ConstraintType::PRIMARY) { + has_primary_key_ = false; + } else if (constraints[constraint_oid]->GetType() == ConstraintType::UNIQUE) { + unique_constraint_count_--; + } else if (constraints[constraint_oid]->GetType() == ConstraintType::FOREIGN) { + for (auto itr = fk_constraints_.begin(); itr < fk_constraints_.end(); itr++) { + if (*itr == constraint_oid) { + fk_constraints_.erase(itr); + break; + } } } + + constraints.erase(constraint_oid); } - inline void AddMultiConstraints(const catalog::MultiConstraint &mc) { - multi_constraints_.push_back(mc); + inline std::unordered_map> GetConstraints() const { + return constraints; } - inline std::vector GetMultiConstraints() { - return multi_constraints_; + inline std::shared_ptr GetConstraint(oid_t constraint_oid) const { + return constraints.at(constraint_oid); + } + + // For primary key constraints + inline bool HasPrimary() { return has_primary_key_; } + + // For unique constraints + inline bool HasUniqueConstraints() const { return (unique_constraint_count_ > 0); } + + // For foreign key constraints + inline std::vector> GetForeignKeyConstraints() { + std::vector> fks; + for (auto oid : fk_constraints_) { + PELOTON_ASSERT(constraints[oid]->GetType() == ConstraintType::FOREIGN); + fks.push_back(constraints[oid]); + } + return fks; + } + + inline bool HasForeignKeys() const { return (fk_constraints_.size() > 0); } + + inline void RegisterForeignKeySource(const std::shared_ptr constraint) { + fk_sources_.push_back(constraint); + } + + inline void DeleteForeignKeySource(const oid_t constraint_oid) { + for (auto itr = fk_sources_.begin(); itr < fk_sources_.end(); itr++) { + if ((*itr)->GetConstraintOid() == constraint_oid) { + fk_sources_.erase(itr); + break; + } + } + } + + inline bool HasForeignKeySources() const { return (fk_sources_.size() > 0); } + + inline std::vector> GetForeignKeySources() { + return fk_sources_; } // Get a string representation for debugging @@ -238,15 +326,12 @@ class Schema : public Printable { // all inlined and uninlined columns in the tuple std::vector columns_; - // keeps track of unlined columns - std::vector uninlined_columns_; - - // keeps multi_constraints - std::vector multi_constraints_; - // keep these in sync with the vectors above oid_t column_count_ = INVALID_OID; + // keeps track of unlined columns + std::vector uninlined_columns_; + oid_t uninlined_column_count_ = INVALID_OID; // are all columns inlined @@ -254,6 +339,27 @@ class Schema : public Printable { // keeps track of indexed columns in original table std::vector indexed_columns_; + + // Constraint Information + // keeps constraints + std::unordered_map> constraints; + + // not null column list for fast constraint checking + std::vector not_null_columns_; + + // has a primary key ? + bool has_primary_key_ = false; + + // # of unique constraints + oid_t unique_constraint_count_ = START_OID; + + // list of foreign key constraints + std::vector fk_constraints_; + + // fk constraints for which this table is the sink + // The complete information is stored so no need to lookup the table + // everytime there is a constraint check + std::vector> fk_sources_; }; } // namespace catalog diff --git a/src/include/catalog/system_catalogs.h b/src/include/catalog/system_catalogs.h index 1d3e8c081dc..e143d4c227d 100644 --- a/src/include/catalog/system_catalogs.h +++ b/src/include/catalog/system_catalogs.h @@ -14,6 +14,7 @@ #include +#include "catalog/constraint_catalog.h" #include "catalog/database_catalog.h" #include "catalog/index_metrics_catalog.h" #include "catalog/query_metrics_catalog.h" @@ -35,6 +36,7 @@ class TableCatalog; class IndexCatalog; class ColumnCatalog; class LayoutCatalog; +class ConstraintCatalog; class SystemCatalogs { public: @@ -88,6 +90,13 @@ class SystemCatalogs { return pg_layout_; } + ConstraintCatalog *GetConstraintCatalog() { + if (!pg_constraint_) { + throw CatalogException("Layout catalog has not been initialized"); + } + return pg_constraint_; + } + TriggerCatalog *GetTriggerCatalog() { if (!pg_trigger_) { throw CatalogException("Trigger catalog has not been initialized"); @@ -122,6 +131,7 @@ class SystemCatalogs { TableCatalog *pg_table_; IndexCatalog *pg_index_; LayoutCatalog *pg_layout_; + ConstraintCatalog *pg_constraint_; TriggerCatalog *pg_trigger_; // ProcCatalog *pg_proc; diff --git a/src/include/catalog/table_catalog.h b/src/include/catalog/table_catalog.h index e22af23b262..f7d373c4d3e 100644 --- a/src/include/catalog/table_catalog.h +++ b/src/include/catalog/table_catalog.h @@ -45,12 +45,14 @@ namespace catalog { class IndexCatalogEntry; class ColumnCatalogEntry; +class ConstraintCatalogEntry; class TableCatalogEntry { friend class TableCatalog; friend class IndexCatalog; friend class ColumnCatalog; friend class LayoutCatalog; + friend class ConstraintCatalog; public: TableCatalogEntry(concurrency::TransactionContext *txn, @@ -95,6 +97,15 @@ class TableCatalogEntry { std::shared_ptr GetLayout(oid_t layout_id, bool cached_entry = false); + // Evict all constraints from the cache + void EvictAllConstraintCatalogEntries(); + + // Get constraints + std::unordered_map> + GetConstraintCatalogEntries(bool cached_only = false); + std::shared_ptr + GetConstraintCatalogEntry(oid_t constraint_oid, bool cached_entry = false); + inline oid_t GetTableOid() { return table_oid; } inline const std::string &GetTableName() { return table_name; } inline const std::string &GetSchemaName() { return schema_name; } @@ -111,39 +122,53 @@ class TableCatalogEntry { uint32_t version_id; oid_t default_layout_oid; - // Get index objects + // Insert/Evict index catalog entries bool InsertIndexCatalogEntry(std::shared_ptr index_catalog_entry); bool EvictIndexCatalogEntry(oid_t index_oid); bool EvictIndexCatalogEntry(const std::string &index_name); - // Get column objects + // Insert/Evict column catalog entries bool InsertColumnCatalogEntry(std::shared_ptr column_catalog_entry); bool EvictColumnCatalogEntry(oid_t column_id); bool EvictColumnCatalogEntry(const std::string &column_name); - // Insert layout into table object + // Insert layout catalog entry into table catalog entry bool InsertLayout(std::shared_ptr layout); - // Evict layout_id from the table object + // Evict layout_id from the table catalog entry bool EvictLayout(oid_t layout_id); - // cache for *all* index catalog objects in this table + // Insert constraint catalog entry into table catalog entry + bool InsertConstraintCatalogEntry( + std::shared_ptr constraint_catalog_entry); + // Evict constraint_oid from the table catalog entry + bool EvictConstraintCatalogEntry(oid_t constraint_oid); + void SetValidConstraintCatalogEntries(bool valid = true) { + valid_constraint_catalog_entries_ = valid; + } + + // cache for *all* index catalog entries in this table std::unordered_map> index_catalog_entries; std::unordered_map> index_catalog_entries_by_name_; bool valid_index_catalog_entries_; - // cache for *all* column catalog objects in this table + // cache for *all* column catalog entries in this table std::unordered_map> column_catalog_entries_; std::unordered_map> column_names_; bool valid_column_catalog_entries_; - // cache for *all* layout objects in the table + // cache for *all* layout catalog entries in the table std::unordered_map> layout_catalog_entries_; bool valid_layout_catalog_entries_; + // cache for *all* constraint catalog entries in the table + std::unordered_map> + constraint_catalog_entries_; + bool valid_constraint_catalog_entries_; + // Pointer to its corresponding transaction concurrency::TransactionContext *txn_; }; @@ -154,6 +179,7 @@ class TableCatalog : public AbstractCatalog { friend class ColumnCatalog; friend class IndexCatalog; friend class LayoutCatalog; + friend class ConstraintCatalog; friend class Catalog; public: diff --git a/src/include/common/internal_types.h b/src/include/common/internal_types.h index 22598226407..b34d2971c70 100644 --- a/src/include/common/internal_types.h +++ b/src/include/common/internal_types.h @@ -892,26 +892,27 @@ enum class PostgresConstraintType { enum class ConstraintType { INVALID = INVALID_TYPE_ID, // invalid - NOT_NULL = 1, // notnull - NOTNULL = 2, // notnull - DEFAULT = 3, // default - CHECK = 4, // check - PRIMARY = 5, // primary key - UNIQUE = 6, // unique - FOREIGN = 7, // foreign key - EXCLUSION = 8 // foreign key + CHECK = 1, // check + PRIMARY = 2, // primary key + UNIQUE = 3, // unique + FOREIGN = 4, // foreign key + EXCLUSION = 5 // foreign key }; std::string ConstraintTypeToString(ConstraintType type); ConstraintType StringToConstraintType(const std::string &str); std::ostream &operator<<(std::ostream &os, const ConstraintType &type); enum class FKConstrActionType { - NOACTION = 0, - RESTRICT = 1, - CASCADE = 2, - SETNULL = 3, - SETDEFAULT = 4 + INVALID = INVALID_TYPE_ID, // invalid + NOACTION = 1, + RESTRICT = 2, + CASCADE = 3, + SETNULL = 4, + SETDEFAULT = 5 }; +std::string FKConstrActionTypeToString(FKConstrActionType type); +FKConstrActionType StringToFKConstrActionType(const std::string &str); +std::ostream &operator<<(std::ostream &os, const FKConstrActionType &type); enum class FKConstrMatchType { SIMPLE = 0, PARTIAL = 1, FULL = 2 }; diff --git a/src/include/planner/create_plan.h b/src/include/planner/create_plan.h index ecf6a0524fe..5f76c0f194b 100644 --- a/src/include/planner/create_plan.h +++ b/src/include/planner/create_plan.h @@ -33,11 +33,16 @@ class AbstractExpression; namespace planner { /** - * The meta-data for a foreign key reference. + * The meta-data for a constraint reference. * This is meant to be a bridge from the parser to the * catalog. It only has table names and not OIDs, whereas * the catalog only wants OIDs. */ +struct PrimaryKeyInfo { + std::vector primary_key_cols; + std::string constraint_name; +}; + struct ForeignKeyInfo { std::vector foreign_key_sources; std::vector foreign_key_sinks; @@ -47,6 +52,17 @@ struct ForeignKeyInfo { FKConstrActionType del_action; }; +struct UniqueInfo { + std::vector unique_cols; + std::string constraint_name; +}; + +struct CheckInfo { + std::vector check_cols; + std::string constraint_name; + std::pair exp; +}; + class CreatePlan : public AbstractPlan { public: CreatePlan() = delete; @@ -90,9 +106,18 @@ class CreatePlan : public AbstractPlan { std::vector GetIndexAttributes() const { return index_attrs; } + inline bool HasPrimaryKey() const { return has_primary_key; } + + inline PrimaryKeyInfo GetPrimaryKey() const { return primary_key; } + inline std::vector GetForeignKeys() const { return foreign_keys; } + + inline std::vector GetUniques() const { return con_uniques; } + + inline std::vector GetChecks() const { return con_checks; } + std::vector GetKeyAttrs() const { return key_attrs; } void SetKeyAttrs(std::vector p_key_attrs) { key_attrs = p_key_attrs; } @@ -115,11 +140,16 @@ class CreatePlan : public AbstractPlan { int16_t GetTriggerType() const { return trigger_type; } protected: - // This is a helper method for extracting foreign key information - // and storing it in an internal struct. + // These following protected function are a helper method for extracting + // Multi-column constraint information and storing it in an internal struct. void ProcessForeignKeyConstraint(const std::string &table_name, const parser::ColumnDefinition *col); + void ProcessUniqueConstraint(const parser::ColumnDefinition *col); + + void ProcessCheckConstraint(const parser::ColumnDefinition *col); + + private: // Table Name std::string table_name; @@ -150,7 +180,11 @@ class CreatePlan : public AbstractPlan { bool unique; // ColumnDefinition for multi-column constraints (including foreign key) + bool has_primary_key = false; + PrimaryKeyInfo primary_key; std::vector foreign_keys; + std::vector con_uniques; + std::vector con_checks; std::string trigger_name; std::vector trigger_funcname; std::vector trigger_args; diff --git a/src/include/storage/abstract_table.h b/src/include/storage/abstract_table.h index 6b49cf9e431..b9e5cdafa10 100644 --- a/src/include/storage/abstract_table.h +++ b/src/include/storage/abstract_table.h @@ -111,16 +111,6 @@ class AbstractTable : public Printable { // Get a string representation for debugging const std::string GetInfo() const; - //===--------------------------------------------------------------------===// - // UTILITIES - //===--------------------------------------------------------------------===// - - virtual bool HasPrimaryKey() const = 0; - - virtual bool HasUniqueConstraints() const = 0; - - virtual bool HasForeignKeys() const = 0; - //===--------------------------------------------------------------------===// // STATS //===--------------------------------------------------------------------===// diff --git a/src/include/storage/data_table.h b/src/include/storage/data_table.h index 1f0d4be29c4..48708b9edb5 100644 --- a/src/include/storage/data_table.h +++ b/src/include/storage/data_table.h @@ -134,8 +134,8 @@ class DataTable : public AbstractTable { // Insert tuple with ItemPointer provided explicitly bool InsertTuple(const AbstractTuple *tuple, ItemPointer location, - concurrency::TransactionContext *transaction, ItemPointer **index_entry_ptr, - bool check_fk = true); + concurrency::TransactionContext *transaction, + ItemPointer **index_entry_ptr, bool check_fk = true); //===--------------------------------------------------------------------===// // TILE GROUP @@ -167,13 +167,12 @@ class DataTable : public AbstractTable { int GetTriggerNumber(); - trigger::Trigger* GetTriggerByIndex(int n); + trigger::Trigger *GetTriggerByIndex(int n); - trigger::TriggerList* GetTriggerList(); + trigger::TriggerList *GetTriggerList(); void UpdateTriggerListFromCatalog(concurrency::TransactionContext *txn); - //===--------------------------------------------------------------------===// // INDEX //===--------------------------------------------------------------------===// @@ -198,29 +197,15 @@ class DataTable : public AbstractTable { const std::vector> &GetIndexColumns() const { return indexes_columns_; } + //===--------------------------------------------------------------------===// // FOREIGN KEYS //===--------------------------------------------------------------------===// - bool CheckForeignKeySrcAndCascade(storage::Tuple *prev_tuple, - storage::Tuple *new_tuple, - concurrency::TransactionContext *transaction, - executor::ExecutorContext *context, - bool is_update); - - void AddForeignKey(catalog::ForeignKey *key); - - catalog::ForeignKey *GetForeignKey(const oid_t &key_offset) const; - - void DropForeignKey(const oid_t &key_offset); - - size_t GetForeignKeyCount() const; - - void RegisterForeignKeySource(catalog::ForeignKey *key); - - size_t GetForeignKeySrcCount() const; - - catalog::ForeignKey *GetForeignKeySrc(const size_t) const; + bool CheckForeignKeySrcAndCascade( + storage::Tuple *prev_tuple, storage::Tuple *new_tuple, + concurrency::TransactionContext *transaction, + executor::ExecutorContext *context, bool is_update); //===--------------------------------------------------------------------===// // TRANSFORMERS @@ -290,12 +275,6 @@ class DataTable : public AbstractTable { // deprecated, use catalog::TableCatalog::GetInstance()->GetDatabaseOid() inline oid_t GetDatabaseOid() const { return (database_oid); } - bool HasPrimaryKey() const { return (has_primary_key_); } - - bool HasUniqueConstraints() const { return (unique_constraint_count_ > 0); } - - bool HasForeignKeys() const { return (foreign_keys_.empty() == false); } - // try to insert into all indexes. // the last argument is the index entry in primary index holding the new // tuple. @@ -335,8 +314,8 @@ class DataTable : public AbstractTable { //===--------------------------------------------------------------------===// bool CheckNotNulls(const AbstractTuple *tuple, oid_t column_idx) const; -// bool MultiCheckNotNulls(const storage::Tuple *tuple, -// std::vector cols) const; + // bool MultiCheckNotNulls(const storage::Tuple *tuple, + // std::vector cols) const; // bool CheckExp(const storage::Tuple *tuple, oid_t column_idx, // std::pair exp) const; @@ -425,20 +404,6 @@ class DataTable : public AbstractTable { // columns present in the indexes std::vector> indexes_columns_; - // CONSTRAINTS - // fk constraints for which this table is the source - std::vector foreign_keys_; - // fk constraints for which this table is the sink - // The complete information is stored so no need to lookup the table - // everytime there is a constraint check - std::vector foreign_key_sources_; - - // has a primary key ? - std::atomic has_primary_key_ = ATOMIC_VAR_INIT(false); - - // # of unique constraints - std::atomic unique_constraint_count_ = ATOMIC_VAR_INIT(START_OID); - // # of tuples. must be atomic as multiple transactions can perform insert // concurrently. std::atomic number_of_tuples_ = ATOMIC_VAR_INIT(0); diff --git a/src/include/storage/temp_table.h b/src/include/storage/temp_table.h index f6b94640750..cc45b541890 100644 --- a/src/include/storage/temp_table.h +++ b/src/include/storage/temp_table.h @@ -91,12 +91,6 @@ class TempTable : public AbstractTable { std::string GetName() const override; - inline bool HasPrimaryKey() const override { return (false); } - - inline bool HasUniqueConstraints() const override { return (false); } - - inline bool HasForeignKeys() const override { return (false); } - //===--------------------------------------------------------------------===// // STATS //===--------------------------------------------------------------------===// diff --git a/src/optimizer/stats/column_stats_collector.cpp b/src/optimizer/stats/column_stats_collector.cpp index f474504f954..f805258538d 100644 --- a/src/optimizer/stats/column_stats_collector.cpp +++ b/src/optimizer/stats/column_stats_collector.cpp @@ -44,11 +44,12 @@ void ColumnStatsCollector::AddValue(const type::Value &value) { total_count_++; if (value.IsNull()) { null_count_++; + } else { + // Update all stats + hll_.Update(value); + hist_.Update(value); + topk_.Add(value); } - // Update all stats - hll_.Update(value); - hist_.Update(value); - topk_.Add(value); } double ColumnStatsCollector::GetFracNull() { diff --git a/src/optimizer/stats/stats_storage.cpp b/src/optimizer/stats/stats_storage.cpp index 4231e95ee9e..0824a978b21 100644 --- a/src/optimizer/stats/stats_storage.cpp +++ b/src/optimizer/stats/stats_storage.cpp @@ -296,7 +296,7 @@ ResultType StatsStorage::AnalyzeStatsForAllTables( oid_t table_count = database->GetTableCount(); for (oid_t table_offset = 0; table_offset < table_count; table_offset++) { auto table = database->GetTable(table_offset); - LOG_TRACE("Analyzing table: %s", table->GetName().c_str()); + LOG_DEBUG("Analyzing table: %s", table->GetName().c_str()); std::unique_ptr table_stats_collector( new TableStatsCollector(table)); table_stats_collector->CollectColumnStats(); diff --git a/src/planner/create_plan.cpp b/src/planner/create_plan.cpp index 2a23a75abb4..47b415175b7 100644 --- a/src/planner/create_plan.cpp +++ b/src/planner/create_plan.cpp @@ -53,49 +53,31 @@ CreatePlan::CreatePlan(parser::CreateStatement *parse_tree) { schema_name = std::string(parse_tree->GetSchemaName()); database_name = std::string(parse_tree->GetDatabaseName()); std::vector columns; - std::vector column_constraints; + std::vector pri_cols; create_type = CreateType::TABLE; - // The parser puts the Foreign Key information into an artificial - // ColumnDefinition. - for (auto &fk : parse_tree->foreign_keys) { - this->ProcessForeignKeyConstraint(table_name, fk.get()); - } - for (auto &col : parse_tree->columns) { type::TypeId val = col->GetValueType(col->type); LOG_TRACE("Column name: %s.%s; Is primary key: %d", table_name.c_str(), col->name.c_str(), col->primary); - // Check main constraints - if (col->primary) { - catalog::Constraint constraint(ConstraintType::PRIMARY, - "con_primary"); - column_constraints.push_back(constraint); - LOG_TRACE("Added a primary key constraint on column \"%s.%s\"", - table_name.c_str(), col->name.c_str()); + // Create column + auto column = catalog::Column(val, type::Type::GetTypeSize(val), + std::string(col->name), false); + if (!column.IsInlined()) { + column.SetLength(col->varlen); } + // Add NOT NULL constraints to the column if (col->not_null) { - catalog::Constraint constraint(ConstraintType::NOTNULL, - "con_not_null"); - column_constraints.push_back(constraint); + column.SetNotNull(); LOG_TRACE("Added a not-null constraint on column \"%s.%s\"", table_name.c_str(), col->name.c_str()); } - if (col->unique) { - catalog::Constraint constraint(ConstraintType::UNIQUE, "con_unique"); - column_constraints.push_back(constraint); - LOG_TRACE("Added a unique constraint on column \"%s.%s\"", - table_name.c_str(), col->name.c_str()); - } - - /* **************** */ - - // Add the default value + // Add DEFAULT constraints to the column if (col->default_value != nullptr) { // Referenced from insert_plan.cpp if (col->default_value->GetExpressionType() != @@ -103,53 +85,58 @@ CreatePlan::CreatePlan(parser::CreateStatement *parse_tree) { expression::ConstantValueExpression *const_expr_elem = dynamic_cast( col->default_value.get()); - - catalog::Constraint constraint(ConstraintType::DEFAULT, - "con_default"); - type::Value v = const_expr_elem->GetValue(); - constraint.addDefaultValue(v); - column_constraints.push_back(constraint); + column.SetDefaultValue(const_expr_elem->GetValue()); LOG_TRACE("Added a default constraint %s on column \"%s.%s\"", - v.ToString().c_str(), table_name.c_str(), - col->name.c_str()); + const_expr_elem->GetValue().ToString().c_str(), + table_name.c_str(), col->name.c_str()); } } + columns.push_back(column); + + // Collect Multi-column constraints information + // TODO: Following constraints info in ColumnDefinition should be + // independent + // for multi-column constraints like foreign key. + + // Primary key + if (col->primary) { + pri_cols.push_back(col->name); + } + + // Unique constraint + // Currently only supports for single column + if (col->unique) { + ProcessUniqueConstraint(col.get()); + } + // Check expression constraint // Currently only supports simple boolean forms like (a > 0) if (col->check_expression != nullptr) { - // TODO: more expression types need to be supported - if (col->check_expression->GetValueType() == type::TypeId::BOOLEAN) { - catalog::Constraint constraint(ConstraintType::CHECK, "con_check"); - - const expression::ConstantValueExpression *const_expr_elem = - dynamic_cast( - col->check_expression->GetChild(1)); - - type::Value tmp_value = const_expr_elem->GetValue(); - constraint.AddCheck( - std::move(col->check_expression->GetExpressionType()), - std::move(tmp_value)); - column_constraints.push_back(constraint); - LOG_TRACE("Added a check constraint on column \"%s.%s\"", - table_name.c_str(), col->name.c_str()); - } + ProcessCheckConstraint(col.get()); } + } - auto column = catalog::Column(val, type::Type::GetTypeSize(val), - std::string(col->name), false); - if (!column.IsInlined()) { - column.SetLength(col->varlen); - } + catalog::Schema *schema = new catalog::Schema(columns); - for (auto con : column_constraints) { - column.AddConstraint(con); - } + // The parser puts the multi-column constraint information + // into an artificial ColumnDefinition. + // primary key constraint + if (pri_cols.size() > 0) { + primary_key.primary_key_cols = pri_cols; + primary_key.constraint_name = "con_primary"; + has_primary_key = true; + LOG_TRACE("Added a primary key constraint on column \"%s\"", + table_name.c_str()); + } - column_constraints.clear(); - columns.push_back(column); + // foreign key + for (auto &fk : parse_tree->foreign_keys) { + ProcessForeignKeyConstraint(table_name, fk.get()); } - catalog::Schema *schema = new catalog::Schema(columns); + + // TODO: UNIQUE and CHECK constraints + table_schema = schema; break; } @@ -241,6 +228,40 @@ void CreatePlan::ProcessForeignKeyConstraint( foreign_keys.push_back(fkey_info); } +void CreatePlan::ProcessUniqueConstraint(const parser::ColumnDefinition *col) { + UniqueInfo unique_info; + + unique_info.unique_cols = {col->name}; + unique_info.constraint_name = "con_unique"; + + LOG_TRACE("Added a unique constraint on column \"%s.%s\"", table_name.c_str(), + col->name.c_str()); + con_uniques.push_back(unique_info); +} + +void CreatePlan::ProcessCheckConstraint(const parser::ColumnDefinition *col) { + CheckInfo check_info; + + // TODO: more expression types need to be supported + if (col->check_expression->GetValueType() == type::TypeId::BOOLEAN) { + check_info.check_cols.push_back(col->name); + + const expression::ConstantValueExpression *const_expr_elem = + dynamic_cast( + col->check_expression->GetChild(1)); + type::Value tmp_value = const_expr_elem->GetValue(); + + check_info.exp = + std::make_pair(std::move(col->check_expression->GetExpressionType()), + std::move(tmp_value)); + + check_info.constraint_name = "con_check"; + + LOG_TRACE("Added a check constraint on column \"%s\"", table_name.c_str()); + con_checks.push_back(check_info); + } +} + expression::AbstractExpression *CreatePlan::GetTriggerWhen() const { if (trigger_when) { return trigger_when->Copy(); diff --git a/src/planner/update_plan.cpp b/src/planner/update_plan.cpp index 8b6bccc4c8a..0d1593738e3 100644 --- a/src/planner/update_plan.cpp +++ b/src/planner/update_plan.cpp @@ -23,18 +23,8 @@ UpdatePlan::UpdatePlan(storage::DataTable *table, std::unique_ptr project_info) : target_table_(table), project_info_(std::move(project_info)), - update_primary_key_(false) { + update_primary_key_(table->GetSchema()->HasPrimary()) { LOG_TRACE("Creating an Update Plan"); - - if (project_info_ != nullptr) { - for (const auto target : project_info_->GetTargetList()) { - auto col_id = target.first; - update_primary_key_ = - target_table_->GetSchema()->GetColumn(col_id).IsPrimary(); - if (update_primary_key_) - break; - } - } } void UpdatePlan::SetParameterValues(std::vector *values) { diff --git a/src/storage/data_table.cpp b/src/storage/data_table.cpp index c292e8d3718..85240e196e1 100644 --- a/src/storage/data_table.cpp +++ b/src/storage/data_table.cpp @@ -14,7 +14,6 @@ #include #include "catalog/catalog.h" -#include "catalog/foreign_key.h" #include "catalog/layout_catalog.h" #include "catalog/system_catalogs.h" #include "catalog/table_catalog.h" @@ -110,17 +109,6 @@ DataTable::~DataTable() { } } - // clean up foreign keys - for (auto foreign_key : foreign_keys_) { - delete foreign_key; - } - foreign_keys_.clear(); - - for (auto foreign_key_src : foreign_key_sources_) { - delete foreign_key_src; - } - foreign_key_sources_.clear(); - // drop all indirection arrays for (auto indirection_array : active_indirection_arrays_) { auto oid = indirection_array->GetOid(); @@ -146,71 +134,61 @@ bool DataTable::CheckNotNulls(const AbstractTuple *tuple, } bool DataTable::CheckConstraints(const AbstractTuple *tuple) const { - // For each column in the table, check to see whether they have - // any constraints. Then if they do, make sure that the - // given tuple does not violate them. - // - // TODO: PAVLO 2017-07-15 - // We should create a faster way of check the constraints for each - // column. Like maybe can store a list of just columns that - // even have constraints defined so that we don't have to - // look at each column individually. - size_t column_count = schema->GetColumnCount(); - for (oid_t column_itr = 0; column_itr < column_count; column_itr++) { - const std::vector &column_constraints = - schema->GetColumn(column_itr).GetConstraints(); - for (const auto &constraint : column_constraints) { - ConstraintType type = constraint.GetType(); - switch (type) { - case ConstraintType::NOTNULL: { - if (CheckNotNulls(tuple, column_itr) == false) { - std::string error = StringUtil::Format( - "%s constraint violated on column '%s' : %s", - ConstraintTypeToString(type).c_str(), - schema->GetColumn(column_itr).GetName().c_str(), - tuple->GetInfo().c_str()); - throw ConstraintException(error); - } - break; - } - case ConstraintType::CHECK: { - // std::pair exp = - // cons.GetCheckExpression(); - // if (CheckExp(tuple, column_itr, exp) == false) { - // LOG_TRACE("CHECK EXPRESSION constraint violated"); - // throw ConstraintException( - // "CHECK EXPRESSION constraint violated : " + - // std::string(tuple->GetInfo())); - // } - break; - } - case ConstraintType::UNIQUE: { - break; - } - case ConstraintType::DEFAULT: { - // Should not be handled here - // Handled in higher hierarchy - break; - } - case ConstraintType::PRIMARY: { - break; - } - case ConstraintType::FOREIGN: { - break; - } - case ConstraintType::EXCLUSION: { - break; - } - default: { - std::string error = - StringUtil::Format("ConstraintType '%s' is not supported", - ConstraintTypeToString(type).c_str()); - LOG_TRACE("%s", error.c_str()); - throw ConstraintException(error); - } - } + // make sure that the given tuple does not violate constraints. + + // NOT NULL constraint + for (oid_t column_id : schema->GetNotNullColumns()) { + if (schema->AllowNull(column_id) == false && + CheckNotNulls(tuple, column_id) == false) { + std::string error = + StringUtil::Format("NOT NULL constraint violated on column '%s' : %s", + schema->GetColumn(column_id).GetName().c_str(), + tuple->GetInfo().c_str()); + throw ConstraintException(error); } } + + // DEFAULT constraint should not be handled here + // Handled in higher hierarchy + + // multi-column constraints + for (auto cons_pair : schema->GetConstraints()) { + auto cons = cons_pair.second; + ConstraintType type = cons->GetType(); + switch (type) { + case ConstraintType::CHECK: { + // std::pair exp = + // cons.GetCheckExpression(); + // if (CheckExp(tuple, column_itr, exp) == false) { + // LOG_TRACE("CHECK EXPRESSION constraint violated"); + // throw ConstraintException( + // "CHECK EXPRESSION constraint violated : " + + // std::string(tuple->GetInfo())); + // } + break; + } + case ConstraintType::UNIQUE: { + break; + } + case ConstraintType::PRIMARY: { + break; + } + case ConstraintType::FOREIGN: { + break; + } + case ConstraintType::EXCLUSION: { + break; + } + default: { + std::string error = + StringUtil::Format("ConstraintType '%s' is not supported", + ConstraintTypeToString(type).c_str()); + LOG_TRACE("%s", error.c_str()); + throw ConstraintException(error); + } + } // SWITCH + } // FOR (constraints) + return true; } @@ -236,8 +214,8 @@ ItemPointer DataTable::GetEmptyTupleSlot(const storage::Tuple *tuple) { if (free_item_pointer.IsNull() == false) { // when inserting a tuple if (tuple != nullptr) { - auto tile_group = - storage::StorageManager::GetInstance()->GetTileGroup(free_item_pointer.block); + auto tile_group = storage::StorageManager::GetInstance()->GetTileGroup( + free_item_pointer.block); tile_group->CopyTuple(tuple, free_item_pointer.offset); } return free_item_pointer; @@ -386,7 +364,7 @@ bool DataTable::InsertTuple(const AbstractTuple *tuple, ItemPointer location, } PELOTON_ASSERT((*index_entry_ptr)->block == location.block && - (*index_entry_ptr)->offset == location.offset); + (*index_entry_ptr)->offset == location.offset); // Increase the table's number of tuples by 1 IncreaseTupleCount(1); @@ -591,18 +569,14 @@ bool DataTable::CheckForeignKeySrcAndCascade( storage::Tuple *prev_tuple, storage::Tuple *new_tuple, concurrency::TransactionContext *current_txn, executor::ExecutorContext *context, bool is_update) { - size_t fk_count = GetForeignKeySrcCount(); - - if (fk_count == 0) return true; + if (!schema->HasForeignKeySources()) return true; auto &transaction_manager = concurrency::TransactionManagerFactory::GetInstance(); - for (size_t iter = 0; iter < fk_count; iter++) { - catalog::ForeignKey *fk = GetForeignKeySrc(iter); - + for (auto cons : schema->GetForeignKeySources()) { // Check if any row in the source table references the current tuple - oid_t source_table_id = fk->GetSourceTableOid(); + oid_t source_table_id = cons->GetTableOid(); storage::DataTable *src_table = nullptr; try { src_table = (storage::DataTable *)storage::StorageManager::GetInstance() @@ -618,17 +592,18 @@ bool DataTable::CheckForeignKeySrcAndCascade( if (index == nullptr) continue; // Make sure this is the right index to search in - if (index->GetMetadata()->GetName().find("_FK_") != std::string::npos && - index->GetMetadata()->GetKeyAttrs() == fk->GetSourceColumnIds()) { + if (index->GetOid() == cons->GetIndexOid() && + index->GetMetadata()->GetKeyAttrs() == cons->GetColumnIds()) { LOG_DEBUG("Searching in source tables's fk index...\n"); - std::vector key_attrs = fk->GetSourceColumnIds(); + std::vector key_attrs = cons->GetColumnIds(); std::unique_ptr fk_schema( catalog::Schema::CopySchema(src_table->GetSchema(), key_attrs)); std::unique_ptr key( new storage::Tuple(fk_schema.get(), true)); - key->SetFromTuple(prev_tuple, fk->GetSinkColumnIds(), index->GetPool()); + key->SetFromTuple(prev_tuple, cons->GetFKSinkColumnIds(), + index->GetPool()); std::vector location_ptrs; index->ScanKey(key.get(), location_ptrs); @@ -646,7 +621,7 @@ bool DataTable::CheckForeignKeySrcAndCascade( if (visibility != VisibilityType::OK) continue; - switch (fk->GetUpdateAction()) { + switch (cons->GetFKUpdateAction()) { // Currently NOACTION is the same as RESTRICT case FKConstrActionType::NOACTION: case FKConstrActionType::RESTRICT: { @@ -661,11 +636,8 @@ bool DataTable::CheckForeignKeySrcAndCascade( // Read the referencing tuple, update the read timestamp so that // we can // delete it later - bool ret = - transaction_manager.PerformRead(current_txn, - *ptr, - src_tile_group_header, - true); + bool ret = transaction_manager.PerformRead( + current_txn, *ptr, src_tile_group_header, true); if (ret == false) { if (src_is_owner) { @@ -690,7 +662,7 @@ bool DataTable::CheckForeignKeySrcAndCascade( // Set the primary key fields for (oid_t k = 0; k < key_attrs.size(); k++) { auto src_col_index = key_attrs[k]; - auto sink_col_index = fk->GetSinkColumnIds()[k]; + auto sink_col_index = cons->GetFKSinkColumnIds()[k]; src_new_tuple.SetValue(src_col_index, new_tuple->GetValue(sink_col_index), context->GetPool()); @@ -756,14 +728,14 @@ bool DataTable::CheckForeignKeySrcAndCascade( */ bool DataTable::CheckForeignKeyConstraints( const AbstractTuple *tuple, concurrency::TransactionContext *transaction) { - for (auto foreign_key : foreign_keys_) { - oid_t sink_table_id = foreign_key->GetSinkTableOid(); + for (auto foreign_key : schema->GetForeignKeyConstraints()) { + oid_t sink_table_id = foreign_key->GetFKSinkTableOid(); storage::DataTable *ref_table = nullptr; try { ref_table = (storage::DataTable *)storage::StorageManager::GetInstance() ->GetTableWithOid(database_oid, sink_table_id); } catch (CatalogException &e) { - LOG_TRACE("Can't find table %d! Return false", sink_table_id); + LOG_ERROR("Can't find table %d! Return false", sink_table_id); return false; } int ref_table_index_count = ref_table->GetIndexCount(); @@ -775,13 +747,12 @@ bool DataTable::CheckForeignKeyConstraints( // The foreign key constraints only refer to the primary key if (index->GetIndexType() == IndexConstraintType::PRIMARY_KEY) { - std::vector key_attrs = foreign_key->GetSinkColumnIds(); + std::vector key_attrs = foreign_key->GetFKSinkColumnIds(); std::unique_ptr foreign_key_schema( catalog::Schema::CopySchema(ref_table->schema, key_attrs)); std::unique_ptr key( new storage::Tuple(foreign_key_schema.get(), true)); - key->SetFromTuple(tuple, foreign_key->GetSourceColumnIds(), - index->GetPool()); + key->SetFromTuple(tuple, foreign_key->GetColumnIds(), index->GetPool()); LOG_TRACE("check key: %s", key->GetInfo().c_str()); std::vector location_ptrs; @@ -790,7 +761,7 @@ bool DataTable::CheckForeignKeyConstraints( // if this key doesn't exist in the referred column if (location_ptrs.size() == 0) { LOG_DEBUG("The key: %s does not exist in table %s\n", - key->GetInfo().c_str(), ref_table->GetInfo().c_str()); + key->GetInfo().c_str(), ref_table->GetName().c_str()); return false; } @@ -808,7 +779,7 @@ bool DataTable::CheckForeignKeyConstraints( LOG_DEBUG( "The key: %s is not yet visible in table %s, visibility " "type: %s.\n", - key->GetInfo().c_str(), ref_table->GetInfo().c_str(), + key->GetInfo().c_str(), ref_table->GetName().c_str(), VisibilityTypeToString(visibility).c_str()); return false; } @@ -875,7 +846,8 @@ void DataTable::ResetDirty() { dirty_ = false; } TileGroup *DataTable::GetTileGroupWithLayout( std::shared_ptr layout) { - oid_t tile_group_id = storage::StorageManager::GetInstance()->GetNextTileGroupId(); + oid_t tile_group_id = + storage::StorageManager::GetInstance()->GetNextTileGroupId(); return (AbstractTable::GetTileGroupWithLayout(database_oid, tile_group_id, layout, tuples_per_tilegroup_)); } @@ -915,7 +887,8 @@ oid_t DataTable::AddDefaultTileGroup(const size_t &active_tile_group_id) { tile_groups_.Append(tile_group_id); // add tile group metadata in locator - storage::StorageManager::GetInstance()->AddTileGroup(tile_group_id, tile_group); + storage::StorageManager::GetInstance()->AddTileGroup(tile_group_id, + tile_group); COMPILER_MEMORY_FENCE; @@ -961,7 +934,8 @@ void DataTable::AddTileGroupWithOidForRecovery(const oid_t &tile_group_id) { LOG_TRACE("Added a tile group "); // add tile group metadata in locator - storage::StorageManager::GetInstance()->AddTileGroup(tile_group_id, tile_group); + storage::StorageManager::GetInstance()->AddTileGroup(tile_group_id, + tile_group); // we must guarantee that the compiler always add tile group before adding // tile_group_count_. @@ -984,7 +958,8 @@ void DataTable::AddTileGroup(const std::shared_ptr &tile_group) { tile_groups_.Append(tile_group_id); // add tile group in catalog - storage::StorageManager::GetInstance()->AddTileGroup(tile_group_id, tile_group); + storage::StorageManager::GetInstance()->AddTileGroup(tile_group_id, + tile_group); // we must guarantee that the compiler always add tile group before adding // tile_group_count_. @@ -1048,14 +1023,6 @@ void DataTable::AddIndex(std::shared_ptr index) { index_columns_.end()); indexes_columns_.push_back(index_columns_set); - - // Update index stats - auto index_type = index->GetIndexType(); - if (index_type == IndexConstraintType::PRIMARY_KEY) { - has_primary_key_ = true; - } else if (index_type == IndexConstraintType::UNIQUE) { - unique_constraint_count_++; - } } std::shared_ptr DataTable::GetIndexWithOid( @@ -1147,55 +1114,6 @@ oid_t DataTable::GetValidIndexCount() const { return valid_index_count; } -//===--------------------------------------------------------------------===// -// FOREIGN KEYS -//===--------------------------------------------------------------------===// - -void DataTable::AddForeignKey(catalog::ForeignKey *key) { - { - std::lock_guard lock(data_table_mutex_); - catalog::Constraint constraint(ConstraintType::FOREIGN, - key->GetConstraintName()); - constraint.SetForeignKeyListOffset(GetForeignKeyCount()); - for (auto fk_column : key->GetSourceColumnIds()) { - schema->AddConstraint(fk_column, constraint); - } - foreign_keys_.push_back(key); - } -} - -catalog::ForeignKey *DataTable::GetForeignKey(const oid_t &key_offset) const { - catalog::ForeignKey *key = nullptr; - key = foreign_keys_.at(key_offset); - return key; -} - -void DataTable::DropForeignKey(const oid_t &key_offset) { - { - std::lock_guard lock(data_table_mutex_); - PELOTON_ASSERT(key_offset < foreign_keys_.size()); - foreign_keys_.erase(foreign_keys_.begin() + key_offset); - } -} - -size_t DataTable::GetForeignKeyCount() const { return foreign_keys_.size(); } - -// Adds to the list of tables for which this table's PK is the foreign key sink -void DataTable::RegisterForeignKeySource(catalog::ForeignKey *key) { - { - std::lock_guard lock(data_table_mutex_); - foreign_key_sources_.push_back(key); - } -} - -size_t DataTable::GetForeignKeySrcCount() const { - return foreign_key_sources_.size(); -} - -catalog::ForeignKey *DataTable::GetForeignKeySrc(const size_t offset) const { - return foreign_key_sources_[offset]; -} - // Get the schema for the new transformed tile group std::vector TransformTileGroupSchema( storage::TileGroup *tile_group, const Layout &layout) { diff --git a/src/storage/database.cpp b/src/storage/database.cpp index 8a7506805c8..55eaccc6892 100644 --- a/src/storage/database.cpp +++ b/src/storage/database.cpp @@ -12,7 +12,6 @@ #include -#include "catalog/foreign_key.h" #include "codegen/query_cache.h" #include "common/exception.h" #include "common/logger.h" @@ -146,15 +145,11 @@ const std::string Database::GetInfo() const { } } - if (table->HasForeignKeys()) { + if (table->GetSchema()->HasForeignKeys()) { os << "foreign tables \n"; - oid_t foreign_key_count = table->GetForeignKeyCount(); - for (oid_t foreign_key_itr = 0; foreign_key_itr < foreign_key_count; - foreign_key_itr++) { - auto foreign_key = table->GetForeignKey(foreign_key_itr); - - auto sink_table_oid = foreign_key->GetSinkTableOid(); + for (auto foreign_key : table->GetSchema()->GetForeignKeyConstraints()) { + auto sink_table_oid = foreign_key->GetFKSinkTableOid(); auto sink_table = GetTableWithOid(sink_table_oid); os << "table name : " << sink_table->GetName() << std::endl; diff --git a/test/brain/query_logger_test.cpp b/test/brain/query_logger_test.cpp index c3affa7fd40..301e3408dbd 100644 --- a/test/brain/query_logger_test.cpp +++ b/test/brain/query_logger_test.cpp @@ -53,7 +53,7 @@ class QueryLoggerTests : public PelotonTest { sleep(wait_time_); TestingSQLUtil::ExecuteSQLQueryAndCheckResult(select_query_.c_str(), - expected_result, true); + expected_result); // the select query we used will also be logged for next time expected_result.push_back(select_query_ + "|" + select_query_fingerprint_); @@ -88,7 +88,7 @@ class QueryLoggerTests : public PelotonTest { temporary_expected_result.end()); temporary_expected_result.clear(); TestingSQLUtil::ExecuteSQLQueryAndCheckResult(select_query_.c_str(), - expected_result, true); + expected_result); // the select query we used will also be logged for next time expected_result.push_back(select_query_ + "|" + @@ -97,7 +97,7 @@ class QueryLoggerTests : public PelotonTest { } else { // verify that the logging does not happen before the txn commit TestingSQLUtil::ExecuteSQLQueryAndCheckResult(select_query_.c_str(), - expected_result, true); + expected_result); // the select query we used will also be logged for next time temporary_expected_result.push_back(select_query_ + "|" + select_query_fingerprint_); diff --git a/test/catalog/catalog_test.cpp b/test/catalog/catalog_test.cpp index bda84540f89..7a15fa0f177 100644 --- a/test/catalog/catalog_test.cpp +++ b/test/catalog/catalog_test.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "catalog/catalog.h" +#include "catalog/column.h" #include "catalog/column_catalog.h" #include "catalog/database_catalog.h" #include "catalog/database_metrics_catalog.h" @@ -25,6 +26,7 @@ #include "sql/testing_sql_util.h" #include "storage/storage_manager.h" #include "type/ephemeral_pool.h" +#include "type/value_factory.h" namespace peloton { namespace test { @@ -70,8 +72,6 @@ TEST_F(CatalogTests, CreatingTable) { auto id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "id", true); - id_column.AddConstraint( - catalog::Constraint(ConstraintType::PRIMARY, "primary_key")); auto name_column = catalog::Column(type::TypeId::VARCHAR, 32, "name", true); std::unique_ptr table_schema( @@ -81,24 +81,55 @@ TEST_F(CatalogTests, CreatingTable) { std::unique_ptr table_schema_3( new catalog::Schema({id_column, name_column})); - catalog::Catalog::GetInstance()->CreateTable(txn, - "emp_db", - DEFAULT_SCHEMA_NAME, - std::move(table_schema), - "emp_table", - false); - catalog::Catalog::GetInstance()->CreateTable(txn, - "emp_db", - DEFAULT_SCHEMA_NAME, - std::move(table_schema_2), - "department_table", - false); - catalog::Catalog::GetInstance()->CreateTable(txn, - "emp_db", - DEFAULT_SCHEMA_NAME, - std::move(table_schema_3), - "salary_table", - false); + auto catalog = catalog::Catalog::GetInstance(); + catalog->CreateTable(txn, + "emp_db", + DEFAULT_SCHEMA_NAME, + std::move(table_schema), + "emp_table", + false); + catalog->CreateTable(txn, + "emp_db", + DEFAULT_SCHEMA_NAME, + std::move(table_schema_2), + "department_table", + false); + catalog->CreateTable(txn, + "emp_db", + DEFAULT_SCHEMA_NAME, + std::move(table_schema_3), + "salary_table", + false); + + auto emp = catalog->GetTableCatalogEntry(txn, + "emp_db", + DEFAULT_SCHEMA_NAME, + "emp_table"); + auto department = catalog->GetTableCatalogEntry(txn, + "emp_db", + DEFAULT_SCHEMA_NAME, + "department_table"); + auto salary = catalog->GetTableCatalogEntry(txn, + "emp_db", + DEFAULT_SCHEMA_NAME, + "salary_table"); + + catalog->AddPrimaryKeyConstraint(txn, + emp->GetDatabaseOid(), + emp->GetTableOid(), + {0}, + "con_primary"); + catalog->AddPrimaryKeyConstraint(txn, + department->GetDatabaseOid(), + department->GetTableOid(), + {0}, + "con_primary"); + catalog->AddPrimaryKeyConstraint(txn, + salary->GetDatabaseOid(), + salary->GetTableOid(), + {0}, + "con_primary"); + // insert random tuple into DATABASE_METRICS_CATALOG and check std::unique_ptr pool(new type::EphemeralPool()); catalog::DatabaseMetricsCatalog::GetInstance()->InsertDatabaseMetrics(txn, @@ -113,10 +144,8 @@ TEST_F(CatalogTests, CreatingTable) { param.len = 1; param.buf = (unsigned char *) pool->Allocate(1); *param.buf = 'a'; - auto database_object = - catalog::Catalog::GetInstance()->GetDatabaseCatalogEntry(txn, "emp_db"); - catalog::Catalog::GetInstance() - ->GetSystemCatalogs(database_object->GetDatabaseOid()) + auto database_object = catalog->GetDatabaseCatalogEntry(txn, "emp_db"); + catalog->GetSystemCatalogs(database_object->GetDatabaseOid()) ->GetQueryMetricsCatalog() ->InsertQueryMetrics(txn, "a query", @@ -133,20 +162,13 @@ TEST_F(CatalogTests, CreatingTable) { 1, 1, pool.get()); - auto param1 = catalog::Catalog::GetInstance() - ->GetSystemCatalogs(database_object->GetDatabaseOid()) - ->GetQueryMetricsCatalog() - ->GetParamTypes(txn, "a query"); + auto param1 = catalog->GetSystemCatalogs(database_object->GetDatabaseOid()) + ->GetQueryMetricsCatalog() + ->GetParamTypes(txn, "a query"); EXPECT_EQ(1, param1.len); EXPECT_EQ('a', *param1.buf); // check colum object - EXPECT_EQ("name", catalog::Catalog::GetInstance() - ->GetTableCatalogEntry(txn, - "emp_db", - DEFAULT_SCHEMA_NAME, - "department_table") - ->GetColumnCatalogEntry(1) - ->GetColumnName()); + EXPECT_EQ("name", department->GetColumnCatalogEntry(1)->GetColumnName()); txn_manager.CommitTransaction(txn); } @@ -155,8 +177,7 @@ TEST_F(CatalogTests, TestingCatalogCache) { auto txn = txn_manager.BeginTransaction(); auto catalog = catalog::Catalog::GetInstance(); - auto - catalog_db_object = + auto catalog_db_object = catalog->GetDatabaseCatalogEntry(txn, CATALOG_DATABASE_OID); auto catalog_table_objects = catalog_db_object->GetTableCatalogEntries(); EXPECT_NE(0, catalog_table_objects.size()); @@ -171,6 +192,7 @@ TEST_F(CatalogTests, TestingCatalogCache) { auto table = user_database->GetTable(table_idx); auto user_table_object = user_db_object->GetTableCatalogEntry(table->GetOid()); + EXPECT_EQ(user_db_object->GetDatabaseOid(), user_table_object->GetDatabaseOid()); } @@ -182,10 +204,11 @@ TEST_F(CatalogTests, TableObject) { auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); auto txn = txn_manager.BeginTransaction(); - auto table_object = catalog::Catalog::GetInstance()->GetTableCatalogEntry(txn, - "emp_db", - DEFAULT_SCHEMA_NAME, - "department_table"); + auto table_object = + catalog::Catalog::GetInstance()->GetTableCatalogEntry(txn, + "emp_db", + DEFAULT_SCHEMA_NAME, + "department_table"); auto index_objects = table_object->GetIndexCatalogEntries(); auto column_objects = table_object->GetColumnCatalogEntries(); @@ -201,8 +224,8 @@ TEST_F(CatalogTests, TableObject) { EXPECT_EQ(type::Type::GetTypeSize(type::TypeId::INTEGER), column_objects[0]->GetColumnLength()); EXPECT_TRUE(column_objects[0]->IsInlined()); - EXPECT_TRUE(column_objects[0]->IsPrimary()); EXPECT_FALSE(column_objects[0]->IsNotNull()); + EXPECT_FALSE(column_objects[0]->HasDefault()); EXPECT_EQ(table_object->GetTableOid(), column_objects[1]->GetTableOid()); EXPECT_EQ("name", column_objects[1]->GetColumnName()); @@ -211,8 +234,8 @@ TEST_F(CatalogTests, TableObject) { EXPECT_EQ(type::TypeId::VARCHAR, column_objects[1]->GetColumnType()); EXPECT_EQ(32, column_objects[1]->GetColumnLength()); EXPECT_TRUE(column_objects[1]->IsInlined()); - EXPECT_FALSE(column_objects[1]->IsPrimary()); EXPECT_FALSE(column_objects[1]->IsNotNull()); + EXPECT_FALSE(column_objects[1]->HasDefault()); // update pg_table SET version_oid = 1 where table_name = department_table oid_t department_table_oid = table_object->GetTableOid(); @@ -487,6 +510,7 @@ TEST_F(CatalogTests, LayoutCatalogTest) { *(default_layout.get()), *(pg_layout->GetLayoutWithOid(txn, table_oid, default_layout_oid).get())); EXPECT_EQ(default_layout_oid, + catalog->GetTableCatalogEntry(txn, database_oid, table_oid)->GetDefaultLayoutOid()); @@ -546,6 +570,7 @@ TEST_F(CatalogTests, LayoutCatalogTest) { EXPECT_EQ(nullptr, pg_layout->GetLayoutWithOid(txn, table_oid, default_layout_oid)); EXPECT_EQ(ROW_STORE_LAYOUT_OID, + catalog->GetTableCatalogEntry(txn, database_oid, table_oid)->GetDefaultLayoutOid()); @@ -562,5 +587,307 @@ TEST_F(CatalogTests, LayoutCatalogTest) { txn_manager.CommitTransaction(txn); } +TEST_F(CatalogTests, ConstraintCatalogTest) { + auto db_name = "con_db"; + auto sink_table_name = "sink_table"; + auto con_table_name = "con_table"; + auto catalog = catalog::Catalog::GetInstance(); + // Create database. + auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); + auto txn = txn_manager.BeginTransaction(); + EXPECT_EQ(ResultType::SUCCESS, catalog->CreateDatabase(txn, db_name)); + + // Create table for foreign key. + auto sink_val0 = catalog::Column( + type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), + "sink_val0", true); + std::unique_ptr sink_table_schema( + new catalog::Schema({sink_val0})); + EXPECT_EQ(ResultType::SUCCESS, + catalog->CreateTable(txn, + db_name, + DEFAULT_SCHEMA_NAME, + std::move(sink_table_schema), + sink_table_name, + false)); + + // Create table for constraint catalog test, and set column constraints. + auto con_val0 = catalog::Column( + type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), + "con_val0", true); + auto con_val1 = catalog::Column( + type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), + "con_val1", true); + auto con_val2 = catalog::Column( + type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), + "con_val2", true); + auto con_val3 = catalog::Column( + type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), + "con_val3", true); + auto con_val4 = catalog::Column( + type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), + "con_val4", true); + auto con_val5 = catalog::Column( + type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), + "con_val5", true); + auto con_val6 = catalog::Column( + type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), + "con_val6", true); + con_val5.SetNotNull(); + con_val6.SetDefaultValue(type::ValueFactory::GetIntegerValue(555)); + std::unique_ptr con_table_schema(new catalog::Schema( + {con_val0, con_val1, con_val2, con_val3, con_val4, con_val5, con_val6})); + EXPECT_EQ(ResultType::SUCCESS, + catalog->CreateTable(txn, + db_name, + DEFAULT_SCHEMA_NAME, + std::move(con_table_schema), + con_table_name, + false)); + + LOG_DEBUG("Success two table creations"); + + auto database_oid = + catalog->GetDatabaseCatalogEntry(txn, db_name)->GetDatabaseOid(); + auto sink_table_object = catalog->GetTableCatalogEntry(txn, + db_name, + DEFAULT_SCHEMA_NAME, + sink_table_name); + auto sink_table = catalog->GetTableWithName(txn, + db_name, + DEFAULT_SCHEMA_NAME, + sink_table_name); + auto sink_table_oid = sink_table_object->GetTableOid(); + auto con_table_object = catalog->GetTableCatalogEntry(txn, + db_name, + DEFAULT_SCHEMA_NAME, + con_table_name); + auto con_table = catalog->GetTableWithName(txn, + db_name, + DEFAULT_SCHEMA_NAME, + con_table_name); + auto con_table_oid = con_table_object->GetTableOid(); + + // Add primary key constraint to sink table + EXPECT_EQ(ResultType::SUCCESS, + catalog->AddPrimaryKeyConstraint(txn, + database_oid, + sink_table_oid, + {0}, + "con_primary")); + + // Add constraints for constraint catalog test. + EXPECT_EQ(ResultType::SUCCESS, + catalog->AddPrimaryKeyConstraint(txn, + database_oid, + con_table_oid, + {0, 1}, + "con_primary")); + EXPECT_EQ(ResultType::SUCCESS, + catalog->AddUniqueConstraint(txn, + database_oid, + con_table_oid, + {2}, + "con_unique")); + + EXPECT_EQ(ResultType::SUCCESS, + catalog->AddForeignKeyConstraint(txn, + database_oid, + con_table_oid, + {3}, + sink_table_oid, + {0}, + FKConstrActionType::NOACTION, + FKConstrActionType::NOACTION, + "con_foreign")); + auto exp = std::make_pair(ExpressionType::COMPARE_GREATERTHAN, + type::ValueFactory::GetIntegerValue(0)); + EXPECT_EQ(ResultType::SUCCESS, + catalog->AddCheckConstraint(txn, + database_oid, + con_table_oid, + {4}, + exp, + "con_check")); + + LOG_DEBUG("Success all constraint creations"); + + // Check constraint + auto sink_schema = sink_table->GetSchema(); + EXPECT_EQ(false, sink_schema->HasForeignKeys()); + EXPECT_EQ(true, sink_schema->HasPrimary()); + EXPECT_EQ(false, sink_schema->HasUniqueConstraints()); + auto constraint_objects = sink_table_object->GetConstraintCatalogEntries(); + EXPECT_EQ(1, constraint_objects.size()); + for (auto constraint_object_pair : constraint_objects) { + auto con_oid = constraint_object_pair.first; + auto con_object = constraint_object_pair.second; + auto column_ids = con_object->GetColumnIds(); + EXPECT_LE(1, column_ids.size()); + auto constraint = sink_table->GetSchema()->GetConstraint(con_oid); + EXPECT_EQ(constraint->GetName(), con_object->GetConstraintName()); + EXPECT_EQ(constraint->GetType(), con_object->GetConstraintType()); + EXPECT_EQ(constraint->GetTableOid(), con_object->GetTableOid()); + EXPECT_EQ(constraint->GetIndexOid(), con_object->GetIndexOid()); + EXPECT_EQ(constraint->GetColumnIds().size(), column_ids.size()); + } + + // Check foreign key as sink table + EXPECT_EQ(true, sink_schema->HasForeignKeySources()); + auto fk_sources = sink_schema->GetForeignKeySources(); + EXPECT_EQ(1, fk_sources.size()); + auto fk_source = fk_sources.at(0); + EXPECT_EQ(con_table_oid, fk_source->GetTableOid()); + EXPECT_EQ(sink_table_oid, fk_source->GetFKSinkTableOid()); + + LOG_DEBUG("%s", sink_schema->GetInfo().c_str()); + LOG_DEBUG("Complete check for sink table"); + + // Single column constraints + for (auto column_object_pair : con_table_object->GetColumnCatalogEntries()) { + auto column_id = column_object_pair.first; + auto column_object = column_object_pair.second; + auto column = con_table->GetSchema()->GetColumn(column_id); + + if (column_object->GetColumnName() == "con_val5") { + LOG_DEBUG("Check not null constraint in column:%s", + column_object->GetColumnName().c_str()); + EXPECT_TRUE(column_object->IsNotNull()); + EXPECT_EQ(column.IsNotNull(), column_object->IsNotNull()); + } else if (column_object->GetColumnName() == "con_val6") { + LOG_DEBUG("Check default constraint in column:%s", + column_object->GetColumnName().c_str()); + EXPECT_TRUE(column_object->HasDefault()); + EXPECT_EQ(column.HasDefault(), column_object->HasDefault()); + EXPECT_EQ(column.GetDefaultValue()->CompareEquals( + column_object->GetDefaultValue()), + CmpBool::CmpTrue); + } + } + + // Table constraints + auto con_schema = con_table->GetSchema(); + EXPECT_EQ(true, con_schema->HasForeignKeys()); + EXPECT_EQ(true, con_schema->HasPrimary()); + EXPECT_EQ(true, con_schema->HasUniqueConstraints()); + EXPECT_EQ(false, con_schema->HasForeignKeySources()); + constraint_objects = con_table_object->GetConstraintCatalogEntries(); + EXPECT_EQ(4, constraint_objects.size()); + for (auto constraint_object_pair : constraint_objects) { + auto con_oid = constraint_object_pair.first; + auto con_object = constraint_object_pair.second; + + LOG_DEBUG("Check constraint:%s (%s)", + con_object->GetConstraintName().c_str(), + ConstraintTypeToString(con_object->GetConstraintType()).c_str()); + + auto constraint = con_table->GetSchema()->GetConstraint(con_oid); + EXPECT_NE(nullptr, constraint); + EXPECT_EQ(constraint->GetName(), con_object->GetConstraintName()); + EXPECT_EQ(constraint->GetType(), con_object->GetConstraintType()); + EXPECT_EQ(con_table_oid, con_object->GetTableOid()); + EXPECT_EQ(constraint->GetIndexOid(), con_object->GetIndexOid()); + EXPECT_EQ(constraint->GetColumnIds().size(), + con_object->GetColumnIds().size()); + + switch (con_object->GetConstraintType()) { + case ConstraintType::PRIMARY: + case ConstraintType::UNIQUE: + break; + + case ConstraintType::FOREIGN: { + EXPECT_EQ(fk_source.get(), constraint.get()); + EXPECT_EQ(constraint->GetFKSinkTableOid(), + con_object->GetFKSinkTableOid()); + EXPECT_EQ(constraint->GetFKSinkColumnIds().size(), + con_object->GetFKSinkColumnIds().size()); + EXPECT_EQ(constraint->GetFKUpdateAction(), + con_object->GetFKUpdateAction()); + EXPECT_EQ(constraint->GetFKDeleteAction(), + con_object->GetFKDeleteAction()); + break; + } + + case ConstraintType::CHECK: { + EXPECT_EQ(1, con_object->GetColumnIds().size()); + auto column = + con_table->GetSchema()->GetColumn(con_object->GetColumnIds().at(0)); + EXPECT_EQ(constraint->GetCheckExpression().first, + con_object->GetCheckExp().first); + EXPECT_EQ(constraint->GetCheckExpression().second.CompareEquals( + con_object->GetCheckExp().second), + CmpBool::CmpTrue); + break; + } + default: + LOG_DEBUG( + "Unexpected constraint appeared: %s", + ConstraintTypeToString(con_object->GetConstraintType()).c_str()); + EXPECT_TRUE(false); + } + } + con_table_object->GetConstraintCatalogEntries(); + + txn_manager.CommitTransaction(txn); + + LOG_DEBUG("%s", con_schema->GetInfo().c_str()); + LOG_DEBUG("Complete check for constraint table"); + + // Drop constraint + txn = txn_manager.BeginTransaction(); + for (auto not_null_column_id : con_schema->GetNotNullColumns()) { + EXPECT_EQ(ResultType::SUCCESS, + catalog->DropNotNullConstraint(txn, + database_oid, + con_table_oid, + not_null_column_id)); + } + EXPECT_EQ(ResultType::SUCCESS, + catalog->DropDefaultConstraint(txn, + database_oid, + con_table_oid, + 6)); + for (auto constraint : con_schema->GetConstraints()) { + EXPECT_EQ( + ResultType::SUCCESS, + catalog->DropConstraint(txn, + database_oid, + con_table_oid, + constraint.second->GetConstraintOid())); + } + txn_manager.CommitTransaction(txn); + + LOG_DEBUG("%s", con_schema->GetInfo().c_str()); + LOG_DEBUG("Complete drop constraints in constraint table"); + + // Check dropping constraints + txn = txn_manager.BeginTransaction(); + con_table_object = catalog->GetTableCatalogEntry(txn, + db_name, + DEFAULT_SCHEMA_NAME, + con_table_name); + EXPECT_EQ(0, con_schema->GetNotNullColumns().size()); + for (oid_t column_id = 0; column_id < con_schema->GetColumnCount(); column_id++) { + EXPECT_EQ(true, con_schema->AllowNull(column_id)); + EXPECT_EQ(false, con_schema->AllowDefault(column_id)); + } + for (auto column_object_pair : con_table_object->GetColumnCatalogEntries()) { + auto column_object = column_object_pair.second; + EXPECT_EQ(false, column_object->IsNotNull()); + EXPECT_EQ(false, column_object->HasDefault()); + } + EXPECT_EQ(false, con_schema->HasForeignKeys()); + EXPECT_EQ(false, con_schema->HasPrimary()); + EXPECT_EQ(false, con_schema->HasUniqueConstraints()); + EXPECT_EQ(false, sink_table->GetSchema()->HasForeignKeySources()); + EXPECT_EQ(0, con_table_object->GetConstraintCatalogEntries().size()); + txn_manager.CommitTransaction(txn); + + // Drop database + txn = txn_manager.BeginTransaction(); + catalog->DropDatabaseWithName(txn, db_name); + txn_manager.CommitTransaction(txn); +} + } // namespace test } // namespace peloton diff --git a/test/catalog/constraints_test.cpp b/test/catalog/constraints_test.cpp index 8235e85e9a9..f9563f9b251 100644 --- a/test/catalog/constraints_test.cpp +++ b/test/catalog/constraints_test.cpp @@ -16,7 +16,6 @@ #include "catalog/testing_constraints_util.h" #include "catalog/catalog.h" -#include "catalog/foreign_key.h" #include "common/internal_types.h" #include "concurrency/testing_transaction_util.h" #include "executor/executors.h" @@ -29,7 +28,9 @@ #define CONSTRAINT_NOTNULL_TEST #define CONSTRAINT_DEFAULT_TEST -//#define CONSTRAINT_CHECK_TEST +// #define CONSTRAINT_CHECK_TEST +#define CONSTRAINT_UNIQUE_TEST +#define CONSTRAINT_FOREIGN_KEY_TEST namespace peloton { namespace test { @@ -52,15 +53,14 @@ TEST_F(ConstraintsTests, NOTNULLTest) { // 140 141 142 "143" // Set all of the columns to be NOT NULL - std::vector> constraints; + std::vector notnull_col_ids; for (int i = 0; i < CONSTRAINTS_NUM_COLS; i++) { - constraints.push_back( - {catalog::Constraint(ConstraintType::NOTNULL, "notnull_constraint")}); + notnull_col_ids.push_back(i); } - std::vector multi_constraints; + std::unordered_map default_values; storage::DataTable *data_table = - TestingConstraintsUtil::CreateAndPopulateTable(constraints, - multi_constraints); + TestingConstraintsUtil::CreateTable(notnull_col_ids, default_values); + TestingConstraintsUtil::PopulateTable(data_table); // Bootstrap auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); @@ -113,29 +113,43 @@ TEST_F(ConstraintsTests, NOTNULLTest) { #ifdef CONSTRAINT_DEFAULT_TEST TEST_F(ConstraintsTests, DEFAULTTEST) { - // Set all of the columns to be NOT NULL - std::vector> constraints; + // Set default value within col_B + std::vector notnull_col_ids; + std::unordered_map default_values; for (int i = 0; i < CONSTRAINTS_NUM_COLS; i++) { + // COL_B + if (i == 1) { + default_values[i] = type::ValueFactory::GetIntegerValue(DEFAULT_VALUE); + } + // COL_A + COL_C + COL_D + else { + // do nothing + } + } + storage::DataTable *data_table = + TestingConstraintsUtil::CreateTable(notnull_col_ids, default_values); + // Add primary key + auto catalog = catalog::Catalog::GetInstance(); + auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); + auto txn = txn_manager.BeginTransaction(); + for (oid_t i = 0; i < CONSTRAINTS_NUM_COLS; i++) { // COL_A if (i == 0) { - constraints.push_back( - {catalog::Constraint(ConstraintType::PRIMARY, "pkey")}); - } - // COL_B - else if (i == 1) { - catalog::Constraint default_const(ConstraintType::DEFAULT, "default"); - default_const.addDefaultValue( - type::ValueFactory::GetIntegerValue(DEFAULT_VALUE)); - constraints.push_back({}); + catalog->AddPrimaryKeyConstraint(txn, + data_table->GetDatabaseOid(), + data_table->GetOid(), + {i}, + "con_primary"); } - // COL_C + COL_D + // COL_B + COL_C + COL_D else { - constraints.push_back({}); + // do nothing } } - std::vector multi_constraints; - TestingConstraintsUtil::CreateAndPopulateTable(constraints, - multi_constraints); + txn_manager.CommitTransaction(txn); + + // populate test data + TestingConstraintsUtil::PopulateTable(data_table); // Bootstrap std::vector result; @@ -153,13 +167,14 @@ TEST_F(ConstraintsTests, DEFAULTTEST) { rows_affected, error_message); EXPECT_EQ(ResultType::SUCCESS, status); - sql = StringUtil::Format("SELECT col_d FROM %s WHERE col_a = 9999", + sql = StringUtil::Format("SELECT col_b FROM %s WHERE col_a = 9999", CONSTRAINTS_TEST_TABLE); status = TestingSQLUtil::ExecuteSQLQuery(sql, result, tuple_descriptor, rows_affected, error_message); EXPECT_EQ(ResultType::SUCCESS, status); std::string resultStr = TestingSQLUtil::GetResultValueAsString(result, 0); - LOG_INFO("OUTPUT:\n%s", resultStr.c_str()); + EXPECT_EQ(std::to_string(DEFAULT_VALUE), resultStr); + LOG_INFO("OUTPUT:%s", resultStr.c_str()); } #endif @@ -173,32 +188,47 @@ TEST_F(ConstraintsTests, CHECKTest) { // 20 21 22 "23" // ..... // 140 141 142 "143" + auto catalog = catalog::Catalog::GetInstance(); + auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); + auto txn = txn_manager.BeginTransaction(); + catalog->CreateDatabase(txn, DEFAULT_DB_NAME); auto column1 = catalog::Column(type::TypeId::INTEGER, 25, "A", false, 0); - auto constraints = catalog::Constraint(ConstraintType::CHECK, "check1"); - type::Value tmp_value = type::ValueFactory::GetIntegerValue(0); - constraints.AddCheck(ExpressionType::COMPARE_GREATERTHAN, tmp_value); - column1.AddConstraint(constraints); - LOG_DEBUG("%s %s", peloton::DOUBLE_STAR.c_str(), - constraints.GetInfo().c_str()); - catalog::Schema *table_schema = new catalog::Schema({column1}); - std::string table_name("TEST_TABLE"); - bool own_schema = true; - bool adapt_table = false; - storage::DataTable *table = storage::TableFactory::GetDataTable( - INVALID_OID, INVALID_OID, table_schema, table_name, - TESTS_TUPLES_PER_TILEGROUP, own_schema, adapt_table); - std::unique_ptr data_table(table); + std::unique_ptr table_schema(new catalog::Schema({column1})); - auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); + std::string table_name("TEST_TABLE"); + auto result = + catalog->CreateTable(txn, + DEFAULT_DB_NAME, + DEFAULT_SCHEMA_NAME, + std::move(table_schema), + table_name, + false); + EXPECT_EQ(ResultType::SUCCESS, result); + + auto data_table = catalog->GetTableWithName(txn, + DEFAULT_DB_NAME, + DEFAULT_SCHEMA_NAME, + table_name); + EXPECT_NE(nullptr, data_table); + + // add check constraint + type::Value tmp_value = type::ValueFactory::GetIntegerValue(0); + catalog->AddCheckConstraint(txn, + data_table->GetDatabaseOid(), + data_table->GetOid(), + {0}, + std::make_pair(ExpressionType::COMPARE_GREATERTHAN, tmp_value), + "con_check"); + txn_manager.CommitTransaction(txn); // begin this transaction - auto txn = txn_manager.BeginTransaction(); + txn = txn_manager.BeginTransaction(); // Test1: insert a tuple with column meet the constraint requirment bool hasException = false; try { TestingConstraintsUtil::ExecuteOneInsert( - txn, data_table.get(), type::ValueFactory::GetIntegerValue(10)); + txn, data_table, type::ValueFactory::GetIntegerValue(10)); } catch (ConstraintException e) { hasException = true; } @@ -208,7 +238,7 @@ TEST_F(ConstraintsTests, CHECKTest) { hasException = false; try { TestingConstraintsUtil::ExecuteOneInsert( - txn, data_table.get(), type::ValueFactory::GetIntegerValue(-1)); + txn, data_table, type::ValueFactory::GetIntegerValue(-1)); } catch (ConstraintException e) { hasException = true; } @@ -216,7 +246,11 @@ TEST_F(ConstraintsTests, CHECKTest) { // commit this transaction txn_manager.CommitTransaction(txn); - delete data_table.release(); + + txn = txn_manager.BeginTransaction(); + auto result = catalog->DropDatabaseWithName(txn, DEFAULT_DB_NAME); + EXPECT_EQ(ResultType::SUCCESS, result); + txn_manager.CommitTransaction(txn); } #endif @@ -225,355 +259,350 @@ TEST_F(ConstraintsTests, UNIQUETest) { auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); auto catalog = catalog::Catalog::GetInstance(); auto txn = txn_manager.BeginTransaction(); - catalog->CreateDatabase(DEFAULT_DB_NAME, nullptr); - auto column1 = catalog::Column(type::TypeId::INTEGER, 25, "A", false, 0); - auto column2 = catalog::Column(type::TypeId::INTEGER, 25, "B", false, 1); + std::string db_name = "db1"; + catalog->CreateDatabase(txn, db_name); + auto column1 = catalog::Column(type::TypeId::INTEGER, 25, "A", false); + auto column2 = catalog::Column(type::TypeId::INTEGER, 25, "B", false); - auto constraints = catalog::Constraint(ConstraintType::UNIQUE, "unique1"); - column1.AddConstraint(constraints); - LOG_DEBUG("%s %s", peloton::DOUBLE_STAR.c_str(), - constraints.GetInfo().c_str()); std::unique_ptr table_schema( new catalog::Schema({column1, column2})); std::string table_name("TEST_TABLE"); - catalog::Catalog::GetInstance()->CreateTable(txn, DEFAULT_DB_NAME, - DEFAULT_SCHEMA_NAME, - std::move(table_schema), - table_name, - false); - storage::DataTable *table = catalog::Catalog::GetInstance()->GetTableWithName( - DEFAULT_DB_NAME, DEFAULT_SCHEMA_NAME, table_name, txn); + catalog->CreateTable(txn, + db_name, + DEFAULT_SCHEMA_NAME, + std::move(table_schema), + table_name, + false); + + auto table = catalog->GetTableWithName(txn, + db_name, + DEFAULT_SCHEMA_NAME, + table_name); + catalog->AddUniqueConstraint(txn, + table->GetDatabaseOid(), + table->GetOid(), + {0}, + "con_unique"); txn_manager.CommitTransaction(txn); - // table->AddUNIQUEIndex(); - txn = txn_manager.BeginTransaction(); // begin this transaction - // Test1: insert a tuple with column meet the unique requirment - bool hasException = false; - try { - // bool result = true; - // result = - TestingConstraintsUtil::ExecuteOneInsert( - txn, table, type::ValueFactory::GetIntegerValue(10)); - // if (result == false) hasException = true; - } catch (ConstraintException e) { - hasException = true; - } - EXPECT_FALSE(hasException); + // Test1: insert a tuple with column meet the unique requirement + bool result = TestingConstraintsUtil::ExecuteOneInsert( + txn, table, type::ValueFactory::GetIntegerValue(10)); + EXPECT_TRUE(result); // Test2: insert not a valid column violate the constraint - hasException = false; - try { - // bool result = true; - // result = - TestingConstraintsUtil::ExecuteOneInsert( + result = TestingConstraintsUtil::ExecuteOneInsert( txn, table, type::ValueFactory::GetIntegerValue(10)); - // if (result == false) hasException = true; - } catch (ConstraintException e) { - hasException = true; - } - EXPECT_TRUE(hasException); + EXPECT_FALSE(result); - hasException = false; - try { - TestingConstraintsUtil::ExecuteOneInsert( + result = TestingConstraintsUtil::ExecuteOneInsert( txn, table, type::ValueFactory::GetIntegerValue(20)); - } catch (ConstraintException e) { - hasException = true; - } - EXPECT_FALSE(hasException); + EXPECT_TRUE(result); // commit this transaction txn_manager.CommitTransaction(txn); txn = txn_manager.BeginTransaction(); - catalog::Catalog::GetInstance()->DropDatabaseWithName(DEFAULT_DB_NAME, txn); + catalog->DropDatabaseWithName(txn, db_name); + txn_manager.CommitTransaction(txn); +} + + TEST_F(ConstraintsTests, MULTIUNIQUETest) { + auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); + auto catalog = catalog::Catalog::GetInstance(); + auto txn = txn_manager.BeginTransaction(); + std::string db_name = "db1"; + catalog->CreateDatabase(txn, db_name); + auto column1 = catalog::Column(type::TypeId::INTEGER, 25, "A", false); + auto column2 = catalog::Column(type::TypeId::INTEGER, 25, "B", false); + auto column3 = catalog::Column(type::TypeId::INTEGER, 25, "C", false); + std::vector cols; + cols.push_back(0); + cols.push_back(1); + std::vector columns; + columns.push_back(column1); + columns.push_back(column2); + columns.push_back(column3); + std::unique_ptr table_schema(new catalog::Schema(columns)); + std::string table_name("TEST_TABLE_1"); + catalog->CreateTable(txn, + db_name, + DEFAULT_SCHEMA_NAME, + std::move(table_schema), + table_name, + false); + + // Add multi-unique constraint + auto table = catalog->GetTableWithName(txn, + db_name, + DEFAULT_SCHEMA_NAME, + table_name); + catalog->AddUniqueConstraint(txn, + table->GetDatabaseOid(), + table->GetOid(), + cols, + "con_unique"); + txn_manager.CommitTransaction(txn); + + txn = txn_manager.BeginTransaction(); + // begin this transaction + // Test1: insert a tuple with column meet the unique requirment + std::vector ccs; + ccs.push_back(type::ValueFactory::GetIntegerValue(10)); + ccs.push_back(type::ValueFactory::GetIntegerValue(11)); + bool result = TestingConstraintsUtil::ExecuteMultiInsert(txn, table, ccs); + EXPECT_TRUE(result); + + // Test2: insert not a valid column violate the constraint + ccs.clear(); + ccs.push_back(type::ValueFactory::GetIntegerValue(10)); + ccs.push_back(type::ValueFactory::GetIntegerValue(11)); + result = TestingConstraintsUtil::ExecuteMultiInsert(txn, table, ccs); + EXPECT_FALSE(result); + + ccs.clear(); + ccs.push_back(type::ValueFactory::GetIntegerValue(10)); + ccs.push_back(type::ValueFactory::GetIntegerValue(12)); + result = TestingConstraintsUtil::ExecuteMultiInsert(txn, table, ccs); + EXPECT_TRUE(result); + + // commit this transaction + txn_manager.CommitTransaction(txn); + txn = txn_manager.BeginTransaction(); + catalog::Catalog::GetInstance()->DropDatabaseWithName(txn, db_name); txn_manager.CommitTransaction(txn); } #endif -// TEST_F(ConstraintsTests, MULTIUNIQUETest) { -// auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); -// auto catalog = catalog::Catalog::GetInstance(); -// auto txn = txn_manager.BeginTransaction(); -// std::string db_name = "db1"; -// catalog->CreateDatabase(db_name, nullptr); -// auto column1 = catalog::Column(type::TypeId::INTEGER, 25, "A", false, 0); -// auto column2 = catalog::Column(type::TypeId::INTEGER, 25, "B", false, 1); -// auto column3 = catalog::Column(type::TypeId::INTEGER, 25, "C", false, 2); -// std::vector cols; -// cols.push_back(0); -// cols.push_back(1); -// std::vector columns; -// columns.push_back(column1); -// columns.push_back(column2); -// columns.push_back(column3); -// auto mc = catalog::MultiConstraint(ConstraintType::UNIQUE, "c1", cols); -// LOG_DEBUG("%s MULTI CONSTRAINTS %s %s", peloton::DOUBLE_STAR.c_str(), -// peloton::DOUBLE_STAR.c_str(), mc.GetInfo().c_str()); -// -// std::unique_ptr table_schema(new catalog::Schema(columns)); -// table_schema->AddMultiConstraints(mc); -// std::string table_name("TEST_TABLE_1"); -// catalog->CreateTable(db_name, table_name, std::move(table_schema), txn); -// txn_manager.CommitTransaction(txn); -// storage::Database *database = catalog->GetDatabaseWithName(db_name); -// storage::DataTable *table = database->GetTableWithName(table_name); -// -// // table->AddUNIQUEIndex(); -// -// txn = txn_manager.BeginTransaction(); -// // begin this transaction -// // Test1: insert a tuple with column meet the unique requirment -// bool hasException = false; -// try { -// std::vector ccs; -// ccs.push_back(type::ValueFactory::GetIntegerValue(10)); -// ccs.push_back(type::ValueFactory::GetIntegerValue(11)); -// // bool result = true; -// // result = -// TestingConstraintsUtil::ExecuteMultiInsert(txn, table, ccs); -// // if (result == false) hasException = true; -// } catch (ConstraintException e) { -// hasException = true; -// } -// EXPECT_FALSE(hasException); -// -// // Test2: insert not a valid column violate the constraint -// hasException = false; -// try { -// std::vector ccs; -// ccs.push_back(type::ValueFactory::GetIntegerValue(10)); -// ccs.push_back(type::ValueFactory::GetIntegerValue(11)); -// // bool result = true; -// // result = -// TestingConstraintsUtil::ExecuteMultiInsert(txn, table, ccs); -// // if (result == false) hasException = true; -// } catch (ConstraintException e) { -// hasException = true; -// } -// EXPECT_TRUE(hasException); -// -// hasException = false; -// try { -// std::vector ccs; -// ccs.push_back(type::ValueFactory::GetIntegerValue(10)); -// ccs.push_back(type::ValueFactory::GetIntegerValue(12)); -// TestingConstraintsUtil::ExecuteMultiInsert(txn, table, ccs); -// } catch (ConstraintException e) { -// hasException = true; -// } -// EXPECT_FALSE(hasException); -// -// // commit this transaction -// txn_manager.CommitTransaction(txn); -// txn = txn_manager.BeginTransaction(); -// catalog::Catalog::GetInstance()->DropDatabaseWithName(db_name, txn); -// txn_manager.CommitTransaction(txn); -//} - -// TEST_F(ConstraintsTests, ForeignKeySingleInsertTest) { -// // First, initial 2 tables like following -// // TABLE A -- src table TABLE B -- sink table -// // a int(primary, ref B) b int b int(primary) c int -// // 0 0 0 0 -// // 1 0 1 0 -// // 2 0 2 0 -// // ..... -// // 9 0 -// -// // create new db -// auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); -// auto txn = txn_manager.BeginTransaction(); -// auto catalog = catalog::Catalog::GetInstance(); -// std::string db_name = "db2"; -// std::string table_a_name = "tableA"; -// std::string table_b_name = "tableB"; -// catalog::Catalog::GetInstance()->CreateDatabase(db_name, nullptr); -// // txn_manager.CommitTransaction(txn); -// -// auto column1 = catalog::Column(type::TypeId::INTEGER, 25, "a", false, 0); -// auto column2 = catalog::Column(type::TypeId::INTEGER, 25, "b", false, 1); -// -// auto constraints = catalog::Constraint(ConstraintType::PRIMARY, "primary1"); -// column1.AddConstraint(constraints); -// LOG_DEBUG("%s %s", peloton::DOUBLE_STAR.c_str(), -// constraints.GetInfo().c_str()); std::unique_ptr -// tableA_schema( -// new catalog::Schema({column1, column2})); -// -// catalog->CreateTable(db_name, table_a_name, std::move(tableA_schema), txn); -// txn_manager.CommitTransaction(txn); -// -// txn = txn_manager.BeginTransaction(); -// auto column3 = catalog::Column(type::TypeId::INTEGER, 25, "b", false, 0); -// column3.AddConstraint(constraints); -// auto column4 = catalog::Column(type::TypeId::INTEGER, 25, "c", false, 1); -// std::unique_ptr tableB_schema( -// new catalog::Schema({column3, column4})); -// -// catalog->CreateTable(db_name, table_b_name, std::move(tableB_schema), txn); -// -// auto table_a = catalog->GetTableWithName(db_name, table_a_name); -// auto table_b = catalog->GetTableWithName(db_name, table_b_name); -// -// oid_t sink_table_id = table_b->GetOid(); -// std::vector sink_col_ids = { table_b->GetSchema()->GetColumnID("b") -// }; std::vector source_col_ids = { -// table_a->GetSchema()->GetColumnID("a") }; catalog::ForeignKey *foreign_key = -// new catalog::ForeignKey( -// sink_table_id, sink_col_ids, source_col_ids, -// FKConstrActionType::NOACTION, -// FKConstrActionType::NOACTION, -// "foreign_constraint1"); -// table_a->AddForeignKey(foreign_key); -// -// txn = txn_manager.BeginTransaction(); -// // begin this transaction -// // Test1: insert a tuple with column meet the unique requirment -// bool hasException = false; -// try { -// std::vector ccs; -// ccs.push_back(type::ValueFactory::GetIntegerValue(1)); -// ccs.push_back(type::ValueFactory::GetIntegerValue(2)); -// TestingConstraintsUtil::ExecuteMultiInsert(txn, table_b, ccs); -// ccs.clear(); -// ccs.push_back(type::ValueFactory::GetIntegerValue(1)); -// ccs.push_back(type::ValueFactory::GetIntegerValue(2)); -// TestingConstraintsUtil::ExecuteMultiInsert(txn, table_a, ccs); -// } catch (ConstraintException e) { -// hasException = true; -// } -// EXPECT_FALSE(hasException); -// -// hasException = true; -// try { -// std::vector ccs; -// ccs.push_back(type::ValueFactory::GetIntegerValue(3)); -// ccs.push_back(type::ValueFactory::GetIntegerValue(4)); -// TestingConstraintsUtil::ExecuteMultiInsert(txn, table_b, ccs); -// ccs.clear(); -// ccs.push_back(type::ValueFactory::GetIntegerValue(2)); -// ccs.push_back(type::ValueFactory::GetIntegerValue(5)); -// TestingConstraintsUtil::ExecuteMultiInsert(txn, table_a, ccs); -// } catch (ConstraintException e) { -// hasException = true; -// } -// EXPECT_TRUE(hasException); -// -// // commit this transaction -// txn_manager.CommitTransaction(txn); -// txn = txn_manager.BeginTransaction(); -// catalog::Catalog::GetInstance()->DropDatabaseWithName(db_name, txn); -// txn_manager.CommitTransaction(txn); -// delete foreign_key; -//} - -// TEST_F(ConstraintsTests, ForeignKeyMultiInsertTest) { -// // First, initial 2 tables like following -// // TABLE A -- src table TABLE B -- sink table -// // a int(primary, ref B) b int b int(primary) c int -// // 0 0 0 0 -// // 1 0 1 0 -// // 2 0 2 0 -// // ..... -// // 9 0 -// -// // create new db -// auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); -// auto txn = txn_manager.BeginTransaction(); -// auto catalog = catalog::Catalog::GetInstance(); -// std::string db_name = "db2"; -// std::string table_a_name = "tableA"; -// std::string table_b_name = "tableB"; -// catalog->CreateDatabase(db_name, txn); -// -// // TABLE A -// auto column1 = catalog::Column(type::TypeId::INTEGER, 25, "a", false, 0); -// auto column2 = catalog::Column(type::TypeId::INTEGER, 25, "b", false, 1); -// std::unique_ptr tableA_schema( -// new catalog::Schema({column1, column2})); -// catalog->CreateTable(db_name, table_a_name, std::move(tableA_schema), txn); -// txn_manager.CommitTransaction(txn); -// auto table_A = catalog->GetTableWithName(db_name, table_a_name); -// -// txn = txn_manager.BeginTransaction(); -// auto column3 = catalog::Column(type::TypeId::INTEGER, 25, "b", false, 0); -// auto column4 = catalog::Column(type::TypeId::INTEGER, 25, "c", false, 1); -// std::vector cols; -// cols.push_back(0); -// cols.push_back(1); -// auto mc = -// catalog::MultiConstraint(ConstraintType::PRIMARY, "multiprimary1", -// cols); -// LOG_DEBUG("%s MULTI CONSTRAINTS %s %s", peloton::DOUBLE_STAR.c_str(), -// peloton::DOUBLE_STAR.c_str(), mc.GetInfo().c_str()); -// -// // TABLE B -// catalog::Schema *table_schema = new catalog::Schema({column3, column4}); -// table_schema->AddMultiConstraints(mc); -// std::unique_ptr tableB_schema(table_schema); -// -// catalog->CreateTable(db_name, table_b_name, std::move(tableB_schema), txn); -// auto table_a = catalog->GetTableWithName(db_name, table_a_name); -// auto table_b = catalog->GetTableWithName(db_name, table_b_name); -// txn_manager.CommitTransaction(txn); -// -// // Create foreign key tableA.B -> tableB.B -// oid_t sink_table_id = table_b->GetOid(); -// std::vector sink_col_ids = { table_b->GetSchema()->GetColumnID("b") -// }; std::vector source_col_ids = { -// table_a->GetSchema()->GetColumnID("b") }; catalog::ForeignKey *foreign_key = -// new catalog::ForeignKey( -// sink_table_id, sink_col_ids, source_col_ids, -// FKConstrActionType::RESTRICT, -// FKConstrActionType::CASCADE, -// "foreign_constraint1"); -// table_A->AddForeignKey(foreign_key); -// -// // Test1: insert a tuple with column meet the constraint requirment -// -// txn = txn_manager.BeginTransaction(); -// // begin this transaction -// // Test1: insert a tuple with column meet the unique requirment -// bool hasException = false; -// try { -// std::vector ccs; -// ccs.push_back(type::ValueFactory::GetIntegerValue(1)); -// ccs.push_back(type::ValueFactory::GetIntegerValue(2)); -// TestingConstraintsUtil::ExecuteMultiInsert(txn, table_b, ccs); -// ccs.clear(); -// ccs.push_back(type::ValueFactory::GetIntegerValue(2)); -// ccs.push_back(type::ValueFactory::GetIntegerValue(1)); -// TestingConstraintsUtil::ExecuteMultiInsert(txn, table_a, ccs); -// } catch (ConstraintException e) { -// hasException = true; -// } -// EXPECT_FALSE(hasException); -// -// hasException = true; -// try { -// std::vector ccs; -// ccs.push_back(type::ValueFactory::GetIntegerValue(3)); -// ccs.push_back(type::ValueFactory::GetIntegerValue(4)); -// TestingConstraintsUtil::ExecuteMultiInsert(txn, table_b, ccs); -// ccs.clear(); -// ccs.push_back(type::ValueFactory::GetIntegerValue(2)); -// ccs.push_back(type::ValueFactory::GetIntegerValue(5)); -// TestingConstraintsUtil::ExecuteMultiInsert(txn, table_a, ccs); -// } catch (ConstraintException e) { -// hasException = true; -// } -// EXPECT_TRUE(hasException); -// -// // commit this transaction -// txn_manager.CommitTransaction(txn); -// txn = txn_manager.BeginTransaction(); -// catalog::Catalog::GetInstance()->DropDatabaseWithName(db_name, txn); -// txn_manager.CommitTransaction(txn); -// delete foreign_key; -//} +#ifdef CONSTRAINT_FOREIGN_KEY_TEST + TEST_F(ConstraintsTests, ForeignKeySingleInsertTest) { + // First, initial 2 tables like following + // TABLE A -- src table TABLE B -- sink table + // a int(primary) b int(ref B) b int(primary) c int + // 0 0 0 0 + // 1 1 1 0 + // 2 2 2 0 + // ..... + // 9 0 + + // create new db + auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); + auto txn = txn_manager.BeginTransaction(); + auto catalog = catalog::Catalog::GetInstance(); + std::string db_name = "db2"; + std::string table_a_name = "tableA"; + std::string table_b_name = "tableB"; + catalog::Catalog::GetInstance()->CreateDatabase(txn, db_name); + + // Table A + auto column1 = catalog::Column(type::TypeId::INTEGER, 25, "a", false); + auto column2 = catalog::Column(type::TypeId::INTEGER, 25, "b", false); + std::unique_ptr tableA_schema( + new catalog::Schema({column1, column2})); + catalog->CreateTable(txn, + db_name, + DEFAULT_SCHEMA_NAME, + std::move(tableA_schema), + table_a_name, + false); + + auto table_a = catalog->GetTableWithName(txn, + db_name, + DEFAULT_SCHEMA_NAME, + table_a_name); + catalog->AddPrimaryKeyConstraint(txn, + table_a->GetDatabaseOid(), + table_a->GetOid(), + {0}, + "con_primary"); + txn_manager.CommitTransaction(txn); + + // Table B + txn = txn_manager.BeginTransaction(); + auto column3 = catalog::Column(type::TypeId::INTEGER, 25, "b", false); + auto column4 = catalog::Column(type::TypeId::INTEGER, 25, "c", false); + std::unique_ptr tableB_schema( + new catalog::Schema({column3, column4})); + + catalog->CreateTable(txn, + db_name, + DEFAULT_SCHEMA_NAME, + std::move(tableB_schema), + table_b_name, + false); + + auto table_b = catalog->GetTableWithName(txn, + db_name, + DEFAULT_SCHEMA_NAME, + table_b_name); + catalog->AddPrimaryKeyConstraint(txn, + table_b->GetDatabaseOid(), + table_b->GetOid(), + {0}, + "con_primary"); + + oid_t sink_table_id = table_b->GetOid(); + std::vector sink_col_ids = { table_b->GetSchema()->GetColumnID("b") }; + std::vector source_col_ids = { table_a->GetSchema()->GetColumnID("b") }; + catalog->AddForeignKeyConstraint(txn, + table_a->GetDatabaseOid(), + table_a->GetOid(), + source_col_ids, + sink_table_id, + sink_col_ids, + FKConstrActionType::NOACTION, + FKConstrActionType::NOACTION, + "con_foreign"); + txn_manager.CommitTransaction(txn); + + txn = txn_manager.BeginTransaction(); + // begin this transaction + // Test1: insert a tuple with column meet the constraint requirement + std::vector ccs; + ccs.push_back(type::ValueFactory::GetIntegerValue(1)); + ccs.push_back(type::ValueFactory::GetIntegerValue(2)); + bool result = TestingConstraintsUtil::ExecuteMultiInsert(txn, table_b, ccs); + EXPECT_TRUE(result); + ccs.clear(); + ccs.push_back(type::ValueFactory::GetIntegerValue(2)); + ccs.push_back(type::ValueFactory::GetIntegerValue(1)); + result = TestingConstraintsUtil::ExecuteMultiInsert(txn, table_a, ccs); + EXPECT_TRUE(result); + + ccs.clear(); + ccs.push_back(type::ValueFactory::GetIntegerValue(3)); + ccs.push_back(type::ValueFactory::GetIntegerValue(4)); + result = TestingConstraintsUtil::ExecuteMultiInsert(txn, table_b, ccs); + EXPECT_TRUE(result); + ccs.clear(); + ccs.push_back(type::ValueFactory::GetIntegerValue(2)); + ccs.push_back(type::ValueFactory::GetIntegerValue(5)); + result = TestingConstraintsUtil::ExecuteMultiInsert(txn, table_a, ccs); + EXPECT_FALSE(result); + + // commit this transaction + txn_manager.CommitTransaction(txn); + txn = txn_manager.BeginTransaction(); + catalog::Catalog::GetInstance()->DropDatabaseWithName(txn, db_name); + txn_manager.CommitTransaction(txn); +} + + TEST_F(ConstraintsTests, ForeignKeyMultiInsertTest) { + // First, initial 2 tables like following + // TABLE A -- src table TABLE B -- sink table + // a int(ref B) b int(ref B) a int(primary) b int(primary) + // 0 0 0 0 + // 1 0 1 0 + // 2 0 2 0 + // ..... + // 9 0 + + // create new db + auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); + auto txn = txn_manager.BeginTransaction(); + auto catalog = catalog::Catalog::GetInstance(); + std::string db_name = "db2"; + std::string table_a_name = "tableA"; + std::string table_b_name = "tableB"; + catalog->CreateDatabase(txn, db_name); + + // TABLE A + auto column1 = catalog::Column(type::TypeId::INTEGER, 25, "a", false); + auto column2 = catalog::Column(type::TypeId::INTEGER, 25, "b", false); + std::unique_ptr tableA_schema( + new catalog::Schema({column1, column2})); + catalog->CreateTable(txn, + db_name, + DEFAULT_SCHEMA_NAME, + std::move(tableA_schema), + table_a_name, + false); + + auto table_a = catalog->GetTableWithName(txn, + db_name, + DEFAULT_SCHEMA_NAME, + table_a_name); + txn_manager.CommitTransaction(txn); + + // TABLE B + txn = txn_manager.BeginTransaction(); + auto column3 = catalog::Column(type::TypeId::INTEGER, 25, "a", false); + auto column4 = catalog::Column(type::TypeId::INTEGER, 25, "b", false); + catalog::Schema *table_schema = new catalog::Schema({column3, column4}); + std::unique_ptr tableB_schema(table_schema); + + catalog->CreateTable(txn, + db_name, + DEFAULT_SCHEMA_NAME, + std::move(tableB_schema), + table_b_name, + false); + + std::vector cols; + cols.push_back(0); + cols.push_back(1); + auto table_b = catalog->GetTableWithName(txn, + db_name, + DEFAULT_SCHEMA_NAME, + table_b_name); + catalog->AddPrimaryKeyConstraint(txn, + table_b->GetDatabaseOid(), + table_b->GetOid(), + cols, + "con_primary"); + + // Create foreign key tableA.B -> tableB.B + oid_t sink_table_id = table_b->GetOid(); + std::vector sink_col_ids = { table_b->GetSchema()->GetColumnID("a"), + table_b->GetSchema()->GetColumnID("b") }; + std::vector source_col_ids = { table_a->GetSchema()->GetColumnID("a"), + table_a->GetSchema()->GetColumnID("b") }; + catalog->AddForeignKeyConstraint(txn, + table_a->GetDatabaseOid(), + table_a->GetOid(), + source_col_ids, + sink_table_id, + sink_col_ids, + FKConstrActionType::RESTRICT, + FKConstrActionType::CASCADE, + "con_foreign"); + txn_manager.CommitTransaction(txn); + + + txn = txn_manager.BeginTransaction(); + // begin this transaction + // Test1: insert a tuple with column meet the constraint requirement + std::vector ccs; + ccs.push_back(type::ValueFactory::GetIntegerValue(1)); + ccs.push_back(type::ValueFactory::GetIntegerValue(2)); + bool result = TestingConstraintsUtil::ExecuteMultiInsert(txn, table_b, ccs); + EXPECT_TRUE(result); + ccs.clear(); + ccs.push_back(type::ValueFactory::GetIntegerValue(1)); + ccs.push_back(type::ValueFactory::GetIntegerValue(2)); + result = TestingConstraintsUtil::ExecuteMultiInsert(txn, table_a, ccs); + EXPECT_TRUE(result); + + ccs.clear(); + ccs.push_back(type::ValueFactory::GetIntegerValue(3)); + ccs.push_back(type::ValueFactory::GetIntegerValue(4)); + result = TestingConstraintsUtil::ExecuteMultiInsert(txn, table_b, ccs); + EXPECT_TRUE(result); + ccs.clear(); + ccs.push_back(type::ValueFactory::GetIntegerValue(2)); + ccs.push_back(type::ValueFactory::GetIntegerValue(5)); + result = TestingConstraintsUtil::ExecuteMultiInsert(txn, table_a, ccs); + EXPECT_FALSE(result); + + // commit this transaction + txn_manager.CommitTransaction(txn); + txn = txn_manager.BeginTransaction(); + catalog::Catalog::GetInstance()->DropDatabaseWithName(txn, db_name); + txn_manager.CommitTransaction(txn); +} +#endif // ======================================================== diff --git a/test/codegen/testing_codegen_util.cpp b/test/codegen/testing_codegen_util.cpp index 98879d6de59..afc498c53b0 100644 --- a/test/codegen/testing_codegen_util.cpp +++ b/test/codegen/testing_codegen_util.cpp @@ -86,23 +86,15 @@ catalog::Column PelotonCodeGenTest::GetTestColumn(uint32_t col_id) const { } // Create the test schema for all the tables -std::unique_ptr PelotonCodeGenTest::CreateTestSchema( - bool add_primary) const { +std::unique_ptr PelotonCodeGenTest::CreateTestSchema() const { // Create the columns std::vector cols = {GetTestColumn(0), GetTestColumn(1), GetTestColumn(2), GetTestColumn(3)}; // Add NOT NULL constraints on COL_A, COL_C, COL_D - cols[0].AddConstraint( - catalog::Constraint{ConstraintType::NOTNULL, "not_null"}); - if (add_primary) { - cols[0].AddConstraint( - catalog::Constraint{ConstraintType::PRIMARY, "con_primary"}); - } - cols[2].AddConstraint( - catalog::Constraint{ConstraintType::NOTNULL, "not_null"}); - cols[3].AddConstraint( - catalog::Constraint{ConstraintType::NOTNULL, "not_null"}); + cols[0].SetNotNull(); + cols[2].SetNotNull(); + cols[3].SetNotNull(); // Return the schema return std::unique_ptr{new catalog::Schema(cols)}; @@ -131,7 +123,7 @@ void PelotonCodeGenTest::CreateTestTables(concurrency::TransactionContext *txn, ->GetTableOid()); } for (int i = 4; i < 5; i++) { - auto table_schema = CreateTestSchema(true); + auto table_schema = CreateTestSchema(); catalog->CreateTable(txn, test_db_name, DEFAULT_SCHEMA_NAME, @@ -140,12 +132,15 @@ void PelotonCodeGenTest::CreateTestTables(concurrency::TransactionContext *txn, false, tuples_per_tilegroup, layout_type); - test_table_oids.push_back(catalog - ->GetTableCatalogEntry(txn, - test_db_name, - DEFAULT_SCHEMA_NAME, - test_table_names[i]) - ->GetTableOid()); + auto table_object = catalog->GetTableCatalogEntry(txn, test_db_name, + DEFAULT_SCHEMA_NAME, + test_table_names[i]); + catalog->AddPrimaryKeyConstraint(txn, + table_object->GetDatabaseOid(), + table_object->GetTableOid(), + {0}, + "con_primary"); + test_table_oids.push_back(table_object->GetTableOid()); } } diff --git a/test/common/internal_types_test.cpp b/test/common/internal_types_test.cpp index 7a616315e20..a8ff6b0881c 100644 --- a/test/common/internal_types_test.cpp +++ b/test/common/internal_types_test.cpp @@ -405,11 +405,9 @@ TEST_F(InternalTypesTests, ResultTypeTest) { TEST_F(InternalTypesTests, ConstraintTypeTest) { std::vector list = { - ConstraintType::INVALID, ConstraintType::NOT_NULL, - ConstraintType::NOTNULL, ConstraintType::DEFAULT, - ConstraintType::CHECK, ConstraintType::PRIMARY, - ConstraintType::UNIQUE, ConstraintType::FOREIGN, - ConstraintType::EXCLUSION}; + ConstraintType::INVALID, ConstraintType::CHECK, + ConstraintType::PRIMARY, ConstraintType::UNIQUE, + ConstraintType::FOREIGN, ConstraintType::EXCLUSION}; // Make sure that ToString and FromString work for (auto val : list) { diff --git a/test/concurrency/testing_transaction_util.cpp b/test/concurrency/testing_transaction_util.cpp index 7f61cc0b765..ca119c0b563 100644 --- a/test/concurrency/testing_transaction_util.cpp +++ b/test/concurrency/testing_transaction_util.cpp @@ -43,13 +43,11 @@ storage::DataTable *TestingTransactionUtil::CreateCombinedPrimaryKeyTable() { auto id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "id", true); - id_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, "not_null")); + id_column.SetNotNull(); auto value_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "value", true); - value_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, "not_null")); + value_column.SetNotNull(); // Create the table catalog::Schema *table_schema = @@ -77,6 +75,12 @@ storage::DataTable *TestingTransactionUtil::CreateCombinedPrimaryKeyTable() { table->AddIndex(pkey_index); + // Create constraint on the table + std::shared_ptr constraint( + new catalog::Constraint(1000, ConstraintType::PRIMARY, + "con_primary", TEST_TABLE_OID, key_attrs, 1234)); + table->GetSchema()->AddConstraint(constraint); + // Insert tuple auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); auto txn = txn_manager.BeginTransaction(); @@ -92,8 +96,7 @@ storage::DataTable *TestingTransactionUtil::CreatePrimaryKeyUniqueKeyTable() { auto id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "id", true); - id_column.AddConstraint( - catalog::Constraint(ConstraintType::NOTNULL, "not_null")); + id_column.SetNotNull(); auto value_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "value", true); @@ -124,6 +127,12 @@ storage::DataTable *TestingTransactionUtil::CreatePrimaryKeyUniqueKeyTable() { table->AddIndex(pkey_index); + // Create primary key constraint on the table + std::shared_ptr constraint( + new catalog::Constraint(1000, ConstraintType::PRIMARY, + "con_primary", TEST_TABLE_OID, key_attrs, 1234)); + table->GetSchema()->AddConstraint(constraint); + // Create unique index on the value column std::vector key_attrs2 = {1}; auto tuple_schema2 = table->GetSchema(); @@ -140,6 +149,12 @@ storage::DataTable *TestingTransactionUtil::CreatePrimaryKeyUniqueKeyTable() { table->AddIndex(ukey_index); + // Create unique constraint on the table + std::shared_ptr unique_constraint( + new catalog::Constraint(1001, ConstraintType::UNIQUE, + "con_unique", TEST_TABLE_OID, key_attrs, 1235)); + table->GetSchema()->AddConstraint(unique_constraint); + // Insert tuple auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); auto txn = txn_manager.BeginTransaction(); @@ -153,7 +168,7 @@ storage::DataTable *TestingTransactionUtil::CreatePrimaryKeyUniqueKeyTable() { storage::DataTable *TestingTransactionUtil::CreateTable( int num_key, std::string table_name, oid_t database_id, oid_t relation_id, - oid_t index_oid, bool need_primary_index, size_t tuples_per_tilegroup) { + oid_t index_oid, bool need_primary_key, size_t tuples_per_tilegroup) { auto id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "id", true); @@ -177,8 +192,8 @@ storage::DataTable *TestingTransactionUtil::CreateTable( key_schema->SetIndexedColumns(key_attrs); auto index_metadata = new index::IndexMetadata( - "primary_btree_index", index_oid, TEST_TABLE_OID, CATALOG_DATABASE_OID, - IndexType::BWTREE, need_primary_index ? IndexConstraintType::PRIMARY_KEY + "primary_btree_index", index_oid, relation_id, database_id, + IndexType::BWTREE, need_primary_key ? IndexConstraintType::PRIMARY_KEY : IndexConstraintType::DEFAULT, tuple_schema, key_schema, key_attrs, unique); @@ -187,6 +202,14 @@ storage::DataTable *TestingTransactionUtil::CreateTable( table->AddIndex(pkey_index); + // Create primary key constraint on the table + if (need_primary_key) { + std::shared_ptr constraint( + new catalog::Constraint(1000, ConstraintType::PRIMARY, + "con_primary", relation_id, key_attrs, index_oid)); + table->GetSchema()->AddConstraint(constraint); + } + // add this table to current database catalog::Catalog::GetInstance(); LOG_INFO("the database_id is %d", database_id); @@ -195,7 +218,7 @@ storage::DataTable *TestingTransactionUtil::CreateTable( db = storage::StorageManager::GetInstance()->GetDatabaseWithOid(database_id); } catch (CatalogException &e) { - LOG_TRACE("Can't find database %d! ", database_id); + LOG_ERROR("Can't find database %d! ", database_id); return nullptr; } PELOTON_ASSERT(db); diff --git a/test/executor/drop_test.cpp b/test/executor/drop_test.cpp index 2c1b9e5d1fb..d5f915f152b 100644 --- a/test/executor/drop_test.cpp +++ b/test/executor/drop_test.cpp @@ -286,7 +286,7 @@ TEST_F(DropTests, DroppingIndexByName) { TEST_DB_NAME, DEFAULT_SCHEMA_NAME, "department_table_01"); - oid_t col_id = source_table->GetSchema()->GetColumnID(id_column.column_name); + oid_t col_id = source_table->GetSchema()->GetColumnID(id_column.GetName()); std::vector source_col_ids; source_col_ids.push_back(col_id); std::string index_name1 = "Testing_Drop_Index_By_Name"; diff --git a/test/executor/testing_executor_util.cpp b/test/executor/testing_executor_util.cpp index eeb9c88095d..4adb7827475 100644 --- a/test/executor/testing_executor_util.cpp +++ b/test/executor/testing_executor_util.cpp @@ -81,7 +81,6 @@ void TestingExecutorUtil::DeleteDatabase(const std::string &db_name) { */ catalog::Column TestingExecutorUtil::GetColumnInfo(int index) { const bool is_inlined = true; - std::string not_null_constraint_name = "not_null"; catalog::Column dummy_column; switch (index) { @@ -90,8 +89,7 @@ catalog::Column TestingExecutorUtil::GetColumnInfo(int index) { type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "COL_A", is_inlined); - column.AddConstraint(catalog::Constraint(ConstraintType::NOTNULL, - not_null_constraint_name)); + column.SetNotNull(); return column; } break; @@ -100,8 +98,7 @@ catalog::Column TestingExecutorUtil::GetColumnInfo(int index) { type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "COL_B", is_inlined); - column.AddConstraint(catalog::Constraint(ConstraintType::NOTNULL, - not_null_constraint_name)); + column.SetNotNull(); return column; } break; @@ -110,8 +107,7 @@ catalog::Column TestingExecutorUtil::GetColumnInfo(int index) { type::TypeId::DECIMAL, type::Type::GetTypeSize(type::TypeId::DECIMAL), "COL_C", is_inlined); - column.AddConstraint(catalog::Constraint(ConstraintType::NOTNULL, - not_null_constraint_name)); + column.SetNotNull(); return column; } break; @@ -120,8 +116,7 @@ catalog::Column TestingExecutorUtil::GetColumnInfo(int index) { catalog::Column(type::TypeId::VARCHAR, 25, // Column length. "COL_D", !is_inlined); // inlined. - column.AddConstraint(catalog::Constraint(ConstraintType::NOTNULL, - not_null_constraint_name)); + column.SetNotNull(); return column; } break; @@ -390,7 +385,7 @@ storage::DataTable *TestingExecutorUtil::CreateTable( unique = true; index_metadata = new index::IndexMetadata( - "primary_btree_index", 123, INVALID_OID, INVALID_OID, IndexType::BWTREE, + "primary_btree_index", 123, table_oid, INVALID_OID, IndexType::BWTREE, IndexConstraintType::PRIMARY_KEY, tuple_schema, key_schema, key_attrs, unique); @@ -399,6 +394,12 @@ storage::DataTable *TestingExecutorUtil::CreateTable( table->AddIndex(pkey_index); + // Create constraint on the table + std::shared_ptr constraint( + new catalog::Constraint(1000, ConstraintType::PRIMARY, + "con_primary", table_oid, key_attrs, 123)); + table->GetSchema()->AddConstraint(constraint); + ///////////////////////////////////////////////////////////////// // Add index on table column 0 and 1 ///////////////////////////////////////////////////////////////// diff --git a/test/executor/update_test.cpp b/test/executor/update_test.cpp index 80cbc4bce7c..230d749ae0d 100644 --- a/test/executor/update_test.cpp +++ b/test/executor/update_test.cpp @@ -18,6 +18,7 @@ #include "binder/bind_node_visitor.h" #include "catalog/catalog.h" +#include "catalog/table_catalog.h" #include "catalog/schema.h" #include "common/internal_types.h" #include "common/logger.h" @@ -172,8 +173,6 @@ TEST_F(UpdateTests, UpdatingOld) { auto id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "dept_id", true); - catalog::Constraint constraint(ConstraintType::PRIMARY, "con_primary"); - id_column.AddConstraint(constraint); auto manager_id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "manager_id", true); @@ -182,14 +181,22 @@ TEST_F(UpdateTests, UpdatingOld) { std::unique_ptr table_schema( new catalog::Schema({id_column, manager_id_column, name_column})); - std::unique_ptr context( - new executor::ExecutorContext(txn)); - planner::CreatePlan node("department_table", DEFAULT_SCHEMA_NAME, - DEFAULT_DB_NAME, std::move(table_schema), - CreateType::TABLE); - executor::CreateExecutor create_executor(&node, context.get()); - create_executor.Init(); - create_executor.Execute(); + + catalog->CreateTable(txn, + DEFAULT_DB_NAME, + DEFAULT_SCHEMA_NAME, + std::move(table_schema), + "department_table", + false); + auto table_object = + catalog->GetTableCatalogEntry(txn, + DEFAULT_DB_NAME, + DEFAULT_SCHEMA_NAME, + "department_table"); + catalog->AddPrimaryKeyConstraint(txn, + table_object->GetDatabaseOid(), + table_object->GetTableOid(), + {0}, "con_primary"); LOG_INFO("Table created!"); diff --git a/test/gc/garbage_collection_test.cpp b/test/gc/garbage_collection_test.cpp index 886131e5fb0..bc7c6b1061b 100644 --- a/test/gc/garbage_collection_test.cpp +++ b/test/gc/garbage_collection_test.cpp @@ -129,12 +129,14 @@ TEST_F(GarbageCollectionTests, UpdateTest) { oid_t db_id = database->GetOid(); EXPECT_TRUE(storage_manager->HasDatabase(db_id)); + auto prev_tc = gc_manager.GetTableCount(); + // create a table with only one key const int num_key = 1; std::unique_ptr table(TestingTransactionUtil::CreateTable( - num_key, "UPDATE_TABLE", db_id, INVALID_OID, 1234, true)); + num_key, "UPDATE_TABLE", db_id, 12345, 1234, true)); - EXPECT_TRUE(gc_manager.GetTableCount() == 1); + EXPECT_EQ(1, gc_manager.GetTableCount() - prev_tc); gc_manager.StartGC(gc_threads); @@ -223,12 +225,15 @@ TEST_F(GarbageCollectionTests, DeleteTest) { auto database = TestingExecutorUtil::InitializeDatabase("delete_db"); oid_t db_id = database->GetOid(); EXPECT_TRUE(storage_manager->HasDatabase(db_id)); + + auto prev_tc = gc_manager.GetTableCount(); + // create a table with only one key const int num_key = 1; std::unique_ptr table(TestingTransactionUtil::CreateTable( - num_key, "DELETE_TABLE", db_id, INVALID_OID, 1234, true)); + num_key, "DELETE_TABLE", db_id, 12346, 1234, true)); - EXPECT_TRUE(gc_manager.GetTableCount() == 1); + EXPECT_EQ(1, gc_manager.GetTableCount() - prev_tc); gc_manager.StartGC(gc_threads); diff --git a/test/gc/transaction_level_gc_manager_test.cpp b/test/gc/transaction_level_gc_manager_test.cpp index e574f5bd4d8..b53f9084ad2 100644 --- a/test/gc/transaction_level_gc_manager_test.cpp +++ b/test/gc/transaction_level_gc_manager_test.cpp @@ -97,12 +97,14 @@ TEST_F(TransactionLevelGCManagerTests, UpdateDeleteTest) { oid_t db_id = database->GetOid(); EXPECT_TRUE(storage_manager->HasDatabase(db_id)); + auto prev_tc = gc_manager.GetTableCount(); + // create a table with only one key const int num_key = 1; std::unique_ptr table(TestingTransactionUtil::CreateTable( - num_key, "TABLE0", db_id, INVALID_OID, 1234, true)); + num_key, "TABLE0", db_id, 12345, 1234, true)); - EXPECT_TRUE(gc_manager.GetTableCount() == 1); + EXPECT_EQ(1, gc_manager.GetTableCount() - prev_tc); //=========================== // update a version here. @@ -228,12 +230,14 @@ TEST_F(TransactionLevelGCManagerTests, ReInsertTest) { oid_t db_id = database->GetOid(); EXPECT_TRUE(storage_manager->HasDatabase(db_id)); + auto prev_tc = gc_manager.GetTableCount(); + // create a table with only one key const int num_key = 1; std::unique_ptr table(TestingTransactionUtil::CreateTable( - num_key, "TABLE1", db_id, INVALID_OID, 1234, true)); + num_key, "TABLE1", db_id, 12346, 1234, true)); - EXPECT_TRUE(gc_manager.GetTableCount() == 1); + EXPECT_EQ(1, gc_manager.GetTableCount() - prev_tc); //=========================== // insert a tuple here. @@ -397,13 +401,15 @@ TEST_F(TransactionLevelGCManagerTests, ImmutabilityTest) { oid_t db_id = database->GetOid(); EXPECT_TRUE(storage_manager->HasDatabase(db_id)); + auto prev_tc = gc_manager.GetTableCount(); + // create a table with only one key const int num_key = 25; const size_t tuples_per_tilegroup = 5; std::unique_ptr table(TestingTransactionUtil::CreateTable( - num_key, "TABLE1", db_id, INVALID_OID, 1234, true, tuples_per_tilegroup)); + num_key, "TABLE1", db_id, 12347, 1234, true, tuples_per_tilegroup)); - EXPECT_TRUE(gc_manager.GetTableCount() == 1); + EXPECT_EQ(1, gc_manager.GetTableCount() - prev_tc); oid_t num_tile_groups = (table.get())->GetTileGroupCount(); EXPECT_EQ(num_tile_groups, (num_key / tuples_per_tilegroup) + 1); diff --git a/test/include/catalog/testing_constraints_util.h b/test/include/catalog/testing_constraints_util.h index ab39e311bd1..8bd27540dbf 100644 --- a/test/include/catalog/testing_constraints_util.h +++ b/test/include/catalog/testing_constraints_util.h @@ -91,26 +91,10 @@ namespace test { class TestingConstraintsUtil { public: - /** @brief Creates a basic table with allocated and populated tuples */ - static storage::DataTable *CreateAndPopulateTable( - std::vector> constraints, - std::vector multi_constraints) { - const int tuple_count = TESTS_TUPLES_PER_TILEGROUP; - storage::DataTable *table = - TestingConstraintsUtil::CreateTable(constraints, multi_constraints); - auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); - auto txn = txn_manager.BeginTransaction(); - TestingConstraintsUtil::PopulateTable( - txn, table, tuple_count * DEFAULT_TILEGROUP_COUNT); - txn_manager.CommitTransaction(txn); - - return table; - }; - /** @brief Creates a basic table with allocated but not populated tuples */ static storage::DataTable *CreateTable( - std::vector> constraints, - UNUSED_ATTRIBUTE std::vector multi_constraints, + std::vector notnull_col_ids, + std::unordered_map default_values, UNUSED_ATTRIBUTE bool indexes = true) { // Create the database auto catalog = catalog::Catalog::GetInstance(); @@ -124,13 +108,24 @@ class TestingConstraintsUtil { std::vector columns; for (int i = 0; i < CONSTRAINTS_NUM_COLS; i++) { columns.push_back( - TestingConstraintsUtil::GetColumnInfo(i, constraints[i])); + TestingConstraintsUtil::GetColumnInfo(i)); } + + // set single column constraints + for (auto col_oid : notnull_col_ids) { + PELOTON_ASSERT(col_oid < CONSTRAINTS_NUM_COLS); + columns[col_oid].SetNotNull(); + } + for (auto dv : default_values) { + PELOTON_ASSERT(dv.first < CONSTRAINTS_NUM_COLS); + columns[dv.first].SetDefaultValue(dv.second); + } + std::unique_ptr table_schema(new catalog::Schema(columns)); - std::string table_name(CONSTRAINTS_TEST_TABLE); // Create table. txn = txn_manager.BeginTransaction(); + std::string table_name(CONSTRAINTS_TEST_TABLE); auto result = catalog->CreateTable(txn, DEFAULT_DB_NAME, DEFAULT_SCHEMA_NAME, std::move(table_schema), table_name, false); @@ -328,6 +323,18 @@ class TestingConstraintsUtil { return executor.Execute(); }; + /** @brief Allocated and populated tuples */ + static storage::DataTable *PopulateTable(storage::DataTable *table) { + const int tuple_count = TESTS_TUPLES_PER_TILEGROUP; + auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); + auto txn = txn_manager.BeginTransaction(); + TestingConstraintsUtil::PopulateTable( + txn, table, tuple_count * DEFAULT_TILEGROUP_COUNT); + txn_manager.CommitTransaction(txn); + + return table; + }; + static void PopulateTable(concurrency::TransactionContext *transaction, storage::DataTable *table, int num_rows) { // Ensure that the tile group is as expected. @@ -357,8 +364,7 @@ class TestingConstraintsUtil { } }; - static catalog::Column GetColumnInfo( - int index, std::vector constraints) { + static catalog::Column GetColumnInfo(int index) { catalog::Column column; switch (index) { // COL_A @@ -394,11 +400,6 @@ class TestingConstraintsUtil { std::to_string(index)); } } - - // Add any constraints that we have for this mofo - for (auto col_const : constraints) { - column.AddConstraint(col_const); - } return (column); }; diff --git a/test/include/codegen/testing_codegen_util.h b/test/include/codegen/testing_codegen_util.h index fa9fcf852cd..4c39f08c92b 100644 --- a/test/include/codegen/testing_codegen_util.h +++ b/test/include/codegen/testing_codegen_util.h @@ -89,8 +89,7 @@ class PelotonCodeGenTest : public PelotonTest { // Create the schema (common among all tables) catalog::Column GetTestColumn(uint32_t col_id) const; - std::unique_ptr CreateTestSchema( - bool add_primary = false) const; + std::unique_ptr CreateTestSchema() const; // Create the test tables void CreateTestTables(concurrency::TransactionContext *txn, diff --git a/test/include/concurrency/testing_transaction_util.h b/test/include/concurrency/testing_transaction_util.h index d7bb919a0f3..d2387f9ee98 100644 --- a/test/include/concurrency/testing_transaction_util.h +++ b/test/include/concurrency/testing_transaction_util.h @@ -122,7 +122,7 @@ class TestingTransactionUtil { int num_key = 10, std::string table_name = "TEST_TABLE", oid_t database_id = CATALOG_DATABASE_OID, oid_t relation_id = TEST_TABLE_OID, oid_t index_oid = 1234, - bool need_primary_index = false, size_t tuples_per_tilegroup = 100); + bool need_primary_key = false, size_t tuples_per_tilegroup = 100); // Create the same table as CreateTable with primary key constraints on id and // unique key constraints on value diff --git a/test/optimizer/stats_storage_test.cpp b/test/optimizer/stats_storage_test.cpp index edf42131355..131bfbdb6ac 100644 --- a/test/optimizer/stats_storage_test.cpp +++ b/test/optimizer/stats_storage_test.cpp @@ -253,4 +253,4 @@ TEST_F(StatsStorageTests, GetTableStatsTest) { } } // namespace test -} // namespace peloton \ No newline at end of file +} // namespace peloton diff --git a/test/planner/plan_util_test.cpp b/test/planner/plan_util_test.cpp index 6130d29d260..d58aae8a5e0 100644 --- a/test/planner/plan_util_test.cpp +++ b/test/planner/plan_util_test.cpp @@ -68,7 +68,7 @@ TEST_F(PlanUtilTests, GetAffectedIndexesTest) { txn_manager.CommitTransaction(txn); txn = txn_manager.BeginTransaction(); - oid_t col_id = source_table->GetSchema()->GetColumnID(id_column.column_name); + oid_t col_id = source_table->GetSchema()->GetColumnID(id_column.GetName()); std::vector source_col_ids; source_col_ids.push_back(col_id); @@ -83,7 +83,7 @@ TEST_F(PlanUtilTests, GetAffectedIndexesTest) { IndexType::BWTREE); // create index on 'id' and 'first_name' - col_id = source_table->GetSchema()->GetColumnID(fname_column.column_name); + col_id = source_table->GetSchema()->GetColumnID(fname_column.GetName()); source_col_ids.push_back(col_id); catalog->CreateIndex(txn, @@ -232,11 +232,11 @@ TEST_F(PlanUtilTests, GetIndexableColumnsTest) { oid_t table_id = source_table->GetOid(); oid_t id_col_oid = - source_table->GetSchema()->GetColumnID(id_column.column_name); + source_table->GetSchema()->GetColumnID(id_column.GetName()); oid_t fname_col_oid = - source_table->GetSchema()->GetColumnID(fname_column.column_name); + source_table->GetSchema()->GetColumnID(fname_column.GetName()); oid_t lname_col_oid = - source_table->GetSchema()->GetColumnID(lname_column.column_name); + source_table->GetSchema()->GetColumnID(lname_column.GetName()); // Insert a 'test_table_job' with 'age', 'job' and 'pid' txn = txn_manager.BeginTransaction(); @@ -266,11 +266,11 @@ TEST_F(PlanUtilTests, GetIndexableColumnsTest) { "test_table_job"); oid_t table_job_id = source_table_job->GetOid(); oid_t age_col_oid = - source_table_job->GetSchema()->GetColumnID(age_column.column_name); + source_table_job->GetSchema()->GetColumnID(age_column.GetName()); oid_t job_col_oid = - source_table_job->GetSchema()->GetColumnID(job_column.column_name); + source_table_job->GetSchema()->GetColumnID(job_column.GetName()); oid_t pid_col_oid = - source_table_job->GetSchema()->GetColumnID(pid_column.column_name); + source_table_job->GetSchema()->GetColumnID(pid_column.GetName()); txn_manager.CommitTransaction(txn); txn = txn_manager.BeginTransaction(); diff --git a/test/planner/planner_test.cpp b/test/planner/planner_test.cpp index 19304048dd9..fc865ab86a1 100644 --- a/test/planner/planner_test.cpp +++ b/test/planner/planner_test.cpp @@ -193,10 +193,10 @@ TEST_F(PlannerTest, UpdatePlanTestParameter) { ExpressionType::COMPARE_EQUAL, tuple_expr, parameter_expr); auto &schema_columns = schema->GetColumns(); - for (uint i = 0; i < schema_columns.size(); i++) { + for (oid_t i = 0; i < schema_columns.size(); i++) { bool is_in_target_list = false; for (auto col_id : column_ids) { - if (schema_columns[i].column_name == schema_columns[col_id].column_name) { + if (schema_columns[i].GetName() == schema_columns[col_id].GetName()) { is_in_target_list = true; break; } @@ -206,7 +206,7 @@ TEST_F(PlannerTest, UpdatePlanTestParameter) { } column_ids.clear(); - for (uint i = 0; i < schema_columns.size(); i++) { + for (oid_t i = 0; i < schema_columns.size(); i++) { column_ids.emplace_back(i); } diff --git a/test/sql/optimizer_sql_test.cpp b/test/sql/optimizer_sql_test.cpp index 9ebd230346c..b9248b1c5be 100644 --- a/test/sql/optimizer_sql_test.cpp +++ b/test/sql/optimizer_sql_test.cpp @@ -339,7 +339,7 @@ TEST_F(OptimizerSQLTests, DDLSqlTest) { auto cols = table->GetSchema()->GetColumns(); EXPECT_EQ(3, cols.size()); EXPECT_EQ("a", cols[0].GetName()); - EXPECT_EQ(true, cols[0].IsPrimary()); + EXPECT_EQ(true, table->GetSchema()->HasPrimary()); EXPECT_EQ(type::TypeId::INTEGER, cols[0].GetType()); EXPECT_EQ("b", cols[1].GetName()); EXPECT_EQ(type::TypeId::INTEGER, cols[1].GetType()); diff --git a/test/statistics/stats_test.cpp b/test/statistics/stats_test.cpp index b40efd823e6..792c4317b38 100644 --- a/test/statistics/stats_test.cpp +++ b/test/statistics/stats_test.cpp @@ -128,8 +128,6 @@ TEST_F(StatsTests, MultiThreadStatsTest) { auto id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "dept_id", true); - catalog::Constraint constraint(ConstraintType::PRIMARY, "con_primary"); - id_column.AddConstraint(constraint); auto name_column = catalog::Column(type::TypeId::VARCHAR, 32, "dept_name", false); @@ -148,9 +146,16 @@ TEST_F(StatsTests, MultiThreadStatsTest) { storage::Database *database = catalog->GetDatabaseWithName(txn, "emp_db"); storage::DataTable *table = catalog->GetTableWithName(txn, - "emp_db", - DEFAULT_SCHEMA_NAME, - "department_table"); + "emp_db", + DEFAULT_SCHEMA_NAME, + "department_table"); + + catalog->AddPrimaryKeyConstraint(txn, + database->GetOid(), + table->GetOid(), + {0}, + "con_primary"); + txn_manager.CommitTransaction(txn); LaunchParallelTest(num_threads, TransactionTest, database, table); // Wait for aggregation to finish diff --git a/test/statistics/testing_stats_util.cpp b/test/statistics/testing_stats_util.cpp index 5c087e4aba4..169999efe9d 100644 --- a/test/statistics/testing_stats_util.cpp +++ b/test/statistics/testing_stats_util.cpp @@ -12,6 +12,8 @@ #include "statistics/testing_stats_util.h" +#include "catalog/catalog.h" +#include "catalog/table_catalog.h" #include "executor/delete_executor.h" #include "executor/executor_context.h" #include "executor/insert_executor.h" @@ -112,24 +114,32 @@ void TestingStatsUtil::CreateTable(bool has_primary_key) { auto id_column = catalog::Column( type::TypeId::INTEGER, type::Type::GetTypeSize(type::TypeId::INTEGER), "dept_id", true); - if (has_primary_key) { - catalog::Constraint constraint(ConstraintType::PRIMARY, "con_primary"); - id_column.AddConstraint(constraint); - } auto name_column = catalog::Column(type::TypeId::VARCHAR, 256, "dept_name", false); - std::unique_ptr table_schema( new catalog::Schema({id_column, name_column})); + + auto catalog = catalog::Catalog::GetInstance(); auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance(); auto txn = txn_manager.BeginTransaction(); - std::unique_ptr context( - new executor::ExecutorContext(txn)); - planner::CreatePlan node("department_table", DEFAULT_SCHEMA_NAME, "emp_db", - std::move(table_schema), CreateType::TABLE); - executor::CreateExecutor create_executor(&node, context.get()); - create_executor.Init(); - create_executor.Execute(); + catalog->CreateTable(txn, + "emp_db", + DEFAULT_SCHEMA_NAME, + std::move(table_schema), + "department_table", + false); + + if (has_primary_key) { + auto table_object = catalog->GetTableCatalogEntry(txn, + "emp_db", + DEFAULT_SCHEMA_NAME, + "department_table"); + catalog->AddPrimaryKeyConstraint(txn, + table_object->GetDatabaseOid(), + table_object->GetTableOid(), + {0}, + "con_primary"); + } txn_manager.CommitTransaction(txn); }