mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 22:43:03 +01:00
Feature CORE-5463 - Support GENERATED ALWAYS identity columns and OVERRIDE clause.
I didn't verified why the error messages are being truncated. It seems idiotic if the engine, library or ISQL does not accept these not-so-detailed messages.
This commit is contained in:
parent
0b80f7dbba
commit
3ca6fc140d
@ -11,16 +11,20 @@ Description:
|
|||||||
|
|
||||||
Syntax:
|
Syntax:
|
||||||
<column definition> ::=
|
<column definition> ::=
|
||||||
<name> <type> GENERATED BY DEFAULT AS IDENTITY [ ( <identity column option>... ) ] <constraints>
|
<name> <type> GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( <identity column option>... ) ] <constraints>
|
||||||
|
|
||||||
<identity column option> ::=
|
<identity column option> ::=
|
||||||
START WITH <value> |
|
START WITH <value> |
|
||||||
INCREMENT [ BY ] <value>
|
INCREMENT [ BY ] <value>
|
||||||
|
|
||||||
<alter column definition> ::=
|
<alter column definition> ::=
|
||||||
|
<name> <set identity column generation clause> [ <alter identity column option>... ] |
|
||||||
<name> <alter identity column option>... |
|
<name> <alter identity column option>... |
|
||||||
<name> DROP IDENTITY
|
<name> DROP IDENTITY
|
||||||
|
|
||||||
|
<set identity column generation clause> ::=
|
||||||
|
SET GENERATED { ALWAYS | BY DEFAULT }
|
||||||
|
|
||||||
<alter identity column option> ::=
|
<alter identity column option> ::=
|
||||||
RESTART [ WITH <value> ] |
|
RESTART [ WITH <value> ] |
|
||||||
SET INCREMENT [ BY ] <value>
|
SET INCREMENT [ BY ] <value>
|
||||||
@ -39,10 +43,8 @@ Notes:
|
|||||||
Implementation:
|
Implementation:
|
||||||
Two columns have been inserted in RDB$RELATION_FIELDS: RDB$GENERATOR_NAME and RDB$IDENTITY_TYPE.
|
Two columns have been inserted in RDB$RELATION_FIELDS: RDB$GENERATOR_NAME and RDB$IDENTITY_TYPE.
|
||||||
RDB$GENERATOR_NAME stores the automatically created generator for the column. In RDB$GENERATORS,
|
RDB$GENERATOR_NAME stores the automatically created generator for the column. In RDB$GENERATORS,
|
||||||
the value of RDB$SYSTEM_FLAG of that generator will be 6. RDB$IDENTITY_TYPE will currently
|
the value of RDB$SYSTEM_FLAG of that generator will be 6. RDB$IDENTITY_TYPE stores the value
|
||||||
always store the value 1 (by default) for identity columns and NULL for non-identity columns.
|
0 for GENERATED ALWAYS, 1 for GENERATED BY DEFAULT, and NULL for non-identity columns.
|
||||||
In the future this column will store the value 0, too (for ALWAYS) when Firebird support this type
|
|
||||||
of identity column.
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -84,3 +86,21 @@ alter table objects
|
|||||||
|
|
||||||
alter table objects
|
alter table objects
|
||||||
alter id drop identity;
|
alter id drop identity;
|
||||||
|
|
||||||
|
|
||||||
|
---------------
|
||||||
|
Override Clause
|
||||||
|
---------------
|
||||||
|
|
||||||
|
BY DEFAULT identity columns can be overriden in INSERT statements (INSERT, UPDATE OR INSERT, MERGE ... WHEN NOT MATCHED)
|
||||||
|
just specifying the value in the values list. However, for ALWAYS identity columns that is not allowed.
|
||||||
|
|
||||||
|
To use the value passed in the INSERT statement for an ALWAYS column, you should pass OVERRIDING SYSTEM VALUE as
|
||||||
|
following:
|
||||||
|
|
||||||
|
insert into objects (id, name) overriding system value values (11, 'Laptop');
|
||||||
|
|
||||||
|
OVERRIDING also supports a subclause to be used with BY DEFAULT columns, to ignore the value passed in INSERT and use
|
||||||
|
the defined sequence:
|
||||||
|
|
||||||
|
insert into objects (id, name) overriding user value values (12, 'Laptop'); -- 12 is not used
|
||||||
|
@ -1678,6 +1678,14 @@ C --
|
|||||||
PARAMETER (GDS__att_shut_db_down = 335545132)
|
PARAMETER (GDS__att_shut_db_down = 335545132)
|
||||||
INTEGER*4 GDS__att_shut_engine
|
INTEGER*4 GDS__att_shut_engine
|
||||||
PARAMETER (GDS__att_shut_engine = 335545133)
|
PARAMETER (GDS__att_shut_engine = 335545133)
|
||||||
|
INTEGER*4 GDS__overriding_without_identity
|
||||||
|
PARAMETER (GDS__overriding_without_identity = 335545134)
|
||||||
|
INTEGER*4 GDS__overriding_system_invalid
|
||||||
|
PARAMETER (GDS__overriding_system_invalid = 335545135)
|
||||||
|
INTEGER*4 GDS__overriding_user_invalid
|
||||||
|
PARAMETER (GDS__overriding_user_invalid = 335545136)
|
||||||
|
INTEGER*4 GDS__overriding_system_missing
|
||||||
|
PARAMETER (GDS__overriding_system_missing = 335545137)
|
||||||
INTEGER*4 GDS__gfix_db_name
|
INTEGER*4 GDS__gfix_db_name
|
||||||
PARAMETER (GDS__gfix_db_name = 335740929)
|
PARAMETER (GDS__gfix_db_name = 335740929)
|
||||||
INTEGER*4 GDS__gfix_invalid_sw
|
INTEGER*4 GDS__gfix_invalid_sw
|
||||||
|
@ -1673,6 +1673,14 @@ const
|
|||||||
gds_att_shut_db_down = 335545132;
|
gds_att_shut_db_down = 335545132;
|
||||||
isc_att_shut_engine = 335545133;
|
isc_att_shut_engine = 335545133;
|
||||||
gds_att_shut_engine = 335545133;
|
gds_att_shut_engine = 335545133;
|
||||||
|
isc_overriding_without_identity = 335545134;
|
||||||
|
gds_overriding_without_identity = 335545134;
|
||||||
|
isc_overriding_system_invalid = 335545135;
|
||||||
|
gds_overriding_system_invalid = 335545135;
|
||||||
|
isc_overriding_user_invalid = 335545136;
|
||||||
|
gds_overriding_user_invalid = 335545136;
|
||||||
|
isc_overriding_system_missing = 335545137;
|
||||||
|
gds_overriding_system_missing = 335545137;
|
||||||
isc_gfix_db_name = 335740929;
|
isc_gfix_db_name = 335740929;
|
||||||
gds_gfix_db_name = 335740929;
|
gds_gfix_db_name = 335740929;
|
||||||
isc_gfix_invalid_sw = 335740930;
|
isc_gfix_invalid_sw = 335740930;
|
||||||
|
@ -35,7 +35,7 @@ class NullableClear
|
|||||||
public:
|
public:
|
||||||
static void clear(T& v)
|
static void clear(T& v)
|
||||||
{
|
{
|
||||||
v = 0;
|
v = T();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -70,6 +70,11 @@ public:
|
|||||||
return (!specified && !o.specified) || (specified == o.specified && value == o.value);
|
return (!specified && !o.specified) || (specified == o.specified && value == o.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator ==(const T& o) const
|
||||||
|
{
|
||||||
|
return specified && value == o;
|
||||||
|
}
|
||||||
|
|
||||||
void operator =(const T& v)
|
void operator =(const T& v)
|
||||||
{
|
{
|
||||||
this->value = v;
|
this->value = v;
|
||||||
@ -84,26 +89,6 @@ public:
|
|||||||
|
|
||||||
// NullableClear specializations.
|
// NullableClear specializations.
|
||||||
|
|
||||||
template <>
|
|
||||||
class NullableClear<Firebird::string> // string especialization for NullableClear
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void clear(Firebird::string& v)
|
|
||||||
{
|
|
||||||
v = "";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
class NullableClear<Firebird::MetaName> // MetaName especialization for NullableClear
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void clear(Firebird::MetaName& v)
|
|
||||||
{
|
|
||||||
v = "";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class NullableClear<BaseNullable<T> >
|
class NullableClear<BaseNullable<T> >
|
||||||
{
|
{
|
||||||
|
@ -5951,7 +5951,7 @@ void RelationNode::FieldDefinition::store(thread_db* tdbb, jrd_tra* transaction)
|
|||||||
strcpy(RFR.RDB$GENERATOR_NAME, identitySequence.c_str());
|
strcpy(RFR.RDB$GENERATOR_NAME, identitySequence.c_str());
|
||||||
|
|
||||||
RFR.RDB$IDENTITY_TYPE.NULL = FALSE;
|
RFR.RDB$IDENTITY_TYPE.NULL = FALSE;
|
||||||
RFR.RDB$IDENTITY_TYPE = IDENT_TYPE_BY_DEFAULT;
|
RFR.RDB$IDENTITY_TYPE = identityType.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notNullFlag.specified)
|
if (notNullFlag.specified)
|
||||||
@ -6296,6 +6296,7 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
|
|||||||
}
|
}
|
||||||
|
|
||||||
DYN_UTIL_generate_generator_name(tdbb, fieldDefinition.identitySequence);
|
DYN_UTIL_generate_generator_name(tdbb, fieldDefinition.identitySequence);
|
||||||
|
fieldDefinition.identityType = clause->identityOptions->type;
|
||||||
|
|
||||||
CreateAlterSequenceNode::store(tdbb, transaction, fieldDefinition.identitySequence,
|
CreateAlterSequenceNode::store(tdbb, transaction, fieldDefinition.identitySequence,
|
||||||
fb_sysflag_identity_generator,
|
fb_sysflag_identity_generator,
|
||||||
@ -7858,6 +7859,13 @@ void AlterRelationNode::modifyField(thread_db* tdbb, DsqlCompilerScratch* dsqlSc
|
|||||||
transaction->getGenIdCache()->put(id, val);
|
transaction->getGenIdCache()->put(id, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (clause->identityOptions->type.specified)
|
||||||
|
{
|
||||||
|
MODIFY RFR
|
||||||
|
RFR.RDB$IDENTITY_TYPE = clause->identityOptions->type.value;
|
||||||
|
END_MODIFY
|
||||||
|
}
|
||||||
|
|
||||||
if (clause->identityOptions->increment.specified)
|
if (clause->identityOptions->increment.specified)
|
||||||
{
|
{
|
||||||
if (clause->identityOptions->increment.value == 0)
|
if (clause->identityOptions->increment.value == 0)
|
||||||
|
@ -1140,6 +1140,7 @@ public:
|
|||||||
Firebird::MetaName relationName;
|
Firebird::MetaName relationName;
|
||||||
Firebird::MetaName fieldSource;
|
Firebird::MetaName fieldSource;
|
||||||
Firebird::MetaName identitySequence;
|
Firebird::MetaName identitySequence;
|
||||||
|
Nullable<IdentityType> identityType;
|
||||||
Nullable<USHORT> collationId;
|
Nullable<USHORT> collationId;
|
||||||
Nullable<bool> notNullFlag; // true = NOT NULL / false = NULL
|
Nullable<bool> notNullFlag; // true = NOT NULL / false = NULL
|
||||||
Nullable<USHORT> position;
|
Nullable<USHORT> position;
|
||||||
@ -1306,11 +1307,18 @@ public:
|
|||||||
|
|
||||||
struct IdentityOptions
|
struct IdentityOptions
|
||||||
{
|
{
|
||||||
|
IdentityOptions(MemoryPool&, IdentityType aType)
|
||||||
|
: type(aType),
|
||||||
|
restart(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
IdentityOptions(MemoryPool&)
|
IdentityOptions(MemoryPool&)
|
||||||
: restart(false)
|
: restart(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Nullable<IdentityType> type;
|
||||||
Nullable<SINT64> startValue;
|
Nullable<SINT64> startValue;
|
||||||
Nullable<SLONG> increment;
|
Nullable<SLONG> increment;
|
||||||
bool restart; // used in ALTER
|
bool restart; // used in ALTER
|
||||||
|
@ -94,6 +94,8 @@ static void postTriggerAccess(CompilerScratch* csb, jrd_rel* ownerRelation,
|
|||||||
ExternalAccess::exa_act operation, jrd_rel* view);
|
ExternalAccess::exa_act operation, jrd_rel* view);
|
||||||
static void preModifyEraseTriggers(thread_db* tdbb, TrigVector** trigs,
|
static void preModifyEraseTriggers(thread_db* tdbb, TrigVector** trigs,
|
||||||
StmtNode::WhichTrigger whichTrig, record_param* rpb, record_param* rec, TriggerAction op);
|
StmtNode::WhichTrigger whichTrig, record_param* rpb, record_param* rec, TriggerAction op);
|
||||||
|
static void preprocessAssignments(thread_db* tdbb, CompilerScratch* csb,
|
||||||
|
StreamType stream, CompoundStmtNode* compoundNode, const Nullable<OverrideClause>* insertOverride);
|
||||||
static void validateExpressions(thread_db* tdbb, const Array<ValidateInfo>& validations);
|
static void validateExpressions(thread_db* tdbb, const Array<ValidateInfo>& validations);
|
||||||
|
|
||||||
} // namespace Jrd
|
} // namespace Jrd
|
||||||
@ -5340,6 +5342,7 @@ StmtNode* MergeNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
|||||||
store->dsqlRelation = relation;
|
store->dsqlRelation = relation;
|
||||||
store->dsqlFields = notMatched->fields;
|
store->dsqlFields = notMatched->fields;
|
||||||
store->dsqlValues = notMatched->values;
|
store->dsqlValues = notMatched->values;
|
||||||
|
store->overrideClause = notMatched->overrideClause;
|
||||||
|
|
||||||
bool needSavePoint; // unused
|
bool needSavePoint; // unused
|
||||||
thisIf->trueAction = store = store->internalDsqlPass(dsqlScratch, false, needSavePoint)->as<StoreNode>();
|
thisIf->trueAction = store = store->internalDsqlPass(dsqlScratch, false, needSavePoint)->as<StoreNode>();
|
||||||
@ -5881,50 +5884,7 @@ void ModifyNode::genBlr(DsqlCompilerScratch* dsqlScratch)
|
|||||||
|
|
||||||
ModifyNode* ModifyNode::pass1(thread_db* tdbb, CompilerScratch* csb)
|
ModifyNode* ModifyNode::pass1(thread_db* tdbb, CompilerScratch* csb)
|
||||||
{
|
{
|
||||||
CompoundStmtNode* compoundNode = statement->as<CompoundStmtNode>();
|
preprocessAssignments(tdbb, csb, newStream, statement->as<CompoundStmtNode>(), NULL);
|
||||||
|
|
||||||
// Remove assignments of DEFAULT to computed fields.
|
|
||||||
if (compoundNode)
|
|
||||||
{
|
|
||||||
for (size_t i = compoundNode->statements.getCount(); i--; )
|
|
||||||
{
|
|
||||||
const AssignmentNode* assign = compoundNode->statements[i]->as<AssignmentNode>();
|
|
||||||
fb_assert(assign);
|
|
||||||
if (!assign)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const ExprNode* assignFrom = assign->asgnFrom;
|
|
||||||
const FieldNode* assignToField = assign->asgnTo->as<FieldNode>();
|
|
||||||
|
|
||||||
if (assignToField && assignFrom->is<DefaultNode>())
|
|
||||||
{
|
|
||||||
jrd_rel* relation = csb->csb_rpt[newStream].csb_relation;
|
|
||||||
int fieldId = assignToField->fieldId;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
jrd_fld* fld;
|
|
||||||
|
|
||||||
if (assignToField->fieldStream == newStream &&
|
|
||||||
relation &&
|
|
||||||
relation->rel_fields &&
|
|
||||||
(fld = (*relation->rel_fields)[fieldId]))
|
|
||||||
{
|
|
||||||
if (fld->fld_computation)
|
|
||||||
compoundNode->statements.remove(i);
|
|
||||||
else if (relation->rel_view_rse && fld->fld_source_rel_field.first.hasData())
|
|
||||||
{
|
|
||||||
relation = MET_lookup_relation(tdbb, fld->fld_source_rel_field.first);
|
|
||||||
if ((fieldId = MET_lookup_field(tdbb, relation, fld->fld_source_rel_field.second)) >= 0)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pass1Modify(tdbb, csb, this);
|
pass1Modify(tdbb, csb, this);
|
||||||
|
|
||||||
@ -6463,6 +6423,7 @@ const StmtNode* ReceiveNode::execute(thread_db* /*tdbb*/, jrd_req* request, ExeS
|
|||||||
|
|
||||||
static RegisterNode<StoreNode> regStoreNode(blr_store);
|
static RegisterNode<StoreNode> regStoreNode(blr_store);
|
||||||
static RegisterNode<StoreNode> regStoreNode2(blr_store2);
|
static RegisterNode<StoreNode> regStoreNode2(blr_store2);
|
||||||
|
static RegisterNode<StoreNode> regStoreNode3(blr_store3);
|
||||||
|
|
||||||
// Parse a store statement.
|
// Parse a store statement.
|
||||||
DmlNode* StoreNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp)
|
DmlNode* StoreNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp)
|
||||||
@ -6471,6 +6432,21 @@ DmlNode* StoreNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* cs
|
|||||||
|
|
||||||
AutoSetRestore<StmtNode*> autoCurrentDMLNode(&csb->csb_currentDMLNode, node);
|
AutoSetRestore<StmtNode*> autoCurrentDMLNode(&csb->csb_currentDMLNode, node);
|
||||||
|
|
||||||
|
if (blrOp == blr_store3)
|
||||||
|
{
|
||||||
|
node->overrideClause = static_cast<OverrideClause>(csb->csb_blr_reader.getByte());
|
||||||
|
|
||||||
|
switch (node->overrideClause.value)
|
||||||
|
{
|
||||||
|
case OverrideClause::USER_VALUE:
|
||||||
|
case OverrideClause::SYSTEM_VALUE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
PAR_syntax_error(csb, "invalid blr_store3 override clause");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const UCHAR* blrPos = csb->csb_blr_reader.getPos();
|
const UCHAR* blrPos = csb->csb_blr_reader.getPos();
|
||||||
|
|
||||||
node->relationSource = PAR_parseRecordSource(tdbb, csb)->as<RelationSourceNode>();
|
node->relationSource = PAR_parseRecordSource(tdbb, csb)->as<RelationSourceNode>();
|
||||||
@ -6485,6 +6461,13 @@ DmlNode* StoreNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* cs
|
|||||||
|
|
||||||
if (blrOp == blr_store2)
|
if (blrOp == blr_store2)
|
||||||
node->statement2 = PAR_parse_stmt(tdbb, csb);
|
node->statement2 = PAR_parse_stmt(tdbb, csb);
|
||||||
|
else if (blrOp == blr_store3)
|
||||||
|
{
|
||||||
|
if (csb->csb_blr_reader.peekByte() == blr_null)
|
||||||
|
csb->csb_blr_reader.getByte();
|
||||||
|
else
|
||||||
|
node->statement2 = PAR_parse_stmt(tdbb, csb);
|
||||||
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@ -6498,6 +6481,7 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch,
|
|||||||
dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_INSERT);
|
dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_INSERT);
|
||||||
|
|
||||||
StoreNode* node = FB_NEW_POOL(getPool()) StoreNode(getPool());
|
StoreNode* node = FB_NEW_POOL(getPool()) StoreNode(getPool());
|
||||||
|
node->overrideClause = overrideClause;
|
||||||
|
|
||||||
// Process SELECT expression, if present
|
// Process SELECT expression, if present
|
||||||
|
|
||||||
@ -6606,7 +6590,21 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch,
|
|||||||
NestConst<ValueExprNode>* ptr2 = values->items.begin();
|
NestConst<ValueExprNode>* ptr2 = values->items.begin();
|
||||||
for (const NestConst<ValueExprNode>* end = fields.end(); ptr != end; ++ptr, ++ptr2)
|
for (const NestConst<ValueExprNode>* end = fields.end(); ptr != end; ++ptr, ++ptr2)
|
||||||
{
|
{
|
||||||
if (*ptr2) // it's NULL for DEFAULT
|
// *ptr2 is NULL for DEFAULT
|
||||||
|
|
||||||
|
if (!*ptr2)
|
||||||
|
{
|
||||||
|
const FieldNode* field = (*ptr)->as<FieldNode>();
|
||||||
|
|
||||||
|
if (field && field->dsqlField)
|
||||||
|
{
|
||||||
|
*ptr2 = FB_NEW_POOL(getPool()) DefaultNode(getPool(),
|
||||||
|
relation->rel_name, field->dsqlField->fld_name);
|
||||||
|
*ptr2 = doDsqlPass(dsqlScratch, *ptr2, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ptr2)
|
||||||
{
|
{
|
||||||
AssignmentNode* temp = FB_NEW_POOL(getPool()) AssignmentNode(getPool());
|
AssignmentNode* temp = FB_NEW_POOL(getPool()) AssignmentNode(getPool());
|
||||||
temp->asgnFrom = *ptr2;
|
temp->asgnFrom = *ptr2;
|
||||||
@ -6691,12 +6689,19 @@ void StoreNode::genBlr(DsqlCompilerScratch* dsqlScratch)
|
|||||||
{
|
{
|
||||||
const dsql_msg* message = dsqlGenDmlHeader(dsqlScratch, dsqlRse->as<RseNode>());
|
const dsql_msg* message = dsqlGenDmlHeader(dsqlScratch, dsqlRse->as<RseNode>());
|
||||||
|
|
||||||
dsqlScratch->appendUChar(statement2 ? blr_store2 : blr_store);
|
dsqlScratch->appendUChar(overrideClause.specified ? blr_store3 : (statement2 ? blr_store2 : blr_store));
|
||||||
|
|
||||||
|
if (overrideClause.specified)
|
||||||
|
dsqlScratch->appendUChar(UCHAR(overrideClause.value));
|
||||||
|
|
||||||
GEN_expr(dsqlScratch, dsqlRelation);
|
GEN_expr(dsqlScratch, dsqlRelation);
|
||||||
|
|
||||||
statement->genBlr(dsqlScratch);
|
statement->genBlr(dsqlScratch);
|
||||||
|
|
||||||
if (statement2)
|
if (statement2)
|
||||||
statement2->genBlr(dsqlScratch);
|
statement2->genBlr(dsqlScratch);
|
||||||
|
else if (overrideClause.specified)
|
||||||
|
dsqlScratch->appendUChar(blr_null);
|
||||||
|
|
||||||
if (message)
|
if (message)
|
||||||
dsqlScratch->appendUChar(blr_end);
|
dsqlScratch->appendUChar(blr_end);
|
||||||
@ -6704,6 +6709,8 @@ void StoreNode::genBlr(DsqlCompilerScratch* dsqlScratch)
|
|||||||
|
|
||||||
StoreNode* StoreNode::pass1(thread_db* tdbb, CompilerScratch* csb)
|
StoreNode* StoreNode::pass1(thread_db* tdbb, CompilerScratch* csb)
|
||||||
{
|
{
|
||||||
|
preprocessAssignments(tdbb, csb, relationSource->getStream(), statement->as<CompoundStmtNode>(), &overrideClause);
|
||||||
|
|
||||||
if (pass1Store(tdbb, csb, this))
|
if (pass1Store(tdbb, csb, this))
|
||||||
makeDefaults(tdbb, csb);
|
makeDefaults(tdbb, csb);
|
||||||
|
|
||||||
@ -6839,7 +6846,6 @@ void StoreNode::makeDefaults(thread_db* tdbb, CompilerScratch* csb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
StmtNodeStack stack;
|
StmtNodeStack stack;
|
||||||
|
|
||||||
USHORT fieldId = 0;
|
USHORT fieldId = 0;
|
||||||
vec<jrd_fld*>::iterator ptr1 = vector->begin();
|
vec<jrd_fld*>::iterator ptr1 = vector->begin();
|
||||||
|
|
||||||
@ -6869,10 +6875,7 @@ void StoreNode::makeDefaults(thread_db* tdbb, CompilerScratch* csb)
|
|||||||
fb_assert(fieldNode);
|
fb_assert(fieldNode);
|
||||||
|
|
||||||
if (fieldNode && fieldNode->fieldStream == stream && fieldNode->fieldId == fieldId)
|
if (fieldNode && fieldNode->fieldStream == stream && fieldNode->fieldId == fieldId)
|
||||||
{
|
|
||||||
inList = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8071,6 +8074,7 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
|||||||
insert->dsqlFields = fields;
|
insert->dsqlFields = fields;
|
||||||
insert->dsqlValues = values;
|
insert->dsqlValues = values;
|
||||||
insert->dsqlReturning = returning;
|
insert->dsqlReturning = returning;
|
||||||
|
insert->overrideClause = overrideClause;
|
||||||
insert = insert->internalDsqlPass(dsqlScratch, true, needSavePoint)->as<StoreNode>();
|
insert = insert->internalDsqlPass(dsqlScratch, true, needSavePoint)->as<StoreNode>();
|
||||||
fb_assert(insert);
|
fb_assert(insert);
|
||||||
|
|
||||||
@ -9324,6 +9328,99 @@ static void preModifyEraseTriggers(thread_db* tdbb, TrigVector** trigs,
|
|||||||
tdbb->getTransaction()->tra_rpblist->PopRpb(rpb, rpblevel);
|
tdbb->getTransaction()->tra_rpblist->PopRpb(rpb, rpblevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1. Remove assignments of DEFAULT to computed fields.
|
||||||
|
// 2. Remove assignments to identity column when OVERRIDING USER VALUE is specified in INSERT.
|
||||||
|
static void preprocessAssignments(thread_db* tdbb, CompilerScratch* csb,
|
||||||
|
StreamType stream, CompoundStmtNode* compoundNode, const Nullable<OverrideClause>* insertOverride)
|
||||||
|
{
|
||||||
|
if (!compoundNode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
jrd_rel* relation = csb->csb_rpt[stream].csb_relation;
|
||||||
|
|
||||||
|
fb_assert(relation);
|
||||||
|
if (!relation)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Nullable<IdentityType> identityType;
|
||||||
|
|
||||||
|
for (size_t i = compoundNode->statements.getCount(); i--; )
|
||||||
|
{
|
||||||
|
const AssignmentNode* assign = compoundNode->statements[i]->as<AssignmentNode>();
|
||||||
|
fb_assert(assign);
|
||||||
|
if (!assign)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const ExprNode* assignFrom = assign->asgnFrom;
|
||||||
|
const FieldNode* assignToField = assign->asgnTo->as<FieldNode>();
|
||||||
|
|
||||||
|
if (assignToField)
|
||||||
|
{
|
||||||
|
int fieldId = assignToField->fieldId;
|
||||||
|
jrd_fld* fld;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (assignToField->fieldStream == stream &&
|
||||||
|
relation->rel_fields &&
|
||||||
|
(fld = (*relation->rel_fields)[fieldId]))
|
||||||
|
{
|
||||||
|
if (insertOverride && fld->fld_identity_type.specified)
|
||||||
|
{
|
||||||
|
if (insertOverride->specified || !assignFrom->is<DefaultNode>())
|
||||||
|
identityType = fld->fld_identity_type;
|
||||||
|
|
||||||
|
if (*insertOverride == OverrideClause::USER_VALUE)
|
||||||
|
{
|
||||||
|
compoundNode->statements.remove(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fld->fld_computation)
|
||||||
|
{
|
||||||
|
if (assignFrom->is<DefaultNode>())
|
||||||
|
compoundNode->statements.remove(i);
|
||||||
|
}
|
||||||
|
else if (relation->rel_view_rse && fld->fld_source_rel_field.first.hasData())
|
||||||
|
{
|
||||||
|
relation = MET_lookup_relation(tdbb, fld->fld_source_rel_field.first);
|
||||||
|
|
||||||
|
fb_assert(relation);
|
||||||
|
if (!relation)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((fieldId = MET_lookup_field(tdbb, relation, fld->fld_source_rel_field.second)) >= 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!insertOverride)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (insertOverride->specified)
|
||||||
|
{
|
||||||
|
if (!identityType.specified)
|
||||||
|
ERR_post(Arg::Gds(isc_overriding_without_identity) << relation->rel_name);
|
||||||
|
|
||||||
|
if (identityType == IDENT_TYPE_BY_DEFAULT && *insertOverride == OverrideClause::SYSTEM_VALUE)
|
||||||
|
ERR_post(Arg::Gds(isc_overriding_system_invalid) << relation->rel_name);
|
||||||
|
|
||||||
|
if (identityType == IDENT_TYPE_ALWAYS && *insertOverride == OverrideClause::USER_VALUE)
|
||||||
|
ERR_post(Arg::Gds(isc_overriding_user_invalid) << relation->rel_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (identityType == IDENT_TYPE_ALWAYS)
|
||||||
|
ERR_post(Arg::Gds(isc_overriding_system_missing) << relation->rel_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Execute a list of validation expressions.
|
// Execute a list of validation expressions.
|
||||||
static void validateExpressions(thread_db* tdbb, const Array<ValidateInfo>& validations)
|
static void validateExpressions(thread_db* tdbb, const Array<ValidateInfo>& validations)
|
||||||
{
|
{
|
||||||
|
@ -112,6 +112,14 @@ struct ValidateInfo
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum OverrideClause : UCHAR
|
||||||
|
{
|
||||||
|
// Warning: used in BLR
|
||||||
|
USER_VALUE = 1,
|
||||||
|
SYSTEM_VALUE
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class AssignmentNode : public TypedNode<StmtNode, StmtNode::TYPE_ASSIGNMENT>
|
class AssignmentNode : public TypedNode<StmtNode, StmtNode::TYPE_ASSIGNMENT>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -1048,6 +1056,7 @@ public:
|
|||||||
Firebird::Array<NestConst<FieldNode> > fields;
|
Firebird::Array<NestConst<FieldNode> > fields;
|
||||||
NestConst<ValueListNode> values;
|
NestConst<ValueListNode> values;
|
||||||
NestConst<BoolExprNode> condition;
|
NestConst<BoolExprNode> condition;
|
||||||
|
Nullable<OverrideClause> overrideClause;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit MergeNode(MemoryPool& pool)
|
explicit MergeNode(MemoryPool& pool)
|
||||||
@ -1267,6 +1276,7 @@ public:
|
|||||||
NestConst<StmtNode> subStore;
|
NestConst<StmtNode> subStore;
|
||||||
Firebird::Array<ValidateInfo> validations;
|
Firebird::Array<ValidateInfo> validations;
|
||||||
NestConst<RelationSourceNode> relationSource;
|
NestConst<RelationSourceNode> relationSource;
|
||||||
|
Nullable<OverrideClause> overrideClause;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1609,6 +1619,7 @@ public:
|
|||||||
NestConst<ValueListNode> values;
|
NestConst<ValueListNode> values;
|
||||||
Firebird::Array<NestConst<FieldNode> > matching;
|
Firebird::Array<NestConst<FieldNode> > matching;
|
||||||
NestConst<ReturningClause> returning;
|
NestConst<ReturningClause> returning;
|
||||||
|
Nullable<OverrideClause> overrideClause;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
45 shift/reduce conflicts, 17 reduce/reduce conflicts.
|
46 shift/reduce conflicts, 17 reduce/reduce conflicts.
|
||||||
|
@ -600,6 +600,7 @@ using namespace Firebird;
|
|||||||
%token <metaNamePtr> MESSAGE
|
%token <metaNamePtr> MESSAGE
|
||||||
%token <metaNamePtr> NTILE
|
%token <metaNamePtr> NTILE
|
||||||
%token <metaNamePtr> OTHERS
|
%token <metaNamePtr> OTHERS
|
||||||
|
%token <metaNamePtr> OVERRIDING
|
||||||
%token <metaNamePtr> PERCENT_RANK
|
%token <metaNamePtr> PERCENT_RANK
|
||||||
%token <metaNamePtr> PRECEDING
|
%token <metaNamePtr> PRECEDING
|
||||||
%token <metaNamePtr> PRIVILEGE
|
%token <metaNamePtr> PRIVILEGE
|
||||||
@ -648,6 +649,7 @@ using namespace Firebird;
|
|||||||
BaseNullable<int> nullableIntVal;
|
BaseNullable<int> nullableIntVal;
|
||||||
BaseNullable<bool> nullableBoolVal;
|
BaseNullable<bool> nullableBoolVal;
|
||||||
BaseNullable<Jrd::TriggerDefinition::SqlSecurity> nullableSqlSecurityVal;
|
BaseNullable<Jrd::TriggerDefinition::SqlSecurity> nullableSqlSecurityVal;
|
||||||
|
BaseNullable<Jrd::OverrideClause> nullableOverrideClause;
|
||||||
bool boolVal;
|
bool boolVal;
|
||||||
int intVal;
|
int intVal;
|
||||||
unsigned uintVal;
|
unsigned uintVal;
|
||||||
@ -727,6 +729,7 @@ using namespace Firebird;
|
|||||||
Jrd::RelationNode::RefActionClause* refActionClause;
|
Jrd::RelationNode::RefActionClause* refActionClause;
|
||||||
Jrd::RelationNode::IndexConstraintClause* indexConstraintClause;
|
Jrd::RelationNode::IndexConstraintClause* indexConstraintClause;
|
||||||
Jrd::RelationNode::IdentityOptions* identityOptions;
|
Jrd::RelationNode::IdentityOptions* identityOptions;
|
||||||
|
IdentityType identityType;
|
||||||
Jrd::CreateRelationNode* createRelationNode;
|
Jrd::CreateRelationNode* createRelationNode;
|
||||||
Jrd::CreateAlterViewNode* createAlterViewNode;
|
Jrd::CreateAlterViewNode* createAlterViewNode;
|
||||||
Jrd::CreateIndexNode* createIndexNode;
|
Jrd::CreateIndexNode* createIndexNode;
|
||||||
@ -2185,10 +2188,16 @@ column_def($relationNode)
|
|||||||
|
|
||||||
%type <identityOptions> identity_clause
|
%type <identityOptions> identity_clause
|
||||||
identity_clause
|
identity_clause
|
||||||
: GENERATED BY DEFAULT AS IDENTITY
|
: GENERATED identity_clause_type AS IDENTITY
|
||||||
{ $$ = newNode<RelationNode::IdentityOptions>(); }
|
{ $$ = newNode<RelationNode::IdentityOptions>($2); }
|
||||||
identity_clause_options_opt($6)
|
identity_clause_options_opt($5)
|
||||||
{ $$ = $6; }
|
{ $$ = $5; }
|
||||||
|
;
|
||||||
|
|
||||||
|
%type <identityType> identity_clause_type
|
||||||
|
identity_clause_type
|
||||||
|
: BY DEFAULT { $$ = IDENT_TYPE_BY_DEFAULT; }
|
||||||
|
| ALWAYS { $$ = IDENT_TYPE_ALWAYS; }
|
||||||
;
|
;
|
||||||
|
|
||||||
%type identity_clause_options_opt(<identityOptions>)
|
%type identity_clause_options_opt(<identityOptions>)
|
||||||
@ -3935,7 +3944,7 @@ alter_op($relationNode)
|
|||||||
}
|
}
|
||||||
| col_opt symbol_column_name
|
| col_opt symbol_column_name
|
||||||
{ $<identityOptions>$ = newNode<RelationNode::IdentityOptions>(); }
|
{ $<identityOptions>$ = newNode<RelationNode::IdentityOptions>(); }
|
||||||
alter_identity_clause_options($<identityOptions>3)
|
alter_identity_clause_spec($<identityOptions>3)
|
||||||
{
|
{
|
||||||
RelationNode::AlterColTypeClause* clause = newNode<RelationNode::AlterColTypeClause>();
|
RelationNode::AlterColTypeClause* clause = newNode<RelationNode::AlterColTypeClause>();
|
||||||
clause->field = newNode<dsql_fld>();
|
clause->field = newNode<dsql_fld>();
|
||||||
@ -4081,6 +4090,24 @@ alter_data_type_or_domain
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
%type alter_identity_clause_spec(<identityOptions>)
|
||||||
|
alter_identity_clause_spec($identityOptions)
|
||||||
|
: alter_identity_clause_generation($identityOptions) alter_identity_clause_options_opt($identityOptions)
|
||||||
|
| alter_identity_clause_options($identityOptions)
|
||||||
|
;
|
||||||
|
|
||||||
|
%type alter_identity_clause_generation(<identityOptions>)
|
||||||
|
alter_identity_clause_generation($identityOptions)
|
||||||
|
: SET GENERATED ALWAYS { $identityOptions->type = IDENT_TYPE_ALWAYS; }
|
||||||
|
| SET GENERATED BY DEFAULT { $identityOptions->type = IDENT_TYPE_BY_DEFAULT; }
|
||||||
|
;
|
||||||
|
|
||||||
|
%type alter_identity_clause_options_opt(<identityOptions>)
|
||||||
|
alter_identity_clause_options_opt($identityOptions)
|
||||||
|
: // nothing
|
||||||
|
| alter_identity_clause_options($identityOptions)
|
||||||
|
;
|
||||||
|
|
||||||
%type alter_identity_clause_options(<identityOptions>)
|
%type alter_identity_clause_options(<identityOptions>)
|
||||||
alter_identity_clause_options($identityOptions)
|
alter_identity_clause_options($identityOptions)
|
||||||
: alter_identity_clause_options alter_identity_clause_option($identityOptions)
|
: alter_identity_clause_options alter_identity_clause_option($identityOptions)
|
||||||
@ -5942,18 +5969,20 @@ fetch_first_clause
|
|||||||
// IBO hack: replace column_parens_opt by ins_column_parens_opt.
|
// IBO hack: replace column_parens_opt by ins_column_parens_opt.
|
||||||
%type <storeNode> insert
|
%type <storeNode> insert
|
||||||
insert
|
insert
|
||||||
: insert_start ins_column_parens_opt(NOTRIAL(&$1->dsqlFields)) VALUES '(' value_or_default_list ')'
|
: insert_start ins_column_parens_opt(NOTRIAL(&$1->dsqlFields)) override_opt VALUES '(' value_or_default_list ')'
|
||||||
returning_clause
|
returning_clause
|
||||||
{
|
{
|
||||||
StoreNode* node = $$ = $1;
|
StoreNode* node = $$ = $1;
|
||||||
node->dsqlValues = $5;
|
node->overrideClause = $3;
|
||||||
node->dsqlReturning = $7;
|
node->dsqlValues = $6;
|
||||||
|
node->dsqlReturning = $8;
|
||||||
}
|
}
|
||||||
| insert_start ins_column_parens_opt(NOTRIAL(&$1->dsqlFields)) select_expr returning_clause
|
| insert_start ins_column_parens_opt(NOTRIAL(&$1->dsqlFields)) override_opt select_expr returning_clause
|
||||||
{
|
{
|
||||||
StoreNode* node = $$ = $1;
|
StoreNode* node = $$ = $1;
|
||||||
node->dsqlRse = $3;
|
node->overrideClause = $3;
|
||||||
node->dsqlReturning = $4;
|
node->dsqlRse = $4;
|
||||||
|
node->dsqlReturning = $5;
|
||||||
$$ = node;
|
$$ = node;
|
||||||
}
|
}
|
||||||
| insert_start DEFAULT VALUES returning_clause
|
| insert_start DEFAULT VALUES returning_clause
|
||||||
@ -5974,6 +6003,13 @@ insert_start
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
%type <nullableOverrideClause> override_opt
|
||||||
|
override_opt
|
||||||
|
: /* nothing */ { $$ = Nullable<OverrideClause>::empty(); }
|
||||||
|
| OVERRIDING USER VALUE { $$ = Nullable<OverrideClause>::val(OverrideClause::USER_VALUE); }
|
||||||
|
| OVERRIDING SYSTEM VALUE { $$ = Nullable<OverrideClause>::val(OverrideClause::SYSTEM_VALUE); }
|
||||||
|
;
|
||||||
|
|
||||||
%type <valueListNode> value_or_default_list
|
%type <valueListNode> value_or_default_list
|
||||||
value_or_default_list
|
value_or_default_list
|
||||||
: value_or_default { $$ = newNode<ValueListNode>($1); }
|
: value_or_default { $$ = newNode<ValueListNode>($1); }
|
||||||
@ -6042,13 +6078,17 @@ merge_update_specification($mergeMatchedClause, $relationName)
|
|||||||
|
|
||||||
%type merge_insert_specification(<mergeNotMatchedClause>)
|
%type merge_insert_specification(<mergeNotMatchedClause>)
|
||||||
merge_insert_specification($mergeNotMatchedClause)
|
merge_insert_specification($mergeNotMatchedClause)
|
||||||
: THEN INSERT ins_column_parens_opt(NOTRIAL(&$mergeNotMatchedClause->fields))
|
: THEN INSERT ins_column_parens_opt(NOTRIAL(&$mergeNotMatchedClause->fields)) override_opt
|
||||||
VALUES '(' value_or_default_list ')'
|
|
||||||
{ $mergeNotMatchedClause->values = $6; }
|
|
||||||
| AND search_condition THEN INSERT ins_column_parens_opt(NOTRIAL(&$mergeNotMatchedClause->fields))
|
|
||||||
VALUES '(' value_or_default_list ')'
|
VALUES '(' value_or_default_list ')'
|
||||||
{
|
{
|
||||||
$mergeNotMatchedClause->values = $8;
|
$mergeNotMatchedClause->overrideClause = $4;
|
||||||
|
$mergeNotMatchedClause->values = $7;
|
||||||
|
}
|
||||||
|
| AND search_condition THEN INSERT ins_column_parens_opt(NOTRIAL(&$mergeNotMatchedClause->fields)) override_opt
|
||||||
|
VALUES '(' value_or_default_list ')'
|
||||||
|
{
|
||||||
|
$mergeNotMatchedClause->overrideClause = $6;
|
||||||
|
$mergeNotMatchedClause->values = $9;
|
||||||
$mergeNotMatchedClause->condition = $2;
|
$mergeNotMatchedClause->condition = $2;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@ -6138,12 +6178,13 @@ update_or_insert
|
|||||||
UpdateOrInsertNode* node = $$ = newNode<UpdateOrInsertNode>();
|
UpdateOrInsertNode* node = $$ = newNode<UpdateOrInsertNode>();
|
||||||
node->relation = $5;
|
node->relation = $5;
|
||||||
}
|
}
|
||||||
ins_column_parens_opt(NOTRIAL(&$6->fields)) VALUES '(' value_or_default_list ')'
|
ins_column_parens_opt(NOTRIAL(&$6->fields)) override_opt VALUES '(' value_or_default_list ')'
|
||||||
update_or_insert_matching_opt(NOTRIAL(&$6->matching)) returning_clause
|
update_or_insert_matching_opt(NOTRIAL(&$6->matching)) returning_clause
|
||||||
{
|
{
|
||||||
UpdateOrInsertNode* node = $$ = $6;
|
UpdateOrInsertNode* node = $$ = $6;
|
||||||
node->values = $10;
|
node->overrideClause = $8;
|
||||||
node->returning = $13;
|
node->values = $11;
|
||||||
|
node->returning = $14;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -8248,6 +8289,7 @@ non_reserved_word
|
|||||||
| MESSAGE
|
| MESSAGE
|
||||||
| NTILE
|
| NTILE
|
||||||
| OTHERS
|
| OTHERS
|
||||||
|
| OVERRIDING
|
||||||
| PERCENT_RANK
|
| PERCENT_RANK
|
||||||
| PRECEDING
|
| PRECEDING
|
||||||
| PRIVILEGE
|
| PRIVILEGE
|
||||||
|
@ -835,6 +835,10 @@ static const struct {
|
|||||||
{"att_shut_idle", 335545131},
|
{"att_shut_idle", 335545131},
|
||||||
{"att_shut_db_down", 335545132},
|
{"att_shut_db_down", 335545132},
|
||||||
{"att_shut_engine", 335545133},
|
{"att_shut_engine", 335545133},
|
||||||
|
{"overriding_without_identity", 335545134},
|
||||||
|
{"overriding_system_invalid", 335545135},
|
||||||
|
{"overriding_user_invalid", 335545136},
|
||||||
|
{"overriding_system_missing", 335545137},
|
||||||
{"gfix_db_name", 335740929},
|
{"gfix_db_name", 335740929},
|
||||||
{"gfix_invalid_sw", 335740930},
|
{"gfix_invalid_sw", 335740930},
|
||||||
{"gfix_incmp_sw", 335740932},
|
{"gfix_incmp_sw", 335740932},
|
||||||
|
@ -869,6 +869,10 @@ const ISC_STATUS isc_att_shut_killed = 335545130L;
|
|||||||
const ISC_STATUS isc_att_shut_idle = 335545131L;
|
const ISC_STATUS isc_att_shut_idle = 335545131L;
|
||||||
const ISC_STATUS isc_att_shut_db_down = 335545132L;
|
const ISC_STATUS isc_att_shut_db_down = 335545132L;
|
||||||
const ISC_STATUS isc_att_shut_engine = 335545133L;
|
const ISC_STATUS isc_att_shut_engine = 335545133L;
|
||||||
|
const ISC_STATUS isc_overriding_without_identity = 335545134L;
|
||||||
|
const ISC_STATUS isc_overriding_system_invalid = 335545135L;
|
||||||
|
const ISC_STATUS isc_overriding_user_invalid = 335545136L;
|
||||||
|
const ISC_STATUS isc_overriding_system_missing = 335545137L;
|
||||||
const ISC_STATUS isc_gfix_db_name = 335740929L;
|
const ISC_STATUS isc_gfix_db_name = 335740929L;
|
||||||
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
|
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
|
||||||
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
|
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
|
||||||
@ -1343,7 +1347,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L;
|
|||||||
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
|
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
|
||||||
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
|
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
|
||||||
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
|
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
|
||||||
const ISC_STATUS isc_err_max = 1287;
|
const ISC_STATUS isc_err_max = 1291;
|
||||||
|
|
||||||
#else /* c definitions */
|
#else /* c definitions */
|
||||||
|
|
||||||
@ -2182,6 +2186,10 @@ const ISC_STATUS isc_err_max = 1287;
|
|||||||
#define isc_att_shut_idle 335545131L
|
#define isc_att_shut_idle 335545131L
|
||||||
#define isc_att_shut_db_down 335545132L
|
#define isc_att_shut_db_down 335545132L
|
||||||
#define isc_att_shut_engine 335545133L
|
#define isc_att_shut_engine 335545133L
|
||||||
|
#define isc_overriding_without_identity 335545134L
|
||||||
|
#define isc_overriding_system_invalid 335545135L
|
||||||
|
#define isc_overriding_user_invalid 335545136L
|
||||||
|
#define isc_overriding_system_missing 335545137L
|
||||||
#define isc_gfix_db_name 335740929L
|
#define isc_gfix_db_name 335740929L
|
||||||
#define isc_gfix_invalid_sw 335740930L
|
#define isc_gfix_invalid_sw 335740930L
|
||||||
#define isc_gfix_incmp_sw 335740932L
|
#define isc_gfix_incmp_sw 335740932L
|
||||||
@ -2656,7 +2664,7 @@ const ISC_STATUS isc_err_max = 1287;
|
|||||||
#define isc_trace_switch_param_miss 337182758L
|
#define isc_trace_switch_param_miss 337182758L
|
||||||
#define isc_trace_param_act_notcompat 337182759L
|
#define isc_trace_param_act_notcompat 337182759L
|
||||||
#define isc_trace_mandatory_switch_miss 337182760L
|
#define isc_trace_mandatory_switch_miss 337182760L
|
||||||
#define isc_err_max 1287
|
#define isc_err_max 1291
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -838,6 +838,10 @@ Data source : @4"}, /* eds_statement */
|
|||||||
{335545131, "Idle timeout expired."}, /* att_shut_idle */
|
{335545131, "Idle timeout expired."}, /* att_shut_idle */
|
||||||
{335545132, "Database is shutdown."}, /* att_shut_db_down */
|
{335545132, "Database is shutdown."}, /* att_shut_db_down */
|
||||||
{335545133, "Engine is shutdown."}, /* att_shut_engine */
|
{335545133, "Engine is shutdown."}, /* att_shut_engine */
|
||||||
|
{335545134, "OVERRIDING clause can be used only when an identity column is present in the INSERT's field list for table/view @1"}, /* overriding_without_identity */
|
||||||
|
{335545135, "OVERRIDING SYSTEM VALUE can be used only for identity column defined as 'GENERATED ALWAYS' in INSERT for table/view @1"}, /* overriding_system_invalid */
|
||||||
|
{335545136, "OVERRIDING USER VALUE can be used only for identity column defined as 'GENERATED BY DEFAULT' in INSERT for table/view"}, /* overriding_user_invalid */
|
||||||
|
{335545137, "OVERRIDING SYSTEM VALUE should be used to override the value of an identity column defined as 'GENERATED ALWAYS' in ta"}, /* overriding_system_missing */
|
||||||
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
|
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
|
||||||
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
|
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
|
||||||
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */
|
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */
|
||||||
|
@ -834,6 +834,10 @@ static const struct {
|
|||||||
{335545131, -902}, /* 811 att_shut_idle */
|
{335545131, -902}, /* 811 att_shut_idle */
|
||||||
{335545132, -902}, /* 812 att_shut_db_down */
|
{335545132, -902}, /* 812 att_shut_db_down */
|
||||||
{335545133, -902}, /* 813 att_shut_engine */
|
{335545133, -902}, /* 813 att_shut_engine */
|
||||||
|
{335545134, -902}, /* 814 overriding_without_identity */
|
||||||
|
{335545135, -902}, /* 815 overriding_system_invalid */
|
||||||
|
{335545136, -902}, /* 816 overriding_user_invalid */
|
||||||
|
{335545137, -902}, /* 817 overriding_system_missing */
|
||||||
{335740929, -901}, /* 1 gfix_db_name */
|
{335740929, -901}, /* 1 gfix_db_name */
|
||||||
{335740930, -901}, /* 2 gfix_invalid_sw */
|
{335740930, -901}, /* 2 gfix_invalid_sw */
|
||||||
{335740932, -901}, /* 4 gfix_incmp_sw */
|
{335740932, -901}, /* 4 gfix_incmp_sw */
|
||||||
|
@ -834,6 +834,10 @@ static const struct {
|
|||||||
{335545131, "08003"}, // 811 att_shut_idle
|
{335545131, "08003"}, // 811 att_shut_idle
|
||||||
{335545132, "08003"}, // 812 att_shut_db_down
|
{335545132, "08003"}, // 812 att_shut_db_down
|
||||||
{335545133, "08003"}, // 813 att_shut_engine
|
{335545133, "08003"}, // 813 att_shut_engine
|
||||||
|
{335545134, "42000"}, // 814 overriding_without_identity
|
||||||
|
{335545135, "42000"}, // 815 overriding_system_invalid
|
||||||
|
{335545136, "42000"}, // 816 overriding_user_invalid
|
||||||
|
{335545137, "42000"}, // 817 overriding_system_missing
|
||||||
{335740929, "00000"}, // 1 gfix_db_name
|
{335740929, "00000"}, // 1 gfix_db_name
|
||||||
{335740930, "00000"}, // 2 gfix_invalid_sw
|
{335740930, "00000"}, // 2 gfix_invalid_sw
|
||||||
{335740932, "00000"}, // 4 gfix_incmp_sw
|
{335740932, "00000"}, // 4 gfix_incmp_sw
|
||||||
|
@ -496,7 +496,9 @@ int EXTRACT_list_table(const SCHAR* relation_name,
|
|||||||
FOR GEN IN RDB$GENERATORS
|
FOR GEN IN RDB$GENERATORS
|
||||||
WITH GEN.RDB$GENERATOR_NAME = RFR.RDB$GENERATOR_NAME
|
WITH GEN.RDB$GENERATOR_NAME = RFR.RDB$GENERATOR_NAME
|
||||||
{
|
{
|
||||||
isqlGlob.printf(" GENERATED BY DEFAULT AS IDENTITY");
|
isqlGlob.printf(" GENERATED %s AS IDENTITY",
|
||||||
|
(RFR.RDB$IDENTITY_TYPE == IDENT_TYPE_BY_DEFAULT ? "BY DEFAULT" :
|
||||||
|
RFR.RDB$IDENTITY_TYPE == IDENT_TYPE_ALWAYS ? "ALWAYS" : ""));
|
||||||
|
|
||||||
if (!GEN.RDB$INITIAL_VALUE.NULL && GEN.RDB$INITIAL_VALUE != 0)
|
if (!GEN.RDB$INITIAL_VALUE.NULL && GEN.RDB$INITIAL_VALUE != 0)
|
||||||
isqlGlob.printf(" (START WITH %" SQUADFORMAT ")", GEN.RDB$INITIAL_VALUE);
|
isqlGlob.printf(" (START WITH %" SQUADFORMAT ")", GEN.RDB$INITIAL_VALUE);
|
||||||
|
@ -5838,7 +5838,11 @@ static processing_state show_table(const SCHAR* relation_name, bool isView)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!RFR.RDB$GENERATOR_NAME.NULL)
|
if (!RFR.RDB$GENERATOR_NAME.NULL)
|
||||||
isqlGlob.printf("Identity (by default)");
|
{
|
||||||
|
isqlGlob.printf("Identity (%s)",
|
||||||
|
(RFR.RDB$IDENTITY_TYPE == IDENT_TYPE_BY_DEFAULT ? "by default" :
|
||||||
|
RFR.RDB$IDENTITY_TYPE == IDENT_TYPE_ALWAYS ? "always" : ""));
|
||||||
|
}
|
||||||
|
|
||||||
// Handle defaults for columns
|
// Handle defaults for columns
|
||||||
|
|
||||||
|
@ -485,6 +485,7 @@ public:
|
|||||||
Firebird::MetaName fld_security_name; // security class name for field
|
Firebird::MetaName fld_security_name; // security class name for field
|
||||||
Firebird::MetaName fld_generator_name; // identity generator name
|
Firebird::MetaName fld_generator_name; // identity generator name
|
||||||
Firebird::MetaNamePair fld_source_rel_field; // Relation/field source name
|
Firebird::MetaNamePair fld_source_rel_field; // Relation/field source name
|
||||||
|
Nullable<IdentityType> fld_identity_type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit jrd_fld(MemoryPool& p)
|
explicit jrd_fld(MemoryPool& p)
|
||||||
|
@ -243,5 +243,6 @@ static const struct
|
|||||||
{"gen_id2", gen_id2}, // 210
|
{"gen_id2", gen_id2}, // 210
|
||||||
{"window_win", window_win},
|
{"window_win", window_win},
|
||||||
{"default", relation_field},
|
{"default", relation_field},
|
||||||
|
{"store3", store3},
|
||||||
{0, 0}
|
{0, 0}
|
||||||
};
|
};
|
||||||
|
@ -421,5 +421,6 @@
|
|||||||
#define blr_window_win_exclusion (unsigned char) 7
|
#define blr_window_win_exclusion (unsigned char) 7
|
||||||
|
|
||||||
#define blr_default (unsigned char) 212
|
#define blr_default (unsigned char) 212
|
||||||
|
#define blr_store3 (unsigned char) 213
|
||||||
|
|
||||||
#endif // JRD_BLR_H
|
#endif // JRD_BLR_H
|
||||||
|
@ -5754,6 +5754,10 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_
|
|||||||
(UCHAR*) RFR.RDB$GENERATOR_NAME, n);
|
(UCHAR*) RFR.RDB$GENERATOR_NAME, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n = RFR.RDB$IDENTITY_TYPE;
|
||||||
|
if (!RFR.RDB$IDENTITY_TYPE.NULL)
|
||||||
|
put_summary_record(tdbb, blob, RSR_field_identity_type, (UCHAR*) &n, sizeof(n));
|
||||||
|
|
||||||
// Make a temporary field block
|
// Make a temporary field block
|
||||||
|
|
||||||
TemporaryField* tfb = FB_NEW_POOL(*tdbb->getDefaultPool()) TemporaryField;
|
TemporaryField* tfb = FB_NEW_POOL(*tdbb->getDefaultPool()) TemporaryField;
|
||||||
|
@ -449,6 +449,10 @@ ISC_STATUS filter_runtime(USHORT action, BlobControl* control)
|
|||||||
sprintf(line, " field_generator_name: %s", p);
|
sprintf(line, " field_generator_name: %s", p);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case RSR_field_identity_type:
|
||||||
|
sprintf(line, "Field identity type: %d", n);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
sprintf(line, "*** unknown verb %d ***", (int) buff[0]);
|
sprintf(line, "*** unknown verb %d ***", (int) buff[0]);
|
||||||
}
|
}
|
||||||
|
@ -4046,6 +4046,12 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation)
|
|||||||
|
|
||||||
case RSR_field_generator_name:
|
case RSR_field_generator_name:
|
||||||
field->fld_generator_name = (const TEXT*) p;
|
field->fld_generator_name = (const TEXT*) p;
|
||||||
|
if (!field->fld_identity_type.specified)
|
||||||
|
field->fld_identity_type = IDENT_TYPE_BY_DEFAULT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RSR_field_identity_type:
|
||||||
|
field->fld_identity_type = static_cast<IdentityType>(n);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: // Shut up compiler warning
|
default: // Shut up compiler warning
|
||||||
|
@ -50,7 +50,8 @@ enum rsr_t {
|
|||||||
RSR_field_length,
|
RSR_field_length,
|
||||||
RSR_field_sub_type,
|
RSR_field_sub_type,
|
||||||
RSR_field_not_null,
|
RSR_field_not_null,
|
||||||
RSR_field_generator_name
|
RSR_field_generator_name,
|
||||||
|
RSR_field_identity_type
|
||||||
};
|
};
|
||||||
|
|
||||||
// Temporary field block
|
// Temporary field block
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
|
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
|
||||||
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
|
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
|
||||||
--
|
--
|
||||||
('2016-12-20 12:57:00', 'JRD', 0, 814)
|
('2017-02-24 22:00:00', 'JRD', 0, 818)
|
||||||
('2015-03-17 18:33:00', 'QLI', 1, 533)
|
('2015-03-17 18:33:00', 'QLI', 1, 533)
|
||||||
('2015-01-07 18:01:51', 'GFIX', 3, 134)
|
('2015-01-07 18:01:51', 'GFIX', 3, 134)
|
||||||
('1996-11-07 13:39:40', 'GPRE', 4, 1)
|
('1996-11-07 13:39:40', 'GPRE', 4, 1)
|
||||||
|
@ -921,6 +921,10 @@ Data source : @4', NULL, NULL)
|
|||||||
('att_shut_idle', NULL, 'jrd.cpp', NULL, 0, 811, NULL, 'Idle timeout expired.', NULL, NULL);
|
('att_shut_idle', NULL, 'jrd.cpp', NULL, 0, 811, NULL, 'Idle timeout expired.', NULL, NULL);
|
||||||
('att_shut_db_down', NULL, 'jrd.cpp', NULL, 0, 812, NULL, 'Database is shutdown.', NULL, NULL);
|
('att_shut_db_down', NULL, 'jrd.cpp', NULL, 0, 812, NULL, 'Database is shutdown.', NULL, NULL);
|
||||||
('att_shut_engine', NULL, 'jrd.cpp', NULL, 0, 813, NULL, 'Engine is shutdown.', NULL, NULL);
|
('att_shut_engine', NULL, 'jrd.cpp', NULL, 0, 813, NULL, 'Engine is shutdown.', NULL, NULL);
|
||||||
|
('overriding_without_identity', NULL, 'StmtNodes.cpp', NULL, 0, 814, NULL, 'OVERRIDING clause can be used only when an identity column is present in the INSERT''s field list for table/view @1', NULL, NULL);
|
||||||
|
('overriding_system_invalid', NULL, 'StmtNodes.cpp', NULL, 0, 815, NULL, 'OVERRIDING SYSTEM VALUE can be used only for identity column defined as ''GENERATED ALWAYS'' in INSERT for table/view @1', NULL, NULL);
|
||||||
|
('overriding_user_invalid', NULL, 'StmtNodes.cpp', NULL, 0, 816, NULL, 'OVERRIDING USER VALUE can be used only for identity column defined as ''GENERATED BY DEFAULT'' in INSERT for table/view @1', NULL, NULL);
|
||||||
|
('overriding_system_missing', NULL, 'StmtNodes.cpp', NULL, 0, 817, NULL, 'OVERRIDING SYSTEM VALUE should be used to override the value of an identity column defined as ''GENERATED ALWAYS'' in table/view @1', NULL, NULL);
|
||||||
-- QLI
|
-- QLI
|
||||||
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
|
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
|
||||||
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);
|
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);
|
||||||
|
@ -820,6 +820,10 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
|
|||||||
(-902, '08', '003', 0, 811, 'att_shut_idle', NULL, NULL)
|
(-902, '08', '003', 0, 811, 'att_shut_idle', NULL, NULL)
|
||||||
(-902, '08', '003', 0, 812, 'att_shut_db_down', NULL, NULL)
|
(-902, '08', '003', 0, 812, 'att_shut_db_down', NULL, NULL)
|
||||||
(-902, '08', '003', 0, 813, 'att_shut_engine', NULL, NULL)
|
(-902, '08', '003', 0, 813, 'att_shut_engine', NULL, NULL)
|
||||||
|
(-902, '42', '000', 0, 814, 'overriding_without_identity', NULL, NULL)
|
||||||
|
(-902, '42', '000', 0, 815, 'overriding_system_invalid', NULL, NULL)
|
||||||
|
(-902, '42', '000', 0, 816, 'overriding_user_invalid', NULL, NULL)
|
||||||
|
(-902, '42', '000', 0, 817, 'overriding_system_missing', NULL, NULL)
|
||||||
-- GFIX
|
-- GFIX
|
||||||
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
|
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
|
||||||
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)
|
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)
|
||||||
|
@ -344,7 +344,8 @@ static const UCHAR
|
|||||||
subfunc_decl[] = { op_subfunc_decl, 0},
|
subfunc_decl[] = { op_subfunc_decl, 0},
|
||||||
window_win[] = { op_byte, op_window_win, 0},
|
window_win[] = { op_byte, op_window_win, 0},
|
||||||
relation_field[] = { op_line, op_indent, op_byte, op_literal,
|
relation_field[] = { op_line, op_indent, op_byte, op_literal,
|
||||||
op_line, op_indent, op_byte, op_literal, op_pad, op_line, 0};
|
op_line, op_indent, op_byte, op_literal, op_pad, op_line, 0},
|
||||||
|
store3[] = { op_line, op_byte, op_line, op_verb, op_verb, op_verb, 0};
|
||||||
|
|
||||||
|
|
||||||
#include "../jrd/blp.h"
|
#include "../jrd/blp.h"
|
||||||
|
@ -309,6 +309,7 @@ static const TOK tokens[] =
|
|||||||
{TOK_OVER, "OVER", false},
|
{TOK_OVER, "OVER", false},
|
||||||
{TOK_OVERFLOW, "OVERFLOW", true},
|
{TOK_OVERFLOW, "OVERFLOW", true},
|
||||||
{TOK_OVERLAY, "OVERLAY", true},
|
{TOK_OVERLAY, "OVERLAY", true},
|
||||||
|
{TOK_OVERRIDING, "OVERRIDING", true},
|
||||||
{TOK_PACKAGE, "PACKAGE", true},
|
{TOK_PACKAGE, "PACKAGE", true},
|
||||||
{TOK_PAD, "PAD", true},
|
{TOK_PAD, "PAD", true},
|
||||||
{TOK_PAGE, "PAGE", true},
|
{TOK_PAGE, "PAGE", true},
|
||||||
|
Loading…
Reference in New Issue
Block a user