Skip to content
This repository was archived by the owner on Sep 27, 2019. It is now read-only.

Commit 97f83d4

Browse files
authored
Merge pull request #1000 from vittvolt/foreign-key-final
Foreign Key Fix
2 parents 37835d6 + df67e87 commit 97f83d4

15 files changed

+475
-102
lines changed

src/executor/create_executor.cpp

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -99,25 +99,26 @@ bool CreateExecutor::CreateDatabase(const planner::CreatePlan &node) {
9999
}
100100

101101
bool CreateExecutor::CreateTable(const planner::CreatePlan &node) {
102-
auto txn = context_->GetTransaction();
102+
auto current_txn = context_->GetTransaction();
103103
std::string table_name = node.GetTableName();
104104
auto database_name = node.GetDatabaseName();
105105
std::unique_ptr<catalog::Schema> schema(node.GetSchema());
106106

107107
ResultType result = catalog::Catalog::GetInstance()->CreateTable(
108-
database_name, table_name, std::move(schema), txn);
109-
txn->SetResult(result);
108+
database_name, table_name, std::move(schema), current_txn);
109+
current_txn->SetResult(result);
110110

111-
if (txn->GetResult() == ResultType::SUCCESS) {
111+
if (current_txn->GetResult() == ResultType::SUCCESS) {
112112
LOG_TRACE("Creating table succeeded!");
113113

114114
// Add the foreign key constraint (or other multi-column constraints)
115115
if (node.GetForeignKeys().empty() == false) {
116116
auto catalog = catalog::Catalog::GetInstance();
117-
auto db = catalog->GetDatabaseWithName(database_name, txn);
117+
auto db = catalog->GetDatabaseWithName(database_name, current_txn);
118118

119119
auto source_table = db->GetTableWithName(table_name);
120120
int count = 1;
121+
121122
for (auto fk : node.GetForeignKeys()) {
122123
auto sink_table = db->GetTableWithName(fk.sink_table_name);
123124

@@ -139,7 +140,7 @@ bool CreateExecutor::CreateTable(const planner::CreatePlan &node) {
139140
// Sink Column Offsets
140141
std::vector<oid_t> sink_col_ids;
141142
for (auto col_name : fk.foreign_key_sinks) {
142-
oid_t col_id = source_table->GetSchema()->GetColumnID(col_name);
143+
oid_t col_id = sink_table->GetSchema()->GetColumnID(col_name);
143144
if (col_id == INVALID_OID) {
144145
std::string error = StringUtil::Format(
145146
"Invalid sink column name '%s.%s' for foreign key '%s'",
@@ -152,43 +153,51 @@ bool CreateExecutor::CreateTable(const planner::CreatePlan &node) {
152153
PL_ASSERT(sink_col_ids.size() == fk.foreign_key_sinks.size());
153154

154155
// Create the catalog object and shove it into the table
155-
auto catalog_fk = new catalog::ForeignKey(
156+
auto catalog_fk = new catalog::ForeignKey(INVALID_OID,
156157
sink_table->GetOid(), sink_col_ids, source_col_ids,
157158
fk.upd_action, fk.del_action, fk.constraint_name);
158159
source_table->AddForeignKey(catalog_fk);
159160

160161
// Register FK with the sink table for delete/update actions
161-
sink_table->RegisterForeignKeySource(table_name);
162+
catalog_fk = new catalog::ForeignKey(source_table->GetOid(),
163+
INVALID_OID,
164+
sink_col_ids,
165+
source_col_ids,
166+
fk.upd_action,
167+
fk.del_action,
168+
fk.constraint_name);
169+
sink_table->RegisterForeignKeySource(catalog_fk);
162170

163171
// Add a non-unique index on the source table if needed
164-
if (catalog_fk->GetUpdateAction() != FKConstrActionType::NOACTION ||
165-
catalog_fk->GetDeleteAction() != FKConstrActionType::NOACTION) {
166-
std::vector<std::string> source_col_names =
167-
fk.foreign_key_sources;
168-
std::string index_name =
169-
source_table->GetName() + "_FK_" + std::to_string(count);
170-
catalog->CreateIndex(database_name, source_table->GetName(),
171-
source_col_ids, index_name, false,
172-
IndexType::BWTREE, txn);
173-
count++;
172+
std::vector<std::string> source_col_names =
173+
fk.foreign_key_sources;
174+
std::string index_name =
175+
source_table->GetName() + "_FK_" + sink_table->GetName() + "_"
176+
+ std::to_string(count);
177+
catalog->CreateIndex(database_name, source_table->GetName(),
178+
source_col_ids, index_name, false,
179+
IndexType::BWTREE, current_txn);
180+
count++;
174181

175182
#ifdef LOG_DEBUG_ENABLED
176-
LOG_DEBUG("Added a FOREIGN index on in %s.", table_name.c_str());
177-
LOG_DEBUG("Foreign key column names: ");
178-
for (auto c : source_col_names) {
179-
LOG_DEBUG("FK col name: %s", c.c_str());
180-
}
181-
#endif
183+
LOG_DEBUG("Added a FOREIGN index on in %s.\n", table_name.c_str());
184+
LOG_DEBUG("Foreign key column names: \n");
185+
for (auto c : source_col_names) {
186+
LOG_DEBUG("FK col name: %s\n", c.c_str());
187+
}
188+
for (auto c : fk.foreign_key_sinks) {
189+
LOG_DEBUG("FK sink col name: %s\n", c.c_str());
182190
}
191+
#endif
183192
}
184193
}
185-
} else if (txn->GetResult() == ResultType::FAILURE) {
194+
} else if (current_txn->GetResult() == ResultType::FAILURE) {
186195
LOG_TRACE("Creating table failed!");
187-
return (false);
188196
} else {
189197
LOG_TRACE("Result is: %s",
190-
ResultTypeToString(txn->GetResult()).c_str());
198+
ResultTypeToString(current_txn->GetResult()).c_str());
191199
}
200+
192201
return (true);
193202
}
194203

src/executor/delete_executor.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,27 @@ bool DeleteExecutor::DExecute() {
133133
physical_tuple_id = old_location.offset;
134134
}
135135

136+
ContainerTuple<storage::TileGroup> old_tuple(tile_group, physical_tuple_id);
137+
storage::Tuple prev_tuple(target_table_->GetSchema(), true);
138+
139+
// Get a copy of the old tuple
140+
for (oid_t column_itr = 0; column_itr < target_table_schema->GetColumnCount(); column_itr++) {
141+
type::Value val = (old_tuple.GetValue(column_itr));
142+
prev_tuple.SetValue(column_itr, val, executor_context_->GetPool());
143+
}
144+
145+
// Check the foreign key source table
146+
if (target_table_->CheckForeignKeySrcAndCascade(&prev_tuple,
147+
nullptr,
148+
current_txn,
149+
executor_context_,
150+
false) == false)
151+
{
152+
transaction_manager.SetTransactionResult(current_txn,
153+
peloton::ResultType::FAILURE);
154+
return false;
155+
}
156+
136157
bool is_owner = transaction_manager.IsOwner(current_txn, tile_group_header,
137158
physical_tuple_id);
138159

src/executor/update_executor.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include "storage/data_table.h"
2323
#include "storage/tile_group_header.h"
2424
#include "storage/tile.h"
25+
#include "storage/storage_manager.h"
26+
#include "catalog/foreign_key.h"
2527

2628
namespace peloton {
2729
namespace executor {
@@ -112,6 +114,27 @@ bool UpdateExecutor::PerformUpdatePrimaryKey(
112114
return false;
113115
}
114116

117+
// Check the source table of any foreign key constraint
118+
if (target_table_->GetForeignKeySrcCount() > 0) {
119+
storage::Tuple prev_tuple(target_table_schema, true);
120+
// Get a copy of the old tuple
121+
for (oid_t column_itr = 0; column_itr < target_table_schema->GetColumnCount(); column_itr++) {
122+
type::Value val = (old_tuple.GetValue(column_itr));
123+
prev_tuple.SetValue(column_itr, val, executor_context_->GetPool());
124+
}
125+
126+
if (target_table_->CheckForeignKeySrcAndCascade(&prev_tuple,
127+
&new_tuple,
128+
current_txn,
129+
executor_context_,
130+
true) == false)
131+
{
132+
transaction_manager.SetTransactionResult(current_txn,
133+
peloton::ResultType::FAILURE);
134+
return false;
135+
}
136+
}
137+
115138
transaction_manager.PerformInsert(current_txn, location, index_entry_ptr);
116139

117140
return true;

src/include/catalog/foreign_key.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,23 @@ namespace catalog {
2828
// Stores info about foreign key constraints, like the sink table id etc.
2929
class ForeignKey {
3030
public:
31-
ForeignKey(oid_t sink_table_id,
31+
ForeignKey(oid_t source_table_id,
32+
oid_t sink_table_id,
3233
std::vector<oid_t> sink_col_ids,
3334
std::vector<oid_t> source_col_ids,
3435
FKConstrActionType update_action,
3536
FKConstrActionType delete_action,
3637
std::string constraint_name)
3738

38-
: sink_table_id(sink_table_id),
39+
: source_table_id(source_table_id),
40+
sink_table_id(sink_table_id),
3941
sink_col_ids(sink_col_ids),
4042
source_col_ids(source_col_ids),
4143
update_action(update_action),
4244
delete_action(delete_action),
4345
fk_name(constraint_name) {}
4446

47+
oid_t GetSourceTableOid() const { return source_table_id; }
4548
oid_t GetSinkTableOid() const { return sink_table_id; }
4649

4750
std::vector<oid_t> GetSinkColumnIds() const { return sink_col_ids; }
@@ -52,6 +55,7 @@ class ForeignKey {
5255
std::string &GetConstraintName() { return fk_name; }
5356

5457
private:
58+
oid_t source_table_id = INVALID_OID;
5559
oid_t sink_table_id = INVALID_OID;
5660

5761
// Columns in the reference table (sink)

src/include/parser/create_statement.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ struct ColumnDefinition {
195195
std::unique_ptr<expression::AbstractExpression> default_value = nullptr;
196196
std::unique_ptr<expression::AbstractExpression> check_expression = nullptr;
197197

198+
std::string fk_sink_table_name;
198199
std::vector<std::string> primary_key;
199200
std::vector<std::string> foreign_key_source;
200201
std::vector<std::string> foreign_key_sink;
@@ -233,6 +234,7 @@ class CreateStatement : public TableRefStatement {
233234
bool if_not_exists;
234235

235236
std::vector<std::unique_ptr<ColumnDefinition>> columns;
237+
std::vector<std::unique_ptr<ColumnDefinition>> foreign_keys;
236238

237239
std::vector<std::string> index_attrs;
238240
IndexType index_type;

src/include/parser/postgresparser.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ class PostgresParser {
167167
static parser::OrderDescription *OrderByTransform(List *order);
168168

169169
// transform helper for table column definitions
170-
static parser::ColumnDefinition *ColumnDefTransform(ColumnDef *root);
170+
static void ColumnDefTransform(ColumnDef* root, parser::CreateStatement* stmt);
171171

172172
// transform helper for create statements
173173
static parser::SQLStatement *CreateTransform(CreateStmt *root);

src/include/storage/abstract_table.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ class AbstractTable : public Printable {
6666
// index_entry_ptr.
6767
virtual ItemPointer InsertTuple(const Tuple *tuple,
6868
concurrency::TransactionContext *transaction,
69-
ItemPointer **index_entry_ptr = nullptr) = 0;
69+
ItemPointer **index_entry_ptr = nullptr,
70+
bool check_fk = true) = 0;
7071

7172
// designed for tables without primary key. e.g., output table used by
7273
// aggregate_executor.

src/include/storage/data_table.h

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "common/item_pointer.h"
2222
#include "common/platform.h"
2323
#include "common/container/lock_free_array.h"
24+
#include "executor/executor_context.h"
2425
#include "index/index.h"
2526
#include "storage/abstract_table.h"
2627
#include "storage/indirection_array.h"
@@ -118,14 +119,16 @@ class DataTable : public AbstractTable {
118119
// index_entry_ptr.
119120
ItemPointer InsertTuple(const Tuple *tuple,
120121
concurrency::TransactionContext *transaction,
121-
ItemPointer **index_entry_ptr = nullptr);
122+
ItemPointer **index_entry_ptr = nullptr,
123+
bool check_fk = true);
122124
// designed for tables without primary key. e.g., output table used by
123125
// aggregate_executor.
124126
ItemPointer InsertTuple(const Tuple *tuple);
125127

126128
// Insert tuple with ItemPointer provided explicitly
127129
bool InsertTuple(const AbstractTuple *tuple, ItemPointer location,
128-
concurrency::TransactionContext *transaction, ItemPointer **index_entry_ptr);
130+
concurrency::TransactionContext *transaction, ItemPointer **index_entry_ptr,
131+
bool check_fk = true);
129132

130133
//===--------------------------------------------------------------------===//
131134
// TILE GROUP
@@ -193,6 +196,12 @@ class DataTable : public AbstractTable {
193196
// FOREIGN KEYS
194197
//===--------------------------------------------------------------------===//
195198

199+
bool CheckForeignKeySrcAndCascade(storage::Tuple *prev_tuple,
200+
storage::Tuple *new_tuple,
201+
concurrency::TransactionContext *transaction,
202+
executor::ExecutorContext *context,
203+
bool is_update);
204+
196205
void AddForeignKey(catalog::ForeignKey *key);
197206

198207
catalog::ForeignKey *GetForeignKey(const oid_t &key_offset) const;
@@ -201,9 +210,11 @@ class DataTable : public AbstractTable {
201210

202211
size_t GetForeignKeyCount() const;
203212

204-
void RegisterForeignKeySource(const std::string &source_table_name);
213+
void RegisterForeignKeySource(catalog::ForeignKey *key);
214+
215+
size_t GetForeignKeySrcCount() const;
205216

206-
void RemoveForeignKeySource(const std::string &source_table_name);
217+
catalog::ForeignKey *GetForeignKeySrc(const size_t) const;
207218

208219
//===--------------------------------------------------------------------===//
209220
// TRANSFORMERS
@@ -333,7 +344,8 @@ class DataTable : public AbstractTable {
333344
ItemPointer *index_entry_ptr);
334345

335346
// check the foreign key constraints
336-
bool CheckForeignKeyConstraints(const AbstractTuple *tuple);
347+
bool CheckForeignKeyConstraints(const AbstractTuple *tuple,
348+
concurrency::TransactionContext *transaction);
337349

338350
public:
339351
static size_t default_active_tilegroup_count_;
@@ -379,8 +391,10 @@ class DataTable : public AbstractTable {
379391
// CONSTRAINTS
380392
// fk constraints for which this table is the source
381393
std::vector<catalog::ForeignKey *> foreign_keys_;
382-
// names of tables for which this table's PK is the foreign key sink
383-
std::vector<std::string> foreign_key_sources_;
394+
// fk constraints for which this table is the sink
395+
// The complete information is stored so no need to lookup the table
396+
// everytime there is a constraint check
397+
std::vector<catalog::ForeignKey *> foreign_key_sources_;
384398

385399
// has a primary key ?
386400
std::atomic<bool> has_primary_key_ = ATOMIC_VAR_INIT(false);

src/include/storage/temp_table.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ class TempTable : public AbstractTable {
6262
// index_entry_ptr.
6363
ItemPointer InsertTuple(const Tuple *tuple,
6464
concurrency::TransactionContext *transaction,
65-
ItemPointer **index_entry_ptr = nullptr) override;
65+
ItemPointer **index_entry_ptr = nullptr,
66+
bool check_fk = true) override;
6667

6768
// designed for tables without primary key. e.g., output table used by
6869
// aggregate_executor.

0 commit comments

Comments
 (0)