From 7251e44e63feb405c9c22914584f3f4bcbc8cac3 Mon Sep 17 00:00:00 2001 From: "HOME5\\dmitr" Date: Sun, 26 Nov 2023 21:51:51 +0300 Subject: [PATCH 1/2] Proposal for fixing #7877 - disable an usage of SCALAR_ARRAY with BLOB datatype Additional change - the check of usage BY SCALAR_ARRAY with return parameter was moved from CreateAlterFunctionNode::executeAlter (execute stage) in CreateAlterFunctionNode::dsqlPass (prepare stage). Test with ISQL: DECLARE EXTERNAL FUNCTION UDF_DUMMY2_BSA__BLOB2 BLOB BY SCALAR_ARRAY RETURNS BLOB BY DESCRIPTOR ENTRY_POINT 'IB_UDF_abs' MODULE_NAME 'ib_udf'; Statement failed, SQLSTATE = 42000 CREATE FUNCTION UDF_DUMMY2_BSA__BLOB2 failed -SQL error code = -607 -Invalid command -BY SCALAR_ARRAY can't be used with BLOB datatype DECLARE EXTERNAL FUNCTION UDF_DUMMY2_BSA__BLOB3 integer BY SCALAR_ARRAY, BLOB BY SCALAR_ARRAY RETURNS PARAMETER 2 ENTRY_POINT 'IB_UDF_abs' MODULE_NAME 'ib_udf'; Statement failed, SQLSTATE = 42000 CREATE FUNCTION UDF_DUMMY2_BSA__BLOB3 failed -SQL error code = -607 -Invalid command -BY SCALAR_ARRAY can't be used as a return parameter --- src/dsql/DdlNodes.epp | 48 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index 8652cb7b7b7..b2fea7d5f15 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -1681,6 +1681,42 @@ DdlNode* CreateAlterFunctionNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) if (returnType && returnType->type) returnType->type->resolve(dsqlScratch); + // check UDF argument types + if (this->isUdf()) + { + for (FB_SIZE_T i = 0; i < parameters.getCount(); ++i) + { + ParameterClause* const parameter = parameters[i]; + + if (this->udfReturnPos == (i + 1)) + { + // It is a parameter that is marked as RETURN + + // We'll verify that SCALAR_ARRAY can't be used as a return type. + // The support for SCALAR_ARRAY is only for input parameters. + if (parameter->udfMechanism == FUN_scalar_array) + { + status_exception::raise( + Arg::Gds(isc_sqlerr) << Arg::Num(-607) << + Arg::Gds(isc_dsql_command_err) << + Arg::Gds(isc_random) << "BY SCALAR_ARRAY can't be used as a return parameter"); + } + continue; + } + + // It is an input argument + + if (parameter->udfMechanism == FUN_scalar_array && + parameter->type->dtype == dtype_blob) + { + status_exception::raise( + Arg::Gds(isc_sqlerr) << Arg::Num(-607) << + Arg::Gds(isc_dsql_command_err) << + Arg::Gds(isc_random) << "BY SCALAR_ARRAY can't be used with BLOB datatype"); + } + } + } + // check SQL SECURITY is not set if function declared in package if (package.hasData() && ssDefiner.specified) { @@ -1952,17 +1988,9 @@ bool CreateAlterFunctionNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* Arg::Gds(isc_dsql_udf_return_pos_err) << Arg::Num(parameters.getCount())); } - // We'll verify that SCALAR_ARRAY can't be used as a return type. // The support for SCALAR_ARRAY is only for input parameters. - - if (parameters[udfReturnPos - 1]->udfMechanism.specified && - parameters[udfReturnPos - 1]->udfMechanism.value == FUN_scalar_array) - { - status_exception::raise( - Arg::Gds(isc_sqlerr) << Arg::Num(-607) << - Arg::Gds(isc_dsql_command_err) << - Arg::Gds(isc_random) << "BY SCALAR_ARRAY can't be used as a return parameter"); - } + // It was checked in CreateAlterFunctionNode::dsqlPass + fb_assert(!(parameters[udfReturnPos - 1]->udfMechanism == FUN_scalar_array)); FUN.RDB$RETURN_ARGUMENT = (SSHORT) udfReturnPos; } From 17faf1cb4016106604670512b4c4a799fd9ec4b4 Mon Sep 17 00:00:00 2001 From: "HOME5\\dmitr" Date: Sun, 26 Nov 2023 23:42:32 +0300 Subject: [PATCH 2/2] The mistake with a check of udfReturnPos was fixed The check of udfReturnPos was moved from CreateAlterFunctionNode::executeAlter in CreateAlterFunctionNode::dsqlPass Tests: DECLARE EXTERNAL FUNCTION UDF_DUMMY2_BSA__BLOB3 integer BY SCALAR_ARRAY, BLOB BY SCALAR_ARRAY RETURNS PARAMETER 0 ENTRY_POINT 'IB_UDF_abs' MODULE_NAME 'ib_udf'; Statement failed, SQLSTATE = 42000 Dynamic SQL Error -SQL error code = -842 -Positive value expected -At line 4, column 19 DECLARE EXTERNAL FUNCTION UDF_DUMMY2_BSA__BLOB3 integer BY SCALAR_ARRAY, BLOB BY SCALAR_ARRAY RETURNS PARAMETER 3 ENTRY_POINT 'IB_UDF_abs' MODULE_NAME 'ib_udf'; Statement failed, SQLSTATE = 38000 CREATE FUNCTION UDF_DUMMY2_BSA__BLOB3 failed -SQL error code = -607 -Invalid command -External function should have return position between 1 and 2 --- src/dsql/DdlNodes.epp | 49 +++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/src/dsql/DdlNodes.epp b/src/dsql/DdlNodes.epp index b2fea7d5f15..bb018d85d65 100644 --- a/src/dsql/DdlNodes.epp +++ b/src/dsql/DdlNodes.epp @@ -1631,6 +1631,40 @@ DdlNode* CreateAlterFunctionNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { dsqlScratch->flags |= (DsqlCompilerScratch::FLAG_BLOCK | DsqlCompilerScratch::FLAG_FUNCTION); + if (this->isUdf()) + { + // check udfReturnPos + const dsql_fld* const field = this->returnType ? this->returnType->type : NULL; + + if (field) + { + // CVC: This is case of "returns [by value|reference]". + fb_assert(udfReturnPos == 0); + } + else + { + // CVC: This is case of "returns parameter " + + // see return_value in parser + fb_assert(udfReturnPos > 0); + + if (udfReturnPos < 1 || ULONG(udfReturnPos) > parameters.getCount()) + { + // CVC: We should devise new msg "position should be between 1 and #params"; + // here it is: dsql_udf_return_pos_err + + // External functions can not have more than 10 parameters + // Not strictly correct -- return position error + status_exception::raise( + Arg::Gds(isc_sqlerr) << Arg::Num(-607) << + Arg::Gds(isc_dsql_command_err) << // gds__extern_func_err + Arg::Gds(isc_dsql_udf_return_pos_err) << Arg::Num(parameters.getCount())); + } + } + + fb_assert(udfReturnPos >= 0 && ULONG(udfReturnPos) <= parameters.getCount()); + } + // check for duplicated parameters and declaration names StrArray names; @@ -1974,19 +2008,8 @@ bool CreateAlterFunctionNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* else // CVC: This is case of "returns parameter " { // Function modifies an argument whose value is the function return value. - - if (udfReturnPos < 1 || ULONG(udfReturnPos) > parameters.getCount()) - { - // CVC: We should devise new msg "position should be between 1 and #params"; - // here it is: dsql_udf_return_pos_err - - // External functions can not have more than 10 parameters - // Not strictly correct -- return position error - status_exception::raise( - Arg::Gds(isc_sqlerr) << Arg::Num(-607) << - Arg::Gds(isc_dsql_command_err) << // gds__extern_func_err - Arg::Gds(isc_dsql_udf_return_pos_err) << Arg::Num(parameters.getCount())); - } + // It was checked in CreateAlterFunctionNode::dsqlPass + fb_assert(!(udfReturnPos < 1 || ULONG(udfReturnPos) > parameters.getCount())); // The support for SCALAR_ARRAY is only for input parameters. // It was checked in CreateAlterFunctionNode::dsqlPass