diff --git a/doc/sql.extensions/README.ddl.txt b/doc/sql.extensions/README.ddl.txt index 1b324ddba7..16b679e109 100644 --- a/doc/sql.extensions/README.ddl.txt +++ b/doc/sql.extensions/README.ddl.txt @@ -608,3 +608,8 @@ If not specified in the CREATE TABLE statement, the database-level default behav (Alexander Zhdanov) ALTER FUNCTION [ {DETERMINISTIC | NOT DETERMINISTIC} ] [ SQL SECURITY {DEFINER | INVOKER} | DROP SQL SECURITY ] + +25) Added the ability to change sql security option without specifying the entire body of the procedure +(Alexander Zhdanov) + +ALTER PROCEDURE SQL SECURITY {DEFINER | INVOKER} | DROP SQL SECURITY diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 8c2ecb77f3..56c7484d1d 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -2711,7 +2711,7 @@ DdlNode* CreateAlterProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) returns[i]->type->resolve(dsqlScratch); // check SQL SECURITY is not set if procedure declared in package - if (package.hasData() && ssDefiner.isAssigned()) + if (package.hasData() && ssDefiner.has_value()) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-204) << Arg::Gds(isc_invalid_clause) << Arg::Str("SQL SECURITY for procedures is prohibit in packages")); @@ -2742,11 +2742,22 @@ void CreateAlterProcedureNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsq AutoSavePoint savePoint(tdbb, transaction); bool altered = false; + const bool alterIndividualParameters = (alter && !(body || external)); + // first pass - if (alter) + if (alterIndividualParameters) + { + if (executeAlterIndividualParameters(tdbb, dsqlScratch, transaction, false, true)) + altered = true; + else + status_exception::raise(Arg::Gds(isc_dyn_proc_not_found) << Arg::Str(name)); + } + else if (alter) { if (executeAlter(tdbb, dsqlScratch, transaction, false, true)) + { altered = true; + } else { if (create) // create or alter @@ -2760,7 +2771,11 @@ void CreateAlterProcedureNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsq compile(tdbb, dsqlScratch); - executeAlter(tdbb, dsqlScratch, transaction, true, false); // second pass + // second pass + if (alterIndividualParameters) + executeAlterIndividualParameters(tdbb, dsqlScratch, transaction, true, false); + else + executeAlter(tdbb, dsqlScratch, transaction, true, false); if (package.isEmpty()) { @@ -2909,10 +2924,10 @@ bool CreateAlterProcedureNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch else P.RDB$PRIVATE_FLAG.NULL = TRUE; - if (ssDefiner.isAssigned()) + if (ssDefiner.has_value()) { P.RDB$SQL_SECURITY.NULL = FALSE; - P.RDB$SQL_SECURITY = ssDefiner.asBool() ? FB_TRUE : FB_FALSE; + P.RDB$SQL_SECURITY = ssDefiner.value() == SqlSecurity::SS_DEFINER ? FB_TRUE : FB_FALSE; } else P.RDB$SQL_SECURITY.NULL = TRUE; @@ -3024,6 +3039,52 @@ bool CreateAlterProcedureNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch return modified; } +bool CreateAlterProcedureNode::executeAlterIndividualParameters(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, bool secondPass, bool runTriggers) +{ + Attachment* const attachment = transaction->getAttachment(); + + bool modifed = false; + + AutoCacheRequest requestHandle(tdbb, drq_m_prm_prcs2, DYN_REQUESTS); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + P IN RDB$PROCEDURES + WITH P.RDB$PROCEDURE_NAME EQ name.c_str() AND + P.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '') + { + if (P.RDB$SYSTEM_FLAG) + { + status_exception::raise( + Arg::Gds(isc_dyn_cannot_mod_sysproc) << + MetaName(P.RDB$PROCEDURE_NAME)); + } + + if (!secondPass && runTriggers && package.isEmpty()) + { + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, + DDL_TRIGGER_ALTER_PROCEDURE, name, NULL); + } + + MODIFY P + if (ssDefiner.has_value()) + { + if(ssDefiner.value() != SqlSecurity::SS_DROP) + { + P.RDB$SQL_SECURITY.NULL = FALSE; + P.RDB$SQL_SECURITY = ssDefiner.value() == SqlSecurity::SS_DEFINER ? FB_TRUE : FB_FALSE; + } + else + P.RDB$SQL_SECURITY.NULL = TRUE; + } + + modifed = true; + END_MODIFY + } + END_FOR + + return modifed; +} + void CreateAlterProcedureNode::storeParameter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, USHORT parameterType, unsigned pos, ParameterClause* parameter, const CollectedParameter* collectedParameter) diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index f33a76d98c..c12cbb47e2 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -600,6 +600,9 @@ private: void executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction); bool executeAlter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, bool secondPass, bool runTriggers); + bool executeAlterIndividualParameters(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, + bool secondPass, bool runTriggers); + void storeParameter(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, USHORT parameterType, unsigned pos, ParameterClause* parameter, const CollectedParameter* collectedParameter); @@ -622,7 +625,7 @@ public: MetaName packageOwner; bool privateScope; bool preserveDefaults; - TriState ssDefiner; + std::optional ssDefiner; }; diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 9eccc8045c..9178458174 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -2707,9 +2707,13 @@ procedure_clause | external_procedure_clause ; +%type change_opt_procedure_clause +change_opt_procedure_clause + ; + %type psql_procedure_clause psql_procedure_clause - : procedure_clause_start sql_security_clause_opt AS local_declarations_opt full_proc_block + : procedure_clause_start optional_sql_security_full_alter_clause AS local_declarations_opt full_proc_block { $$ = $1; $$->ssDefiner = $2; @@ -2738,6 +2742,17 @@ procedure_clause_start { $$ = $2; } ; +%type change_opt_procedure_clause +change_opt_procedure_clause + : symbol_procedure_name + { $$ = newNode(*$1); } + optional_sql_security_partial_alter_clause + { + $$ = $2; + $$->ssDefiner = $3; + } + ; + %type alter_procedure_clause alter_procedure_clause : procedure_clause @@ -2746,6 +2761,12 @@ alter_procedure_clause $$->alter = true; $$->create = false; } + | change_opt_procedure_clause + { + $$ = $1; + $$->alter = true; + $$->create = false; + } ; %type replace_procedure_clause diff --git a/src/jrd/drq.h b/src/jrd/drq.h index 423dd16e34..01622d25e9 100644 --- a/src/jrd/drq.h +++ b/src/jrd/drq.h @@ -182,6 +182,7 @@ enum drq_type_t drq_s_prms4, drq_s_prm_src2, drq_m_prcs2, + drq_m_prm_prcs2, // modify individual procedure parameters (CreateAlterProcedureNode) drq_e_prms2, drq_m_trigger2, drq_e_prcs2,