mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 16:43:03 +01:00
parent
4e80dde604
commit
003b2e0a77
@ -675,12 +675,16 @@ already exists.
|
|||||||
For ALTER TABLE ... ADD subclause, DDL triggers are not fired if there are only IF NOT EXISTS subclauses and all
|
For ALTER TABLE ... ADD subclause, DDL triggers are not fired if there are only IF NOT EXISTS subclauses and all
|
||||||
of them are related to existing columns or constraints.
|
of them are related to existing columns or constraints.
|
||||||
|
|
||||||
For others commands where IF NOT EXISTS is part of the main command, DDL triggers are not fired when the object
|
For others commands (except users currently) where IF NOT EXISTS is part of the main command,
|
||||||
already exists.
|
DDL triggers are not fired when the object already exists.
|
||||||
|
|
||||||
The engine only verifies if the name (object, column or constraint) already exists, and if yes, do nothing.
|
The engine only verifies if the name (object, column or constraint) already exists, and if yes, do nothing.
|
||||||
It never tries to match the existing object with the one being created.
|
It never tries to match the existing object with the one being created.
|
||||||
|
|
||||||
|
Some objects share the same "namespace", for example, there cannot be a table and a procedure with the same name.
|
||||||
|
In this case, if there is table XYZ and CREATE PROCEDURE IF NOT EXISTS XYZ is tried, the procedure will not be created
|
||||||
|
and no error will be raised.
|
||||||
|
|
||||||
The following statements are supported:
|
The following statements are supported:
|
||||||
|
|
||||||
CREATE EXCEPTION [IF NOT EXISTS] ...
|
CREATE EXCEPTION [IF NOT EXISTS] ...
|
||||||
|
@ -1754,8 +1754,8 @@ void CreateAlterFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsql
|
|||||||
status_exception::raise(Arg::Gds(isc_dyn_func_not_found) << Arg::Str(name));
|
status_exception::raise(Arg::Gds(isc_dyn_func_not_found) << Arg::Str(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (!executeCreate(tdbb, dsqlScratch, transaction))
|
||||||
executeCreate(tdbb, dsqlScratch, transaction);
|
return;
|
||||||
|
|
||||||
compile(tdbb, dsqlScratch);
|
compile(tdbb, dsqlScratch);
|
||||||
|
|
||||||
@ -1781,7 +1781,7 @@ void CreateAlterFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsql
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateAlterFunctionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
bool CreateAlterFunctionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
||||||
jrd_tra* transaction)
|
jrd_tra* transaction)
|
||||||
{
|
{
|
||||||
Attachment* const attachment = transaction->getAttachment();
|
Attachment* const attachment = transaction->getAttachment();
|
||||||
@ -1790,7 +1790,7 @@ void CreateAlterFunctionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch
|
|||||||
if (package.isEmpty())
|
if (package.isEmpty())
|
||||||
{
|
{
|
||||||
if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_udf))
|
if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_udf))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
|
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
|
||||||
DDL_TRIGGER_CREATE_FUNCTION, name, NULL);
|
DDL_TRIGGER_CREATE_FUNCTION, name, NULL);
|
||||||
@ -1865,6 +1865,8 @@ void CreateAlterFunctionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch
|
|||||||
storePrivileges(tdbb, transaction, name, obj_udf, EXEC_PRIVILEGES);
|
storePrivileges(tdbb, transaction, name, obj_udf, EXEC_PRIVILEGES);
|
||||||
|
|
||||||
executeAlter(tdbb, dsqlScratch, transaction, false, false);
|
executeAlter(tdbb, dsqlScratch, transaction, false, false);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CreateAlterFunctionNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
bool CreateAlterFunctionNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
||||||
@ -2772,8 +2774,8 @@ void CreateAlterProcedureNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsq
|
|||||||
status_exception::raise(Arg::Gds(isc_dyn_proc_not_found) << Arg::Str(name));
|
status_exception::raise(Arg::Gds(isc_dyn_proc_not_found) << Arg::Str(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (!executeCreate(tdbb, dsqlScratch, transaction))
|
||||||
executeCreate(tdbb, dsqlScratch, transaction);
|
return;
|
||||||
|
|
||||||
compile(tdbb, dsqlScratch);
|
compile(tdbb, dsqlScratch);
|
||||||
|
|
||||||
@ -2799,7 +2801,7 @@ void CreateAlterProcedureNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsq
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateAlterProcedureNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
bool CreateAlterProcedureNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
||||||
jrd_tra* transaction)
|
jrd_tra* transaction)
|
||||||
{
|
{
|
||||||
Attachment* const attachment = transaction->getAttachment();
|
Attachment* const attachment = transaction->getAttachment();
|
||||||
@ -2808,7 +2810,7 @@ void CreateAlterProcedureNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc
|
|||||||
if (package.isEmpty())
|
if (package.isEmpty())
|
||||||
{
|
{
|
||||||
if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_procedure))
|
if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_procedure))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
|
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
|
||||||
DDL_TRIGGER_CREATE_PROCEDURE, name, NULL);
|
DDL_TRIGGER_CREATE_PROCEDURE, name, NULL);
|
||||||
@ -2875,6 +2877,8 @@ void CreateAlterProcedureNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc
|
|||||||
storePrivileges(tdbb, transaction, name, obj_procedure, EXEC_PRIVILEGES);
|
storePrivileges(tdbb, transaction, name, obj_procedure, EXEC_PRIVILEGES);
|
||||||
|
|
||||||
executeAlter(tdbb, dsqlScratch, transaction, false, false);
|
executeAlter(tdbb, dsqlScratch, transaction, false, false);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CreateAlterProcedureNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
bool CreateAlterProcedureNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
|
||||||
@ -6430,20 +6434,6 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
|
|||||||
dsql_fld* field = clause->field;
|
dsql_fld* field = clause->field;
|
||||||
dsql_rel* relation = dsqlScratch->relation;
|
dsql_rel* relation = dsqlScratch->relation;
|
||||||
|
|
||||||
if (clause->createIfNotExistsOnly)
|
|
||||||
{
|
|
||||||
AutoCacheRequest request(tdbb, drq_l_rel_fld_name, DYN_REQUESTS);
|
|
||||||
|
|
||||||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
|
|
||||||
RFL IN RDB$RELATION_FIELDS
|
|
||||||
WITH RFL.RDB$RELATION_NAME = relation->rel_name.c_str() AND
|
|
||||||
RFL.RDB$FIELD_NAME = field->fld_name.c_str()
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
END_FOR
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the field to the relation being defined for parsing purposes.
|
// Add the field to the relation being defined for parsing purposes.
|
||||||
|
|
||||||
bool permanent = false;
|
bool permanent = false;
|
||||||
@ -6646,20 +6636,6 @@ void RelationNode::makeConstraint(thread_db* tdbb, DsqlCompilerScratch* dsqlScra
|
|||||||
{
|
{
|
||||||
MemoryPool& pool = dsqlScratch->getPool();
|
MemoryPool& pool = dsqlScratch->getPool();
|
||||||
|
|
||||||
if (clause->createIfNotExistsOnly)
|
|
||||||
{
|
|
||||||
AutoCacheRequest request(tdbb, drq_l_rel_con, DYN_REQUESTS);
|
|
||||||
|
|
||||||
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
|
|
||||||
RC IN RDB$RELATION_CONSTRAINTS
|
|
||||||
WITH RC.RDB$CONSTRAINT_NAME EQ clause->name.c_str() AND
|
|
||||||
RC.RDB$RELATION_NAME EQ name.c_str()
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
END_FOR
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (clause->constraintType)
|
switch (clause->constraintType)
|
||||||
{
|
{
|
||||||
case AddConstraintClause::CTYPE_NOT_NULL:
|
case AddConstraintClause::CTYPE_NOT_NULL:
|
||||||
@ -7754,10 +7730,33 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
|
|||||||
switch ((*i)->type)
|
switch ((*i)->type)
|
||||||
{
|
{
|
||||||
case Clause::TYPE_ADD_COLUMN:
|
case Clause::TYPE_ADD_COLUMN:
|
||||||
executeBeforeTrigger();
|
{
|
||||||
defineField(tdbb, dsqlScratch, transaction,
|
const auto addColumnClause = static_cast<AddColumnClause*>(i->getObject());
|
||||||
static_cast<AddColumnClause*>(i->getObject()), -1, NULL);
|
bool createColumn = true;
|
||||||
|
|
||||||
|
if (addColumnClause->createIfNotExistsOnly)
|
||||||
|
{
|
||||||
|
AutoCacheRequest request(tdbb, drq_l_rel_fld_name, DYN_REQUESTS);
|
||||||
|
|
||||||
|
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
|
||||||
|
RFL IN RDB$RELATION_FIELDS
|
||||||
|
WITH RFL.RDB$RELATION_NAME = relation->rel_name.c_str() AND
|
||||||
|
RFL.RDB$FIELD_NAME = addColumnClause->field->fld_name.c_str()
|
||||||
|
{
|
||||||
|
createColumn = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
END_FOR
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createColumn)
|
||||||
|
{
|
||||||
|
executeBeforeTrigger();
|
||||||
|
defineField(tdbb, dsqlScratch, transaction, addColumnClause, -1, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case Clause::TYPE_ALTER_COL_TYPE:
|
case Clause::TYPE_ALTER_COL_TYPE:
|
||||||
executeBeforeTrigger();
|
executeBeforeTrigger();
|
||||||
@ -7937,16 +7936,46 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
|
|||||||
}
|
}
|
||||||
|
|
||||||
case Clause::TYPE_ADD_CONSTRAINT:
|
case Clause::TYPE_ADD_CONSTRAINT:
|
||||||
executeBeforeTrigger();
|
|
||||||
makeConstraint(tdbb, dsqlScratch, transaction,
|
|
||||||
static_cast<AddConstraintClause*>(i->getObject()), constraints);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Clause::TYPE_DROP_CONSTRAINT:
|
case Clause::TYPE_DROP_CONSTRAINT:
|
||||||
{
|
{
|
||||||
CreateDropConstraint& dropConstraint = constraints.add();
|
const bool silent = (*i)->type == Clause::TYPE_ADD_CONSTRAINT ?
|
||||||
dropConstraint.name = static_cast<const DropConstraintClause*>(i->getObject())->name;
|
static_cast<AddConstraintClause*>(i->getObject())->createIfNotExistsOnly :
|
||||||
dropConstraint.silent = static_cast<const DropConstraintClause*>(i->getObject())->silent;
|
static_cast<DropConstraintClause*>(i->getObject())->silent;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
if (silent)
|
||||||
|
{
|
||||||
|
const auto& constraintName = (*i)->type == Clause::TYPE_ADD_CONSTRAINT ?
|
||||||
|
static_cast<AddConstraintClause*>(i->getObject())->name :
|
||||||
|
static_cast<DropConstraintClause*>(i->getObject())->name;
|
||||||
|
|
||||||
|
AutoCacheRequest request(tdbb, drq_l_rel_con, DYN_REQUESTS);
|
||||||
|
|
||||||
|
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
|
||||||
|
RC IN RDB$RELATION_CONSTRAINTS
|
||||||
|
WITH RC.RDB$CONSTRAINT_NAME EQ constraintName.c_str() AND
|
||||||
|
RC.RDB$RELATION_NAME EQ name.c_str()
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
END_FOR
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*i)->type == Clause::TYPE_ADD_CONSTRAINT && !(silent && found))
|
||||||
|
{
|
||||||
|
executeBeforeTrigger();
|
||||||
|
makeConstraint(tdbb, dsqlScratch, transaction,
|
||||||
|
static_cast<AddConstraintClause*>(i->getObject()), constraints);
|
||||||
|
}
|
||||||
|
else if ((*i)->type == Clause::TYPE_DROP_CONSTRAINT && !(silent && !found))
|
||||||
|
{
|
||||||
|
executeBeforeTrigger();
|
||||||
|
CreateDropConstraint& dropConstraint = constraints.add();
|
||||||
|
dropConstraint.name = static_cast<const DropConstraintClause*>(i->getObject())->name;
|
||||||
|
dropConstraint.silent = static_cast<const DropConstraintClause*>(i->getObject())->silent;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8038,15 +8067,11 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
|
|||||||
RC.RDB$RELATION_NAME EQ name.c_str()
|
RC.RDB$RELATION_NAME EQ name.c_str()
|
||||||
{
|
{
|
||||||
found = true;
|
found = true;
|
||||||
executeBeforeTrigger();
|
|
||||||
ERASE RC;
|
ERASE RC;
|
||||||
}
|
}
|
||||||
END_FOR
|
END_FOR
|
||||||
|
|
||||||
if (!constraint->silent && !found)
|
if (!found)
|
||||||
executeBeforeTrigger();
|
|
||||||
|
|
||||||
if (!found && !constraint->silent)
|
|
||||||
{
|
{
|
||||||
// msg 130: "CONSTRAINT %s does not exist."
|
// msg 130: "CONSTRAINT %s does not exist."
|
||||||
status_exception::raise(Arg::PrivateDyn(130) << constraint->name);
|
status_exception::raise(Arg::PrivateDyn(130) << constraint->name);
|
||||||
|
@ -459,7 +459,7 @@ private:
|
|||||||
return external && external->udfModule.hasData();
|
return external && external->udfModule.hasData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction);
|
bool executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction);
|
||||||
bool executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction,
|
bool executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction,
|
||||||
bool secondPass, bool runTriggers);
|
bool secondPass, bool runTriggers);
|
||||||
bool executeAlterIndividualParameters(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction,
|
bool executeAlterIndividualParameters(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction,
|
||||||
@ -599,7 +599,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction);
|
bool executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction);
|
||||||
bool executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction,
|
bool executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction,
|
||||||
bool secondPass, bool runTriggers);
|
bool secondPass, bool runTriggers);
|
||||||
bool executeAlterIndividualParameters(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction,
|
bool executeAlterIndividualParameters(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction,
|
||||||
|
Loading…
Reference in New Issue
Block a user