diff --git a/doc/sql.extensions/README.ddl.txt b/doc/sql.extensions/README.ddl.txt index d62e6b0b1f..15cb880d59 100644 --- a/doc/sql.extensions/README.ddl.txt +++ b/doc/sql.extensions/README.ddl.txt @@ -603,3 +603,8 @@ ALTER TABLE ... [ {ENABLE | DISABLE} PUBLICATION ] Defines whether replication is enabled for the specified table. If not specified in the CREATE TABLE statement, the database-level default behaviour is applied. + +24) Added the ability to change deterministic option without specifying the entire body of the function. +(Alexander Zhdanov) + +ALTER FUNCTION {DETERMINISTIC | NOT DETERMINISTIC} diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 454561faba..a99a2ead4d 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -1726,10 +1726,19 @@ void CreateAlterFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsql AutoSavePoint savePoint(tdbb, transaction); bool altered = false; + const bool alterIndividualParameters = !(body || external); + // first pass if (alter) { - if (executeAlter(tdbb, dsqlScratch, transaction, false, true)) + if (alterIndividualParameters) + { + if (executeAlterIndividualParameters(tdbb, dsqlScratch, transaction, false, true)) + altered = true; + else + status_exception::raise(Arg::Gds(isc_dyn_func_not_found) << Arg::Str(name)); + } + else if (executeAlter(tdbb, dsqlScratch, transaction, false, true)) { altered = true; } @@ -1746,7 +1755,12 @@ void CreateAlterFunctionNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsql 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()) { @@ -2062,6 +2076,43 @@ bool CreateAlterFunctionNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* return modified; } +bool CreateAlterFunctionNode::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_funcs2, DYN_REQUESTS); + + FOR (REQUEST_HANDLE requestHandle TRANSACTION_HANDLE transaction) + FUN IN RDB$FUNCTIONS + WITH FUN.RDB$FUNCTION_NAME EQ name.c_str() AND + FUN.RDB$PACKAGE_NAME EQUIV NULLIF(package.c_str(), '') + { + if (FUN.RDB$SYSTEM_FLAG) + { + status_exception::raise( + Arg::Gds(isc_dyn_cannot_mod_sysfunc) << MetaName(FUN.RDB$FUNCTION_NAME)); + } + + if (!secondPass && runTriggers && package.isEmpty()) + { + executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, + DDL_TRIGGER_ALTER_FUNCTION, name, NULL); + } + + MODIFY FUN + FUN.RDB$DETERMINISTIC_FLAG.NULL = FALSE; + FUN.RDB$DETERMINISTIC_FLAG = deterministic ? TRUE : FALSE; + + modifed = true; + END_MODIFY + } + END_FOR + + return modifed; +} + void CreateAlterFunctionNode::storeArgument(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, unsigned pos, bool returnArg, ParameterClause* parameter, const CollectedParameter* collectedParameter) diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index cd9c369a3f..2cdc276c25 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -455,6 +455,8 @@ 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 storeArgument(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction, unsigned pos, bool returnArg, ParameterClause* parameter, diff --git a/src/dsql/parse.y b/src/dsql/parse.y index c201fab22b..ab093aa102 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -2831,6 +2831,11 @@ function_clause : psql_function_clause | external_function_clause; +%type change_opt_function_clause +change_opt_function_clause + : change_deterministic_opt_function_clause + ; + %type psql_function_clause psql_function_clause : function_clause_start sql_security_clause_opt AS local_declarations_opt full_proc_block @@ -2859,7 +2864,7 @@ function_clause_start : symbol_UDF_name { $$ = newNode(*$1); } input_parameters(NOTRIAL(&$2->parameters)) - RETURNS domain_or_non_array_type collate_clause deterministic_opt + RETURNS domain_or_non_array_type collate_clause deterministic_clause_opt { $$ = $2; $$->returnType = newNode($5, optName($6)); @@ -2867,13 +2872,30 @@ function_clause_start } ; -%type deterministic_opt -deterministic_opt - : { $$ = false; } - | NOT DETERMINISTIC { $$ = false; } +%type change_deterministic_opt_function_clause +change_deterministic_opt_function_clause + : symbol_UDF_name + { $$ = newNode(*$1); } + deterministic_clause + { + $$ = $2; + $$->deterministic = $3; + } + ; + + +%type deterministic_clause +deterministic_clause + : NOT DETERMINISTIC { $$ = false; } | DETERMINISTIC { $$ = true; } ; +%type deterministic_clause_opt +deterministic_clause_opt + : { $$ = false; } + | deterministic_clause { $$ = $1; } + ; + %type external_clause external_clause : EXTERNAL NAME utf_string ENGINE valid_symbol_name @@ -2903,6 +2925,12 @@ alter_function_clause $$->alter = true; $$->create = false; } + | change_opt_function_clause + { + $$ = $1; + $$->alter = true; + $$->create = false; + } ; %type replace_function_clause @@ -3149,7 +3177,7 @@ local_declaration_subfunc_start $$->dsqlBlock = newNode(); } input_parameters(NOTRIAL(&$4->dsqlBlock->parameters)) - RETURNS domain_or_non_array_type collate_clause deterministic_opt + RETURNS domain_or_non_array_type collate_clause deterministic_clause_opt { $$ = $4; $$->dsqlBlock->returns.add(newNode($7, optName($8))); diff --git a/src/jrd/drq.h b/src/jrd/drq.h index 7d82ab58a1..423dd16e34 100644 --- a/src/jrd/drq.h +++ b/src/jrd/drq.h @@ -176,6 +176,7 @@ enum drq_type_t drq_s_funcs2, // store functions (CreateAlterFunctionNode) drq_s_func_args2, // store function arguments (CreateAlterFunctionNode) drq_m_funcs2, // modify functions (CreateAlterFunctionNode) + drq_m_prm_funcs2, // modify individual function parameters (CreateAlterFunctionNode) drq_e_func_args2, // erase function arguments (CreateAlterFunctionNode) drq_s_prcs2, drq_s_prms4,