diff --git a/doc/sql.extensions/README.ddl.txt b/doc/sql.extensions/README.ddl.txt index 8fca318c3b..020c96930c 100644 --- a/doc/sql.extensions/README.ddl.txt +++ b/doc/sql.extensions/README.ddl.txt @@ -629,3 +629,32 @@ Only users with administrator rights can use this option. (Dmitry Sibiryakov) If is used twice, an error is returned. + + +DDL enhancements in Firebird v6. +-------------------------------- + +1) DROP [IF EXISTS] + +Using subclause IF EXISTS, it's now possible to try to drop objects and do not get errors when they di not exists. + +DROP EXCEPTION [IF EXISTS] +DROP INDEX [IF EXISTS] +DROP PROCEDURE [IF EXISTS] +DROP TABLE [IF EXISTS] +DROP TRIGGER [IF EXISTS] +DROP VIEW [IF EXISTS] +DROP FILTER [IF EXISTS] +DROP DOMAIN [IF EXISTS] +DROP [EXTERNAL] FUNCTION [IF EXISTS] +DROP SHADOW [IF EXISTS] +DROP ROLE [IF EXISTS] +DROP GENERATOR [IF EXISTS] +DROP SEQUENCE [IF EXISTS] +DROP COLLATION [IF EXISTS] +DROP USER [IF EXISTS] [USING PLUGIN ] +DROP PACKAGE [IF EXISTS] +DROP PACKAGE BODY [IF EXISTS] +DROP [GLOBAL] MAPPING [IF EXISTS] +ALTER TABLE
DROP [IF EXISTS] +ALTER TABLE
DROP CONSTRAINT [IF EXISTS] diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index d156e11fe1..cdce32bb64 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -4335,7 +4335,7 @@ void DropCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_COLLATION, name, NULL); } - else + else if (!silent) status_exception::raise(Arg::Gds(isc_dyn_collation_not_found) << Arg::Str(name)); savePoint.release(); // everything is ok @@ -5406,7 +5406,7 @@ void DropDomainNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_DOMAIN, name, NULL); } - else + else if (!silent) { // msg 89: "Domain not found" status_exception::raise(Arg::PrivateDyn(89)); @@ -6236,7 +6236,7 @@ void RelationNode::FieldDefinition::store(thread_db* tdbb, jrd_tra* transaction) // done by code and system triggers. See the functional description of // deleteKeyConstraint function for detail. void RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction, - const MetaName& relationName, const MetaName& fieldName) + const MetaName& relationName, const MetaName& fieldName, bool silent) { AutoCacheRequest request(tdbb, drq_l_dep_flds, DYN_REQUESTS); bool found = false; @@ -6358,7 +6358,7 @@ void RelationNode::deleteLocalField(thread_db* tdbb, jrd_tra* transaction, } END_FOR - if (!found) + if (!found && !silent) { // msg 176: "column %s does not exist in table/view %s" status_exception::raise(Arg::PrivateDyn(176) << fieldName << relationName); @@ -7828,7 +7828,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc Arg::Gds(isc_dsql_construct_err)); } - deleteLocalField(tdbb, transaction, name, clause->name); + deleteLocalField(tdbb, transaction, name, clause->name, clause->silent); break; } @@ -7840,8 +7840,8 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc case Clause::TYPE_DROP_CONSTRAINT: { CreateDropConstraint& dropConstraint = constraints.add(); - dropConstraint.name = - static_cast(i->getObject())->name; + dropConstraint.name = static_cast(i->getObject())->name; + dropConstraint.silent = static_cast(i->getObject())->silent; break; } @@ -7933,7 +7933,7 @@ void AlterRelationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc } END_FOR - if (!found) + if (!found && !constraint->silent) { // msg 130: "CONSTRAINT %s does not exist." status_exception::raise(Arg::PrivateDyn(130) << constraint->name); @@ -9222,7 +9222,7 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra for (dsql_fld* relField = modifyingView->rel_fields; relField; relField = relField->fld_next) { if (!modifiedFields.exist(relField)) - deleteLocalField(tdbb, transaction, name, relField->fld_name); + deleteLocalField(tdbb, transaction, name, relField->fld_name, false); } } @@ -10154,7 +10154,7 @@ void DropIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, j executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_INDEX, name, NULL); } - else + else if (!silent) { // msg 48: "Index not found" status_exception::raise(Arg::PrivateDyn(48)); @@ -10283,7 +10283,7 @@ void DropFilterNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScratch } END_FOR - if (!found) + if (!found && !silent) { // msg 37: "Blob Filter %s not found" status_exception::raise(Arg::PrivateDyn(37) << name); @@ -10990,19 +10990,24 @@ void MappingNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd break; case MAP_MOD: - case MAP_DROP: case MAP_COMMENT: if (!found) (Arg::Gds(isc_map_not_exists) << name).raise(); break; + + case MAP_DROP: + if (!found && !silentDrop) + (Arg::Gds(isc_map_not_exists) << name).raise(); + break; } - fb_assert(ddlTriggerAction > 0 || op == MAP_COMMENT); + fb_assert(ddlTriggerAction > 0 || op == MAP_COMMENT || (op == MAP_DROP && silentDrop)); if (ddlTriggerAction > 0) executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, ddlTriggerAction, name, NULL); if (op != MAP_COMMENT) DFW_post_work(transaction, dfw_clear_cache, NULL, Mapping::MAPPING_CACHE); + savePoint.release(); // everything is ok } @@ -11083,7 +11088,7 @@ void DropRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jr executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_AFTER, DDL_TRIGGER_DROP_ROLE, name, NULL); } - else + else if (!silent) { // msg 155: "Role %s not found" status_exception::raise(Arg::PrivateDyn(155) << name); diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index 5338d3ca9d..b4157e6aff 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -918,6 +918,7 @@ protected: public: MetaName name; + bool silent = false; }; @@ -1025,6 +1026,7 @@ private: public: MetaName name; + bool silent = false; }; @@ -1301,6 +1303,7 @@ public: MetaName name; Firebird::AutoPtr create; + bool silent = false; }; struct Clause @@ -1484,13 +1487,13 @@ public: { explicit DropColumnClause(MemoryPool& p) : Clause(p, TYPE_DROP_COLUMN), - name(p), - cascade(false) + name(p) { } MetaName name; - bool cascade; + bool cascade = false; + bool silent = false; }; struct DropConstraintClause : public Clause @@ -1502,12 +1505,13 @@ public: } MetaName name; + bool silent = false; }; RelationNode(MemoryPool& p, RelationSourceNode* aDsqlNode); static void deleteLocalField(thread_db* tdbb, jrd_tra* transaction, - const MetaName& relationName, const MetaName& fieldName); + const MetaName& relationName, const MetaName& fieldName, bool silent); static void addToPublication(thread_db* tdbb, jrd_tra* transaction, const MetaName& tableName, const MetaName& pubTame); @@ -1858,6 +1862,7 @@ protected: public: MetaName name; + bool silent = false; }; @@ -1946,6 +1951,7 @@ protected: public: MetaName name; + bool silent = false; }; @@ -2081,16 +2087,7 @@ public: : DdlNode(p), name(p, nm), fromUtf8(p), - plugin(NULL), - db(NULL), - fromType(NULL), - from(NULL), - to(NULL), - comment(NULL), - op(o), - mode('#'), - global(false), - role(false) + op(o) { } @@ -2117,16 +2114,17 @@ private: public: MetaName name; Firebird::string fromUtf8; - MetaName* plugin; - MetaName* db; - MetaName* fromType; - IntlString* from; - MetaName* to; - Firebird::string* comment; + MetaName* plugin = nullptr; + MetaName* db = nullptr; + MetaName* fromType = nullptr; + IntlString* from = nullptr; + MetaName* to = nullptr; + Firebird::string* comment = nullptr; OP op; - char mode; // * - any source, P - plugin, M - mapping, S - any serverwide plugin - bool global; - bool role; + char mode = '#'; // * - any source, P - plugin, M - mapping, S - any serverwide plugin + bool global = false; + bool role = false; + bool silentDrop = false; }; @@ -2152,6 +2150,7 @@ protected: public: MetaName name; + bool silent = false; }; diff --git a/src/dsql/parse-conflicts.txt b/src/dsql/parse-conflicts.txt index e54f99874e..bf49686d98 100644 --- a/src/dsql/parse-conflicts.txt +++ b/src/dsql/parse-conflicts.txt @@ -1 +1 @@ -71 shift/reduce conflicts, 22 reduce/reduce conflicts. +94 shift/reduce conflicts, 22 reduce/reduce conflicts. diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 1dd6bddebb..6e3b75306a 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -4249,17 +4249,19 @@ alter_ops($relationNode) %type alter_op() alter_op($relationNode) - : DROP symbol_column_name drop_behaviour + : DROP if_exists_opt symbol_column_name drop_behaviour { RelationNode::DropColumnClause* clause = newNode(); - clause->name = *$2; - clause->cascade = $3; + clause->silent = $2; + clause->name = *$3; + clause->cascade = $4; $relationNode->clauses.add(clause); } - | DROP CONSTRAINT symbol_constraint_name + | DROP CONSTRAINT if_exists_opt symbol_constraint_name { RelationNode::DropConstraintClause* clause = newNode(); - clause->name = *$3; + clause->silent = $3; + clause->name = *$4; $relationNode->clauses.add(clause); } | ADD column_def($relationNode) @@ -4775,48 +4777,138 @@ drop %type drop_clause drop_clause - : EXCEPTION symbol_exception_name - { $$ = newNode(*$2); } - | INDEX symbol_index_name - { $$ = newNode(*$2); } - | PROCEDURE symbol_procedure_name - { $$ = newNode(*$2); } - | TABLE symbol_table_name - { $$ = newNode(*$2, false); } - | TRIGGER symbol_trigger_name - { $$ = newNode(*$2); } - | VIEW symbol_view_name - { $$ = newNode(*$2, true); } - | FILTER symbol_filter_name - { $$ = newNode(*$2); } - | DOMAIN symbol_domain_name - { $$ = newNode(*$2); } - | EXTERNAL FUNCTION symbol_UDF_name - { $$ = newNode(*$3); } - | FUNCTION symbol_UDF_name - { $$ = newNode(*$2); } - | SHADOW pos_short_integer opt_no_file_delete - { $$ = newNode($2, $3); } - | ROLE symbol_role_name - { $$ = newNode(*$2); } - | GENERATOR symbol_generator_name - { $$ = newNode(*$2); } - | SEQUENCE symbol_generator_name - { $$ = newNode(*$2); } - | COLLATION symbol_collation_name - { $$ = newNode(*$2); } - | USER symbol_user_name USING PLUGIN valid_symbol_name - { $$ = newNode(*$2, $5); } - | USER symbol_user_name - { $$ = newNode(*$2); } - | PACKAGE symbol_package_name - { $$ = newNode(*$2); } - | PACKAGE BODY symbol_package_name - { $$ = newNode(*$3); } - | MAPPING drop_map_clause(false) - { $$ = $2; } - | GLOBAL MAPPING drop_map_clause(true) - { $$ = $3; } + : EXCEPTION if_exists_opt symbol_exception_name + { + const auto node = newNode(*$3); + node->silent = $2; + $$ = node; + } + | INDEX if_exists_opt symbol_index_name + { + const auto node = newNode(*$3); + node->silent = $2; + $$ = node; + } + | PROCEDURE if_exists_opt symbol_procedure_name + { + const auto node = newNode(*$3); + node->silent = $2; + $$ = node; + } + | TABLE if_exists_opt symbol_table_name + { + const auto node = newNode(*$3, false); + node->silent = $2; + $$ = node; + } + | TRIGGER if_exists_opt symbol_trigger_name + { + const auto node = newNode(*$3); + node->silent = $2; + $$ = node; + } + | VIEW if_exists_opt symbol_view_name + { + const auto node = newNode(*$3, true); + node->silent = $2; + $$ = node; + } + | FILTER if_exists_opt symbol_filter_name + { + const auto node = newNode(*$3); + node->silent = $2; + $$ = node; + } + | DOMAIN if_exists_opt symbol_domain_name + { + const auto node = newNode(*$3); + node->silent = $2; + $$ = node; + } + | EXTERNAL FUNCTION if_exists_opt symbol_UDF_name + { + const auto node = newNode(*$4); + node->silent = $3; + $$ = node; + } + | FUNCTION if_exists_opt symbol_UDF_name + { + const auto node = newNode(*$3); + node->silent = $2; + $$ = node; + } + | SHADOW if_exists_opt pos_short_integer opt_no_file_delete + { + const auto node = newNode($3, $4); + // DROP SHADOW implicitly has IF EXISTS behavior + $$ = node; + } + | ROLE if_exists_opt symbol_role_name + { + const auto node = newNode(*$3); + node->silent = $2; + $$ = node; + } + | GENERATOR if_exists_opt symbol_generator_name + { + const auto node = newNode(*$3); + node->silent = $2; + $$ = node; + } + | SEQUENCE if_exists_opt symbol_generator_name + { + const auto node = newNode(*$3); + node->silent = $2; + $$ = node; + } + | COLLATION if_exists_opt symbol_collation_name + { + const auto node = newNode(*$3); + node->silent = $2; + $$ = node; + } + | USER if_exists_opt symbol_user_name USING PLUGIN valid_symbol_name + { + const auto node = newNode(*$3, $6); + node->silent = $2; + $$ = node; + } + | USER if_exists_opt symbol_user_name + { + const auto node = newNode(*$3); + node->silent = $2; + $$ = node; + } + | PACKAGE if_exists_opt symbol_package_name + { + const auto node = newNode(*$3); + node->silent = $2; + $$ = node; + } + | PACKAGE BODY if_exists_opt symbol_package_name + { + const auto node = newNode(*$4); + node->silent = $3; + $$ = node; + } + | MAPPING if_exists_opt drop_map_clause(false) + { + const auto node = $3; + node->silentDrop = $2; + $$ = node; + } + | GLOBAL MAPPING if_exists_opt drop_map_clause(true) + { + const auto node = $4; + node->silentDrop = $3; + $$ = node; + } + ; + +%type if_exists_opt +if_exists_opt + : /* nothing */ { $$ = false; } + | IF EXISTS { $$ = true; } ; %type opt_no_file_delete