Skip to content

Commit

Permalink
Fixed CORE-3073 - Foreign key cascade with SET DEFAULT uses the defau…
Browse files Browse the repository at this point in the history
…lt value of the moment of the FK creation.
  • Loading branch information
asfernandes committed Jan 20, 2017
1 parent 7539585 commit 7bb6ceb
Showing 1 changed file with 51 additions and 77 deletions.
128 changes: 51 additions & 77 deletions src/dsql/DdlNodes.epp
Original file line number Diff line number Diff line change
Expand Up @@ -6868,104 +6868,76 @@ void RelationNode::defineSetDefaultTrigger(DsqlCompilerScratch* dsqlScratch,
Constraint::BlrWriter& blrWriter = constraint.blrWritersHolder.add();
blrWriter.init(dsqlScratch);

generateUnnamedTriggerBeginning(constraint, onUpdate, blrWriter);
blrWriter.appendUChar(blr_begin);

const int BLOB_BUFFER_SIZE = 4096; // to read in blr blob for default values
UCHAR defaultVal[BLOB_BUFFER_SIZE];
USHORT index = 0;

for (ObjectsArray<MetaName>::const_iterator column(constraint.columns.begin());
column != constraint.columns.end();
++column)
++column, index += 2)
{
blrWriter.appendUChar(blr_assignment);
// If the FK table's column is NOT NULL without DEFAULT, we want to avoid the engine throwing a constraint
// violation on our trigger's variable, so we declare two variables, one with blr_domain_type_of (don't use
// DEFAULT and null flag) and another blr_domain_full with DEFAULT and null flag. We swallow the error when
// transfering the value from the second to the first variable.

// ASF: This is wrong way to do the thing. See CORE-3073.

// Here stuff the default value as blr_literal .... or blr_null
// if this column does not have an applicable default.
// The default is determined in many cases:
// (1) the info. for the column is in memory. (This is because
// the column is being created in this ddl statement).
// (1-a) the table has a column level default. We get this by
// searching the dsql parse tree.
// (1-b) the table does not have a column level default, but
// has a domain default. We get the domain name from the dsql
// parse tree and call METD_get_domain_default to read the
// default from the system tables.
// (2) The default-info for this column is not in memory (This is
// because this is an alter table ddl statement). The table
// already exists; therefore we get the column and/or domain
// default value from the system tables by calling:
// METD_get_col_default().

bool foundDefault = false;
bool searchForDefault = true;

// Search the parse tree to find the column

for (NestConst<Clause>* ptr = clauses.begin(); ptr != clauses.end(); ++ptr)
{
if ((*ptr)->type != Clause::TYPE_ADD_COLUMN)
continue;
blrWriter.appendUChar(blr_dcl_variable);
blrWriter.appendUShort(index);

AddColumnClause* clause = static_cast<AddColumnClause*>(ptr->getObject());
blrWriter.appendUChar(blr_column_name);
blrWriter.appendUChar(blr_domain_type_of);
blrWriter.appendNullString(0, name.c_str());
blrWriter.appendNullString(0, column->c_str());

if (*column != clause->field->fld_name)
continue;
blrWriter.appendUChar(blr_dcl_variable);
blrWriter.appendUShort(index + 1);

// Now we have the right column in the parse tree. case (1) above
blrWriter.appendUChar(blr_column_name);
blrWriter.appendUChar(blr_domain_full);
blrWriter.appendNullString(0, name.c_str());
blrWriter.appendNullString(0, column->c_str());

if (clause->defaultValue)
{
// case (1-a) above: There is a column level default
blrWriter.appendUChar(blr_assignment);
blrWriter.appendUChar(blr_null);
blrWriter.appendUChar(blr_variable);
blrWriter.appendUShort(index);

dsqlScratch->getBlrData().clear();
dsqlScratch->getDebugData().clear();
blrWriter.appendUChar(blr_block); // 1

GEN_expr(dsqlScratch, clause->defaultValue->value);
blrWriter.appendUChar(blr_begin); // 2

foundDefault = true;
searchForDefault = false;
blrWriter.appendUChar(blr_init_variable);
blrWriter.appendUShort(index + 1);

// Move the blr to the constraint blrWriter.
blrWriter.getBlrData().join(dsqlScratch->getBlrData());
}
else
{
if (!clause->field->typeOfName.hasData())
break;
blrWriter.appendUChar(blr_assignment);
blrWriter.appendUChar(blr_variable);
blrWriter.appendUShort(index + 1);
blrWriter.appendUChar(blr_variable);
blrWriter.appendUShort(index);

// case: (1-b): Domain name is available. Column level default
// is not declared. So get the domain default.
const USHORT defaultLen = METD_get_domain_default(dsqlScratch->getTransaction(),
clause->field->typeOfName, &foundDefault, defaultVal, sizeof(defaultVal));
blrWriter.appendUChar(blr_end); // 2

searchForDefault = false;
blrWriter.appendUChar(blr_error_handler);
blrWriter.appendUShort(1);
blrWriter.appendUChar(blr_default_code);
blrWriter.appendUChar(blr_begin); // 3
blrWriter.appendUChar(blr_end); // 3

if (foundDefault)
stuffDefaultBlr(ByteChunk(defaultVal, defaultLen), blrWriter);
else
{
// Neither column level nor domain level default exists.
blrWriter.appendUChar(blr_null);
}
}
blrWriter.appendUChar(blr_end); // 1
}

break;
}
generateUnnamedTriggerBeginning(constraint, onUpdate, blrWriter);

if (searchForDefault)
{
// case 2: See if the column/domain has already been created.
index = 0;

const USHORT defaultLen = METD_get_col_default(dsqlScratch->getTransaction(),
name.c_str(), column->c_str(), &foundDefault, defaultVal, sizeof(defaultVal));
for (ObjectsArray<MetaName>::const_iterator column(constraint.columns.begin());
column != constraint.columns.end();
++column, index += 2)
{
blrWriter.appendUChar(blr_assignment);

if (foundDefault)
stuffDefaultBlr(ByteChunk(defaultVal, defaultLen), blrWriter);
else
blrWriter.appendUChar(blr_null);
}
blrWriter.appendUChar(blr_variable);
blrWriter.appendUShort(index);

// The context for the foreign key relation.
blrWriter.appendUChar(blr_field);
Expand All @@ -6978,6 +6950,8 @@ void RelationNode::defineSetDefaultTrigger(DsqlCompilerScratch* dsqlScratch,
if (onUpdate)
blrWriter.appendUCharRepeated(blr_end, 3);

blrWriter.appendUChar(blr_end);

blrWriter.appendUChar(blr_eoc); // end of the blr

TriggerDefinition& trigger = constraint.triggers.add();
Expand Down

0 comments on commit 7bb6ceb

Please sign in to comment.