8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 16:43:03 +01:00

Feature #8062 - CREATE IF NOT EXISTS. (#8072)

This commit is contained in:
Adriano dos Santos Fernandes 2024-04-14 16:32:51 -03:00 committed by GitHub
parent aaf5fafac6
commit b6eab891d5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 400 additions and 64 deletions

View File

@ -664,5 +664,43 @@ DROP USER [IF EXISTS] <user> [USING PLUGIN <plugin>]
DROP PACKAGE [IF EXISTS] <package> DROP PACKAGE [IF EXISTS] <package>
DROP PACKAGE BODY [IF EXISTS] <package> DROP PACKAGE BODY [IF EXISTS] <package>
DROP [GLOBAL] MAPPING [IF EXISTS] <mapping> DROP [GLOBAL] MAPPING [IF EXISTS] <mapping>
ALTER TABLE <table> DROP [IF EXISTS] <column> ALTER TABLE <table> DROP [IF EXISTS] <column name>
ALTER TABLE <table> DROP CONSTRAINT [IF EXISTS] <constraint> ALTER TABLE <table> DROP CONSTRAINT [IF EXISTS] <constraint name>
2) CREATE [IF NOT EXISTS]
Using subclause IF NOT EXISTS, it's now possible to try to create objects and do not get errors when they
already exists.
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.
For others commands where IF NOT EXISTS is part of the main command, 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.
It never tries to match the existing object with the one being created.
The following statements are supported:
CREATE EXCEPTION [IF NOT EXISTS] ...
CREATE INDEX [IF NOT EXISTS] ...
CREATE PROCEDURE [IF NOT EXISTS] ...
CREATE TABLE [IF NOT EXISTS] ...
CREATE TRIGGER [IF NOT EXISTS] ...
CREATE VIEW [IF NOT EXISTS] ...
CREATE FILTER [IF NOT EXISTS] ...
CREATE DOMAIN [IF NOT EXISTS] ...
CREATE FUNCTION [IF NOT EXISTS] ...
DECLARE EXTERNAL FUNCTION [IF NOT EXISTS] ...
CREATE SHADOW [IF NOT EXISTS] ...
CREATE ROLE [IF NOT EXISTS] ...
CREATE GENERATOR [IF NOT EXISTS] ...
CREATE SEQUENCE [IF NOT EXISTS] ...
CREATE COLLATION [IF NOT EXISTS] ...
CREATE USER [IF NOT EXISTS] ...
CREATE PACKAGE [IF NOT EXISTS] ...
CREATE PACKAGE BODY [IF NOT EXISTS] ...
CREATE [GLOBAL] MAPPING [IF NOT EXISTS] ...
ALTER TABLE <table> ADD [IF NOT EXISTS] <column name> ...
ALTER TABLE <table> ADD CONSTRAINT [IF NOT EXISTS] <constraint name> ...

View File

@ -220,6 +220,7 @@ public:
unsigned int op; unsigned int op;
int trustedAuth; int trustedAuth;
bool silent; bool silent;
bool createIfNotExistsOnly = false;
CharField user, pass, first, last, middle, com, attr; CharField user, pass, first, last, middle, com, attr;
IntField adm, act; IntField adm, act;
CharField database, dba, dbaPassword, role; CharField database, dba, dbaPassword, role;

View File

@ -1789,6 +1789,9 @@ 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))
return;
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
DDL_TRIGGER_CREATE_FUNCTION, name, NULL); DDL_TRIGGER_CREATE_FUNCTION, name, NULL);
@ -2804,6 +2807,9 @@ 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))
return;
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
DDL_TRIGGER_CREATE_PROCEDURE, name, NULL); DDL_TRIGGER_CREATE_PROCEDURE, name, NULL);
@ -3724,9 +3730,14 @@ void CreateAlterTriggerNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlS
void CreateAlterTriggerNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, void CreateAlterTriggerNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
jrd_tra* transaction) jrd_tra* transaction)
{ {
if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_trigger))
return;
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_TRIGGER, executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_TRIGGER,
name, NULL); name, NULL);
DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_trigger);
store(tdbb, dsqlScratch, transaction); store(tdbb, dsqlScratch, transaction);
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_TRIGGER, executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_TRIGGER,
@ -4010,9 +4021,14 @@ void CreateCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra
// run all statements under savepoint control // run all statements under savepoint control
AutoSavePoint savePoint(tdbb, transaction); AutoSavePoint savePoint(tdbb, transaction);
if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_collation))
return;
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
DDL_TRIGGER_CREATE_COLLATION, name, NULL); DDL_TRIGGER_CREATE_COLLATION, name, NULL);
DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_collation);
AutoCacheRequest request(tdbb, drq_s_colls, DYN_REQUESTS); AutoCacheRequest request(tdbb, drq_s_colls, DYN_REQUESTS);
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
@ -4400,9 +4416,14 @@ void CreateDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
// run all statements under savepoint control // run all statements under savepoint control
AutoSavePoint savePoint(tdbb, transaction); AutoSavePoint savePoint(tdbb, transaction);
if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, nameType->name, obj_field))
return;
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
DDL_TRIGGER_CREATE_DOMAIN, nameType->name, NULL); DDL_TRIGGER_CREATE_DOMAIN, nameType->name, NULL);
DYN_UTIL_check_unique_name(tdbb, transaction, nameType->name, obj_field);
storeGlobalField(tdbb, transaction, nameType->name, type); storeGlobalField(tdbb, transaction, nameType->name, type);
if (nameType->defaultClause || check || notNull) if (nameType->defaultClause || check || notNull)
@ -5539,6 +5560,9 @@ void CreateAlterExceptionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc
Attachment* const attachment = transaction->getAttachment(); Attachment* const attachment = transaction->getAttachment();
const MetaString& ownerName = attachment->getEffectiveUserName(); const MetaString& ownerName = attachment->getEffectiveUserName();
if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_exception))
return;
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
DDL_TRIGGER_CREATE_EXCEPTION, name, NULL); DDL_TRIGGER_CREATE_EXCEPTION, name, NULL);
@ -5766,9 +5790,14 @@ void CreateAlterSequenceNode::putErrorPrefix(Firebird::Arg::StatusVector& status
void CreateAlterSequenceNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, void CreateAlterSequenceNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
jrd_tra* transaction) jrd_tra* transaction)
{ {
if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_generator))
return;
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_SEQUENCE, executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_SEQUENCE,
name, NULL); name, NULL);
DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_generator);
const SINT64 val = value.value_or(1); const SINT64 val = value.value_or(1);
SLONG initialStep = 1; SLONG initialStep = 1;
if (step.has_value()) if (step.has_value())
@ -5777,6 +5806,7 @@ void CreateAlterSequenceNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch
if (initialStep == 0) if (initialStep == 0)
status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_increment) << Arg::Str(name)); status_exception::raise(Arg::Gds(isc_dyn_cant_use_zero_increment) << Arg::Str(name));
} }
store(tdbb, transaction, name, fb_sysflag_user, val, initialStep); store(tdbb, transaction, name, fb_sysflag_user, val, initialStep);
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_SEQUENCE, executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_CREATE_SEQUENCE,
@ -6398,11 +6428,25 @@ void RelationNode::defineField(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch
const ObjectsArray<MetaName>* pkCols) const ObjectsArray<MetaName>* pkCols)
{ {
dsql_fld* field = clause->field; dsql_fld* field = clause->field;
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;
dsql_rel* relation = dsqlScratch->relation;
if (relation != NULL) if (relation != NULL)
{ {
if (!(relation->rel_flags & REL_new_relation)) if (!(relation->rel_flags & REL_new_relation))
@ -6596,12 +6640,26 @@ bool RelationNode::defineDefault(thread_db* /*tdbb*/, DsqlCompilerScratch* dsqlS
} }
// Make a constraint object from a legacy node. // Make a constraint object from a legacy node.
void RelationNode::makeConstraint(thread_db* /*tdbb*/, DsqlCompilerScratch* dsqlScratch, void RelationNode::makeConstraint(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
jrd_tra* transaction, AddConstraintClause* clause, jrd_tra* transaction, AddConstraintClause* clause,
ObjectsArray<CreateDropConstraint>& constraints, bool* notNull) ObjectsArray<CreateDropConstraint>& constraints, bool* notNull)
{ {
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:
@ -7474,6 +7532,9 @@ void CreateRelationNode::checkPermission(thread_db* tdbb, jrd_tra* transaction)
void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, void CreateRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
jrd_tra* transaction) jrd_tra* transaction)
{ {
if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_relation))
return;
saveRelation(tdbb, dsqlScratch, name, false, true); saveRelation(tdbb, dsqlScratch, name, false, true);
if (externalFile) if (externalFile)
@ -8790,6 +8851,9 @@ void CreateAlterViewNode::checkPermission(thread_db* tdbb, jrd_tra* transaction)
void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
jrd_tra* transaction) jrd_tra* transaction)
{ {
if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_relation))
return;
Attachment* const attachment = transaction->tra_attachment; Attachment* const attachment = transaction->tra_attachment;
const MetaString& ownerName = attachment->getEffectiveUserName(); const MetaString& ownerName = attachment->getEffectiveUserName();
@ -9962,6 +10026,9 @@ void CreateIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch,
// run all statements under savepoint control // run all statements under savepoint control
AutoSavePoint savePoint(tdbb, transaction); AutoSavePoint savePoint(tdbb, transaction);
if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_index))
return;
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_INDEX, executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_INDEX,
name, NULL); name, NULL);
@ -10402,6 +10469,9 @@ void CreateShadowNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScrat
FIRST 1 X IN RDB$FILES FIRST 1 X IN RDB$FILES
WITH X.RDB$SHADOW_NUMBER EQ number WITH X.RDB$SHADOW_NUMBER EQ number
{ {
if (createIfNotExistsOnly)
return;
// msg 165: "Shadow %ld already exists" // msg 165: "Shadow %ld already exists"
status_exception::raise(Arg::PrivateDyn(165) << Arg::Num(number)); status_exception::raise(Arg::PrivateDyn(165) << Arg::Num(number));
} }
@ -10522,6 +10592,10 @@ void CreateAlterRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra
// run all statements under savepoint control // run all statements under savepoint control
AutoSavePoint savePoint(tdbb, transaction); AutoSavePoint savePoint(tdbb, transaction);
MetaName dummyName;
if (createIfNotExistsOnly && isItSqlRole(tdbb, transaction, name, dummyName))
return;
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
createFlag ? DDL_TRIGGER_CREATE_ROLE : DDL_TRIGGER_ALTER_ROLE, name, NULL); createFlag ? DDL_TRIGGER_CREATE_ROLE : DDL_TRIGGER_ALTER_ROLE, name, NULL);
@ -10544,7 +10618,6 @@ void CreateAlterRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra
status_exception::raise(Arg::PrivateDyn(193) << name); status_exception::raise(Arg::PrivateDyn(193) << name);
} }
MetaName dummyName;
if (createFlag && isItSqlRole(tdbb, transaction, name, dummyName)) if (createFlag && isItSqlRole(tdbb, transaction, name, dummyName))
{ {
// msg 194: "SQL role @1 already exists" // msg 194: "SQL role @1 already exists"
@ -10701,6 +10774,8 @@ void MappingNode::runInSecurityDb(SecDbContext* secDbContext)
{ {
case MAP_ADD: case MAP_ADD:
ddl = "CREATE MAPPING "; ddl = "CREATE MAPPING ";
if (createIfNotExistsOnly)
ddl += "IF NOT EXISTS ";
break; break;
case MAP_MOD: case MAP_MOD:
ddl = "ALTER MAPPING "; ddl = "ALTER MAPPING ";
@ -11014,6 +11089,8 @@ void MappingNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd
case MAP_ADD: case MAP_ADD:
if (found) if (found)
{ {
if (createIfNotExistsOnly)
return;
(Arg::Gds(isc_map_already_exists) << name).raise(); (Arg::Gds(isc_map_already_exists) << name).raise();
} }
// fall through ... // fall through ...
@ -11261,6 +11338,8 @@ void CreateAlterUserNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra
(Arg::Gds(isc_random) << "Missing user name for ALTER CURRENT USER").raise(); (Arg::Gds(isc_random) << "Missing user name for ALTER CURRENT USER").raise();
} }
userData->createIfNotExistsOnly = createIfNotExistsOnly;
Firebird::LocalStatus s; Firebird::LocalStatus s;
CheckStatusWrapper statusWrapper(&s); CheckStatusWrapper statusWrapper(&s);

View File

@ -475,6 +475,7 @@ public:
MetaName name; MetaName name;
bool create; bool create;
bool alter; bool alter;
bool createIfNotExistsOnly = false;
NestConst<ExternalClause> external; NestConst<ExternalClause> external;
Firebird::TriState deterministic; Firebird::TriState deterministic;
Firebird::Array<NestConst<ParameterClause> > parameters; Firebird::Array<NestConst<ParameterClause> > parameters;
@ -614,6 +615,7 @@ public:
MetaName name; MetaName name;
bool create; bool create;
bool alter; bool alter;
bool createIfNotExistsOnly = false;
NestConst<ExternalClause> external; NestConst<ExternalClause> external;
Firebird::Array<NestConst<ParameterClause> > parameters; Firebird::Array<NestConst<ParameterClause> > parameters;
Firebird::Array<NestConst<ParameterClause> > returns; Firebird::Array<NestConst<ParameterClause> > returns;
@ -789,6 +791,7 @@ private:
public: public:
bool create; bool create;
bool alter; bool alter;
bool createIfNotExistsOnly = false;
NestConst<LocalDeclarationsNode> localDeclList; NestConst<LocalDeclarationsNode> localDeclList;
NestConst<StmtNode> body; NestConst<StmtNode> body;
bool compiled; bool compiled;
@ -888,6 +891,7 @@ public:
MetaName fromName; MetaName fromName;
Firebird::string fromExternal; Firebird::string fromExternal;
Firebird::UCharBuffer specificAttributes; Firebird::UCharBuffer specificAttributes;
bool createIfNotExistsOnly = false;
private: private:
USHORT attributesOn; USHORT attributesOn;
@ -949,6 +953,7 @@ public:
NestConst<ParameterClause> nameType; NestConst<ParameterClause> nameType;
bool notNull; bool notNull;
NestConst<BoolSourceClause> check; NestConst<BoolSourceClause> check;
bool createIfNotExistsOnly = false;
}; };
@ -1068,6 +1073,7 @@ public:
Firebird::string message; Firebird::string message;
bool create; bool create;
bool alter; bool alter;
bool createIfNotExistsOnly = false;
}; };
@ -1152,6 +1158,7 @@ private:
public: public:
bool create; bool create;
bool alter; bool alter;
bool createIfNotExistsOnly = false;
bool legacy; bool legacy;
bool restartSpecified; bool restartSpecified;
const MetaName name; const MetaName name;
@ -1380,6 +1387,7 @@ public:
Firebird::ObjectsArray<MetaName> refColumns; Firebird::ObjectsArray<MetaName> refColumns;
NestConst<RefActionClause> refAction; NestConst<RefActionClause> refAction;
NestConst<BoolSourceClause> check; NestConst<BoolSourceClause> check;
bool createIfNotExistsOnly = false;
}; };
struct IdentityOptions struct IdentityOptions
@ -1422,6 +1430,7 @@ public:
NestConst<ValueSourceClause> computed; NestConst<ValueSourceClause> computed;
NestConst<IdentityOptions> identityOptions; NestConst<IdentityOptions> identityOptions;
bool notNullSpecified; bool notNullSpecified;
bool createIfNotExistsOnly = false;
}; };
struct AlterColNameClause : public Clause struct AlterColNameClause : public Clause
@ -1596,6 +1605,7 @@ public:
std::optional<rel_t> relationType = rel_persistent; std::optional<rel_t> relationType = rel_persistent;
bool preserveRowsOpt; bool preserveRowsOpt;
bool deleteRowsOpt; bool deleteRowsOpt;
bool createIfNotExistsOnly = false;
}; };
@ -1699,6 +1709,7 @@ private:
public: public:
bool create; bool create;
bool alter; bool alter;
bool createIfNotExistsOnly = false;
NestConst<ValueListNode> viewFields; NestConst<ValueListNode> viewFields;
NestConst<SelectExprNode> selectExpr; NestConst<SelectExprNode> selectExpr;
Firebird::string source; Firebird::string source;
@ -1783,6 +1794,7 @@ public:
NestConst<ValueListNode> columns; NestConst<ValueListNode> columns;
NestConst<ValueSourceClause> computed; NestConst<ValueSourceClause> computed;
NestConst<BoolSourceClause> partial; NestConst<BoolSourceClause> partial;
bool createIfNotExistsOnly = false;
}; };
@ -1990,6 +2002,7 @@ public:
bool manual; bool manual;
bool conditional; bool conditional;
Firebird::Array<NestConst<DbFileClause> > files; Firebird::Array<NestConst<DbFileClause> > files;
bool createIfNotExistsOnly = false;
}; };
@ -2067,7 +2080,9 @@ private:
public: public:
MetaName name; MetaName name;
bool createFlag, sysPrivDrop; bool createFlag;
bool sysPrivDrop;
bool createIfNotExistsOnly = false;
void addPrivilege(const MetaName* privName) void addPrivilege(const MetaName* privName)
{ {
@ -2127,6 +2142,7 @@ public:
bool global = false; bool global = false;
bool role = false; bool role = false;
bool silentDrop = false; bool silentDrop = false;
bool createIfNotExistsOnly = false;
}; };
@ -2226,6 +2242,7 @@ public:
Firebird::TriState adminRole; Firebird::TriState adminRole;
Firebird::TriState active; Firebird::TriState active;
Mode mode; Mode mode;
bool createIfNotExistsOnly = false;
void addProperty(MetaName* pr, Firebird::string* val = NULL) void addProperty(MetaName* pr, Firebird::string* val = NULL)
{ {

View File

@ -27,6 +27,7 @@
#include "../jrd/jrd.h" #include "../jrd/jrd.h"
#include "../jrd/tra.h" #include "../jrd/tra.h"
#include "../jrd/dfw_proto.h" #include "../jrd/dfw_proto.h"
#include "../jrd/dyn_ut_proto.h"
#include "../jrd/exe_proto.h" #include "../jrd/exe_proto.h"
#include "../jrd/met_proto.h" #include "../jrd/met_proto.h"
#include "../jrd/vio_proto.h" #include "../jrd/vio_proto.h"
@ -363,9 +364,14 @@ void CreateAlterPackageNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch*
Attachment* const attachment = transaction->getAttachment(); Attachment* const attachment = transaction->getAttachment();
const MetaString& ownerName = attachment->getEffectiveUserName(); const MetaString& ownerName = attachment->getEffectiveUserName();
if (createIfNotExistsOnly && !DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, name, obj_package_header))
return;
executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE,
DDL_TRIGGER_CREATE_PACKAGE, name, NULL); DDL_TRIGGER_CREATE_PACKAGE, name, NULL);
DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_package_header);
AutoCacheRequest requestHandle(tdbb, drq_s_pkg, DYN_REQUESTS); AutoCacheRequest requestHandle(tdbb, drq_s_pkg, DYN_REQUESTS);
STORE (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) STORE (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction)
@ -789,6 +795,9 @@ void CreatePackageBodyNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlSc
{ {
if (!PKG.RDB$VALID_BODY_FLAG.NULL && PKG.RDB$VALID_BODY_FLAG != 0) if (!PKG.RDB$VALID_BODY_FLAG.NULL && PKG.RDB$VALID_BODY_FLAG != 0)
{ {
if (createIfNotExistsOnly)
return;
status_exception::raise( status_exception::raise(
Arg::Gds(isc_no_meta_update) << Arg::Gds(isc_no_meta_update) <<
Arg::Gds(isc_dyn_package_body_exists) << Arg::Str(name)); Arg::Gds(isc_dyn_package_body_exists) << Arg::Str(name));

View File

@ -107,6 +107,7 @@ public:
MetaName name; MetaName name;
bool create; bool create;
bool alter; bool alter;
bool createIfNotExistsOnly = false;
Firebird::string source; Firebird::string source;
Firebird::Array<Item>* items; Firebird::Array<Item>* items;
Firebird::SortedArray<MetaName> functionNames; Firebird::SortedArray<MetaName> functionNames;
@ -179,6 +180,7 @@ public:
Firebird::string source; Firebird::string source;
Firebird::Array<CreateAlterPackageNode::Item>* declaredItems; Firebird::Array<CreateAlterPackageNode::Item>* declaredItems;
Firebird::Array<CreateAlterPackageNode::Item>* items; Firebird::Array<CreateAlterPackageNode::Item>* items;
bool createIfNotExistsOnly = false;
private: private:
Firebird::string owner; Firebird::string owner;

View File

@ -1 +1 @@
94 shift/reduce conflicts, 22 reduce/reduce conflicts. 115 shift/reduce conflicts, 22 reduce/reduce conflicts.

View File

@ -822,6 +822,7 @@ using namespace Firebird;
Jrd::ValueSourceClause* valueSourceClause; Jrd::ValueSourceClause* valueSourceClause;
Jrd::RelationNode* relationNode; Jrd::RelationNode* relationNode;
Jrd::RelationNode::AddColumnClause* addColumnClause; Jrd::RelationNode::AddColumnClause* addColumnClause;
Jrd::RelationNode::AddConstraintClause* addConstraintClause;
Jrd::RelationNode::RefActionClause* refActionClause; Jrd::RelationNode::RefActionClause* refActionClause;
Jrd::RelationNode::IndexConstraintClause* indexConstraintClause; Jrd::RelationNode::IndexConstraintClause* indexConstraintClause;
Jrd::RelationNode::IdentityOptions* identityOptions; Jrd::RelationNode::IdentityOptions* identityOptions;
@ -1406,7 +1407,12 @@ declare
%type <ddlNode> declare_clause %type <ddlNode> declare_clause
declare_clause declare_clause
: FILTER filter_decl_clause { $$ = $2; } : FILTER filter_decl_clause { $$ = $2; }
| EXTERNAL FUNCTION udf_decl_clause { $$ = $3; } | EXTERNAL FUNCTION if_not_exists_opt udf_decl_clause
{
const auto node = $4;
node->createIfNotExistsOnly = $3;
$$ = node;
}
; ;
%type <createAlterFunctionNode> udf_decl_clause %type <createAlterFunctionNode> udf_decl_clause
@ -1534,37 +1540,129 @@ create
%type <ddlNode> create_clause %type <ddlNode> create_clause
create_clause create_clause
: EXCEPTION exception_clause { $$ = $2; } : EXCEPTION if_not_exists_opt exception_clause
| unique_opt order_direction INDEX symbol_index_name ON simple_table_name {
const auto node = $3;
node->createIfNotExistsOnly = $2;
$$ = node;
}
| unique_opt order_direction INDEX if_not_exists_opt symbol_index_name ON simple_table_name
{ {
CreateIndexNode* node = newNode<CreateIndexNode>(*$4); const auto node = newNode<CreateIndexNode>(*$5);
node->unique = $1; node->unique = $1;
node->descending = $2; node->descending = $2;
node->relation = $6; node->createIfNotExistsOnly = $4;
node->relation = $7;
$$ = node; $$ = node;
} }
index_definition(static_cast<CreateIndexNode*>($7)) index_definition(static_cast<CreateIndexNode*>($8))
{ {
$$ = $7; $$ = $8;
} }
| FUNCTION function_clause { $$ = $2; } | FUNCTION if_not_exists_opt function_clause
| PROCEDURE procedure_clause { $$ = $2; } {
| TABLE table_clause { $$ = $2; } const auto node = $3;
| GLOBAL TEMPORARY TABLE gtt_table_clause { $$ = $4; } node->createIfNotExistsOnly = $2;
| TRIGGER trigger_clause { $$ = $2; } $$ = node;
| VIEW view_clause { $$ = $2; } }
| GENERATOR generator_clause { $$ = $2; } | PROCEDURE if_not_exists_opt procedure_clause
| SEQUENCE generator_clause { $$ = $2; } {
const auto node = $3;
node->createIfNotExistsOnly = $2;
$$ = node;
}
| TABLE if_not_exists_opt table_clause
{
const auto node = $3;
node->createIfNotExistsOnly = $2;
$$ = node;
}
| GLOBAL TEMPORARY TABLE if_not_exists_opt gtt_table_clause
{
const auto node = $5;
node->createIfNotExistsOnly = $4;
$$ = node;
}
| TRIGGER if_not_exists_opt trigger_clause
{
const auto node = $3;
node->createIfNotExistsOnly = $2;
$$ = node;
}
| VIEW if_not_exists_opt view_clause
{
const auto node = $3;
node->createIfNotExistsOnly = $2;
$$ = node;
}
| GENERATOR if_not_exists_opt generator_clause
{
const auto node = $3;
node->createIfNotExistsOnly = $2;
$$ = node;
}
| SEQUENCE if_not_exists_opt generator_clause
{
const auto node = $3;
node->createIfNotExistsOnly = $2;
$$ = node;
}
| DATABASE db_clause { $$ = $2; } | DATABASE db_clause { $$ = $2; }
| DOMAIN domain_clause { $$ = $2; } | DOMAIN if_not_exists_opt domain_clause
| SHADOW shadow_clause { $$ = $2; } {
| ROLE role_clause { $2->createFlag = true; $$ = $2; } const auto node = $3;
| COLLATION collation_clause { $$ = $2; } node->createIfNotExistsOnly = $2;
| USER create_user_clause { $$ = $2; } $$ = node;
| PACKAGE package_clause { $$ = $2; } }
| PACKAGE BODY package_body_clause { $$ = $3; } | SHADOW if_not_exists_opt shadow_clause
| MAPPING create_map_clause(false) { $$ = $2; } {
| GLOBAL MAPPING create_map_clause(true) { $$ = $3; } const auto node = $3;
node->createIfNotExistsOnly = $2;
$$ = node;
}
| ROLE if_not_exists_opt role_clause
{
const auto node = $3;
node->createIfNotExistsOnly = $2;
node->createFlag = true;
$$ = node;
}
| COLLATION if_not_exists_opt collation_clause
{
const auto node = $3;
node->createIfNotExistsOnly = $2;
$$ = node;
}
| USER if_not_exists_opt create_user_clause
{
const auto node = $3;
node->createIfNotExistsOnly = $2;
$$ = node;
}
| PACKAGE if_not_exists_opt package_clause
{
const auto node = $3;
node->createIfNotExistsOnly = $2;
$$ = node;
}
| PACKAGE BODY if_not_exists_opt package_body_clause
{
const auto node = $4;
node->createIfNotExistsOnly = $3;
$$ = node;
}
| MAPPING if_not_exists_opt create_map_clause(false)
{
const auto node = $3;
node->createIfNotExistsOnly = $2;
$$ = node;
}
| GLOBAL MAPPING if_not_exists_opt create_map_clause(true)
{
const auto node = $4;
node->createIfNotExistsOnly = $3;
$$ = node;
}
; ;
@ -2345,7 +2443,7 @@ table_element($createRelationNode)
// column definition // column definition
%type column_def(<relationNode>) %type <addColumnClause> column_def(<relationNode>)
column_def($relationNode) column_def($relationNode)
: symbol_column_name data_type_or_domain domain_default_opt : symbol_column_name data_type_or_domain domain_default_opt
{ {
@ -2359,6 +2457,7 @@ column_def($relationNode)
column_constraint_clause(NOTRIAL($<addColumnClause>4)) collate_clause column_constraint_clause(NOTRIAL($<addColumnClause>4)) collate_clause
{ {
setCollate($2, $6); setCollate($2, $6);
$$ = $<addColumnClause>4;
} }
| symbol_column_name data_type_or_domain identity_clause | symbol_column_name data_type_or_domain identity_clause
{ {
@ -2372,6 +2471,7 @@ column_def($relationNode)
column_constraint_clause(NOTRIAL($<addColumnClause>4)) collate_clause column_constraint_clause(NOTRIAL($<addColumnClause>4)) collate_clause
{ {
setCollate($2, $6); setCollate($2, $6);
$$ = $<addColumnClause>4;
} }
| symbol_column_name non_array_type def_computed | symbol_column_name non_array_type def_computed
{ {
@ -2381,6 +2481,7 @@ column_def($relationNode)
clause->computed = $3; clause->computed = $3;
$relationNode->clauses.add(clause); $relationNode->clauses.add(clause);
clause->field->flags |= FLD_computed; clause->field->flags |= FLD_computed;
$$ = clause;
} }
| symbol_column_name def_computed | symbol_column_name def_computed
{ {
@ -2390,6 +2491,7 @@ column_def($relationNode)
clause->computed = $2; clause->computed = $2;
$relationNode->clauses.add(clause); $relationNode->clauses.add(clause);
clause->field->flags |= FLD_computed; clause->field->flags |= FLD_computed;
$$ = clause;
} }
; ;
@ -2577,15 +2679,13 @@ column_constraint($addColumnClause)
// table constraints // table constraints
%type table_constraint_definition(<relationNode>) %type <addConstraintClause> table_constraint_definition(<relationNode>)
table_constraint_definition($relationNode) table_constraint_definition($relationNode)
: constraint_name_opt table_constraint($relationNode) : constraint_name_opt table_constraint($relationNode)
{ {
if ($1) if ($1)
{ $2->name = *$1;
static_cast<RelationNode::AddConstraintClause*>( $$ = $2;
$relationNode->clauses.back().getObject())->name = *$1;
}
} }
; ;
@ -2595,7 +2695,7 @@ constraint_name_opt
| CONSTRAINT symbol_constraint_name { $$ = $2; } | CONSTRAINT symbol_constraint_name { $$ = $2; }
; ;
%type table_constraint(<relationNode>) %type <addConstraintClause> table_constraint(<relationNode>)
table_constraint($relationNode) table_constraint($relationNode)
: UNIQUE column_parens constraint_index_opt : UNIQUE column_parens constraint_index_opt
{ {
@ -2611,6 +2711,7 @@ table_constraint($relationNode)
constraint.index = $3; constraint.index = $3;
$relationNode->clauses.add(&constraint); $relationNode->clauses.add(&constraint);
$$ = &constraint;
} }
| PRIMARY KEY column_parens constraint_index_opt | PRIMARY KEY column_parens constraint_index_opt
{ {
@ -2626,6 +2727,7 @@ table_constraint($relationNode)
constraint.index = $4; constraint.index = $4;
$relationNode->clauses.add(&constraint); $relationNode->clauses.add(&constraint);
$$ = &constraint;
} }
| FOREIGN KEY column_parens REFERENCES symbol_table_name column_parens_opt | FOREIGN KEY column_parens REFERENCES symbol_table_name column_parens_opt
referential_trigger_action constraint_index_opt referential_trigger_action constraint_index_opt
@ -2654,6 +2756,7 @@ table_constraint($relationNode)
constraint.index = $8; constraint.index = $8;
$relationNode->clauses.add(&constraint); $relationNode->clauses.add(&constraint);
$$ = &constraint;
} }
| check_constraint | check_constraint
{ {
@ -2661,6 +2764,7 @@ table_constraint($relationNode)
constraint->constraintType = RelationNode::AddConstraintClause::CTYPE_CHECK; constraint->constraintType = RelationNode::AddConstraintClause::CTYPE_CHECK;
constraint->check = $1; constraint->check = $1;
$relationNode->clauses.add(constraint); $relationNode->clauses.add(constraint);
$$ = constraint;
} }
; ;
@ -4267,8 +4371,18 @@ alter_op($relationNode)
clause->name = *$4; clause->name = *$4;
$relationNode->clauses.add(clause); $relationNode->clauses.add(clause);
} }
| ADD column_def($relationNode) | ADD if_not_exists_opt column_def($relationNode)
| ADD table_constraint_definition($relationNode) {
const auto node = $3;
node->createIfNotExistsOnly = $2;
}
| ADD table_constraint($relationNode)
| ADD CONSTRAINT if_not_exists_opt symbol_constraint_name table_constraint($relationNode)
{
const auto node = $5;
node->name = *$4;
node->createIfNotExistsOnly = $3;
}
| col_opt alter_column_name POSITION pos_short_integer | col_opt alter_column_name POSITION pos_short_integer
{ {
RelationNode::AlterColPosClause* clause = newNode<RelationNode::AlterColPosClause>(); RelationNode::AlterColPosClause* clause = newNode<RelationNode::AlterColPosClause>();
@ -4917,6 +5031,12 @@ if_exists_opt
| IF EXISTS { $$ = true; } | IF EXISTS { $$ = true; }
; ;
%type <boolVal> if_not_exists_opt
if_not_exists_opt
: /* nothing */ { $$ = false; }
| IF NOT EXISTS { $$ = true; }
;
%type <boolVal> opt_no_file_delete %type <boolVal> opt_no_file_delete
opt_no_file_delete opt_no_file_delete
: /* nothing */ { $$ = false; } : /* nothing */ { $$ = false; }

View File

@ -299,3 +299,7 @@ FB_IMPL_MSG(DYN, 306, dyn_rel_not_exist, -901, "42", "000", "Table @1 does not e
FB_IMPL_MSG(DYN, 307, dyn_exc_not_exist, -901, "42", "000", "Exception @1 does not exist") FB_IMPL_MSG(DYN, 307, dyn_exc_not_exist, -901, "42", "000", "Exception @1 does not exist")
FB_IMPL_MSG(DYN, 308, dyn_gen_not_exist, -901, "42", "000", "Generator/Sequence @1 does not exist") FB_IMPL_MSG(DYN, 308, dyn_gen_not_exist, -901, "42", "000", "Generator/Sequence @1 does not exist")
FB_IMPL_MSG(DYN, 309, dyn_fld_not_exist, -901, "42", "000", "Field @1 of table @2 does not exist") FB_IMPL_MSG(DYN, 309, dyn_fld_not_exist, -901, "42", "000", "Field @1 of table @2 does not exist")
FB_IMPL_MSG_SYMBOL(DYN, 310, dyn_dup_trigger, "Trigger @1 already exists")
FB_IMPL_MSG_SYMBOL(DYN, 311, dyn_dup_domain, "Domain @1 already exists")
FB_IMPL_MSG_SYMBOL(DYN, 312, dyn_dup_collation, "Collation @1 already exists")
FB_IMPL_MSG_SYMBOL(DYN, 313, dyn_dup_package, "Package @1 already exists")

View File

@ -482,8 +482,13 @@ void UserManagement::execute(USHORT id)
} }
int errcode = manager->execute(&statusWrapper, command, NULL); int errcode = manager->execute(&statusWrapper, command, NULL);
if (!command->silent)
if (!command->silent &&
!(command->createIfNotExistsOnly &&
fb_utils::containsErrorCode(status.getErrors(), isc_unique_key_violation)))
{
checkSecurityResult(errcode, &status, command->userName()->get(), command->operation()); checkSecurityResult(errcode, &status, command->userName()->get(), command->operation());
}
delete commands[id]; delete commands[id];
commands[id] = NULL; commands[id] = NULL;

View File

@ -249,6 +249,12 @@ enum drq_type_t
drq_l_pub_rel_name, // lookup relation by name drq_l_pub_rel_name, // lookup relation by name
drq_l_pub_all_rels, // iterate through all user relations drq_l_pub_all_rels, // iterate through all user relations
drq_e_pub_tab_all, // erase relation from all publication drq_e_pub_tab_all, // erase relation from all publication
drq_l_trg_name, // lookup trigger name
drq_l_fld_name, // lookup field name
drq_l_coll_name, // lookup collation name
drq_l_pkg_name, // lookup package name
drq_l_rel_con, // lookup relation constraint
drq_l_rel_fld_name, // lookup relation field name
drq_MAX drq_MAX
}; };

View File

@ -37,6 +37,8 @@ void DYN_UTIL_generate_field_position(Jrd::thread_db*, const Jrd::MetaName&, SLO
void DYN_UTIL_generate_field_name(Jrd::thread_db*, TEXT*); void DYN_UTIL_generate_field_name(Jrd::thread_db*, TEXT*);
void DYN_UTIL_generate_field_name(Jrd::thread_db*, Jrd::MetaName&); void DYN_UTIL_generate_field_name(Jrd::thread_db*, Jrd::MetaName&);
void DYN_UTIL_generate_constraint_name(Jrd::thread_db*, Jrd::MetaName&); void DYN_UTIL_generate_constraint_name(Jrd::thread_db*, Jrd::MetaName&);
bool DYN_UTIL_check_unique_name_nothrow(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction,
const Jrd::MetaName& object_name, int object_type, USHORT* errorCode = nullptr);
void DYN_UTIL_check_unique_name(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction, void DYN_UTIL_check_unique_name(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction,
const Jrd::MetaName& object_name, int object_type); const Jrd::MetaName& object_name, int object_type);
SINT64 DYN_UTIL_gen_unique_id(Jrd::thread_db*, SSHORT, const char*); SINT64 DYN_UTIL_gen_unique_id(Jrd::thread_db*, SSHORT, const char*);

View File

@ -78,23 +78,16 @@ static const UCHAR gen_id_blr2[] =
blr_parameter, 0, 0, 0, blr_end, blr_end, blr_end, blr_eoc blr_parameter, 0, 0, 0, blr_end, blr_end, blr_end, blr_eoc
}; };
void DYN_UTIL_check_unique_name(thread_db* tdbb, jrd_tra* transaction, // Check if an object already exists. If yes, return false.
const MetaName& object_name, int object_type) bool DYN_UTIL_check_unique_name_nothrow(thread_db* tdbb, jrd_tra* transaction,
const MetaName& object_name, int object_type, USHORT* errorCode)
{ {
/**************************************
*
* D Y N _ U T I L _ c h e c k _ u n i q u e _ n a m e
*
**************************************
*
* Functional description
* Check if an object already exists.
* If yes then return error.
*
**************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
USHORT error_code = 0; USHORT tempErrorCode;
errorCode = errorCode ? errorCode : &tempErrorCode;
*errorCode = 0;
AutoCacheRequest request; AutoCacheRequest request;
switch (object_type) switch (object_type)
@ -106,11 +99,11 @@ void DYN_UTIL_check_unique_name(thread_db* tdbb, jrd_tra* transaction,
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
EREL IN RDB$RELATIONS WITH EREL.RDB$RELATION_NAME EQ object_name.c_str() EREL IN RDB$RELATIONS WITH EREL.RDB$RELATION_NAME EQ object_name.c_str()
{ {
error_code = 132; *errorCode = 132;
} }
END_FOR END_FOR
if (!error_code) if (!*errorCode)
{ {
request.reset(tdbb, drq_l_prc_name, DYN_REQUESTS); request.reset(tdbb, drq_l_prc_name, DYN_REQUESTS);
@ -119,7 +112,7 @@ void DYN_UTIL_check_unique_name(thread_db* tdbb, jrd_tra* transaction,
WITH EPRC.RDB$PROCEDURE_NAME EQ object_name.c_str() AND WITH EPRC.RDB$PROCEDURE_NAME EQ object_name.c_str() AND
EPRC.RDB$PACKAGE_NAME MISSING EPRC.RDB$PACKAGE_NAME MISSING
{ {
error_code = 135; *errorCode = 135;
} }
END_FOR END_FOR
} }
@ -131,7 +124,7 @@ void DYN_UTIL_check_unique_name(thread_db* tdbb, jrd_tra* transaction,
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
EIDX IN RDB$INDICES WITH EIDX.RDB$INDEX_NAME EQ object_name.c_str() EIDX IN RDB$INDICES WITH EIDX.RDB$INDEX_NAME EQ object_name.c_str()
{ {
error_code = 251; *errorCode = 251;
} }
END_FOR END_FOR
@ -143,7 +136,7 @@ void DYN_UTIL_check_unique_name(thread_db* tdbb, jrd_tra* transaction,
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
EXCP IN RDB$EXCEPTIONS WITH EXCP.RDB$EXCEPTION_NAME EQ object_name.c_str() EXCP IN RDB$EXCEPTIONS WITH EXCP.RDB$EXCEPTION_NAME EQ object_name.c_str()
{ {
error_code = 253; *errorCode = 253;
} }
END_FOR END_FOR
@ -155,7 +148,7 @@ void DYN_UTIL_check_unique_name(thread_db* tdbb, jrd_tra* transaction,
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction) FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
EGEN IN RDB$GENERATORS WITH EGEN.RDB$GENERATOR_NAME EQ object_name.c_str() EGEN IN RDB$GENERATORS WITH EGEN.RDB$GENERATOR_NAME EQ object_name.c_str()
{ {
error_code = 254; *errorCode = 254;
} }
END_FOR END_FOR
@ -169,7 +162,59 @@ void DYN_UTIL_check_unique_name(thread_db* tdbb, jrd_tra* transaction,
WITH EFUN.RDB$FUNCTION_NAME EQ object_name.c_str() AND WITH EFUN.RDB$FUNCTION_NAME EQ object_name.c_str() AND
EFUN.RDB$PACKAGE_NAME MISSING EFUN.RDB$PACKAGE_NAME MISSING
{ {
error_code = 268; *errorCode = 268;
}
END_FOR
break;
case obj_trigger:
request.reset(tdbb, drq_l_trg_name, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
TRG IN RDB$TRIGGERS
WITH TRG.RDB$TRIGGER_NAME EQ object_name.c_str()
{
*errorCode = 310;
}
END_FOR
break;
case obj_field:
request.reset(tdbb, drq_l_fld_name, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
FLD IN RDB$FIELDS
WITH FLD.RDB$FIELD_NAME EQ object_name.c_str()
{
*errorCode = 311;
}
END_FOR
break;
case obj_collation:
request.reset(tdbb, drq_l_coll_name, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
COLL IN RDB$COLLATIONS
WITH COLL.RDB$COLLATION_NAME EQ object_name.c_str()
{
*errorCode = 312;
}
END_FOR
break;
case obj_package_header:
request.reset(tdbb, drq_l_pkg_name, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
PKG IN RDB$PACKAGES
WITH PKG.RDB$PACKAGE_NAME EQ object_name.c_str()
{
*errorCode = 313;
} }
END_FOR END_FOR
@ -179,8 +224,16 @@ void DYN_UTIL_check_unique_name(thread_db* tdbb, jrd_tra* transaction,
fb_assert(false); fb_assert(false);
} }
if (error_code) return *errorCode == 0;
status_exception::raise(Arg::PrivateDyn(error_code) << object_name.c_str()); }
// Check if an object already exists. If yes, throw error.
void DYN_UTIL_check_unique_name(thread_db* tdbb, jrd_tra* transaction, const MetaName& object_name, int object_type)
{
USHORT errorCode;
if (!DYN_UTIL_check_unique_name_nothrow(tdbb, transaction, object_name, object_type, &errorCode))
status_exception::raise(Arg::PrivateDyn(errorCode) << object_name.c_str());
} }