Skip to content

Conversation

@dmitry-lipetsk
Copy link
Contributor

@dmitry-lipetsk dmitry-lipetsk commented Nov 14, 2023

Hello.

It is the implementation of the second solution to issue #7843.

These changes force a server to do two things:

  1. Generation of names for INPUT-arguments of UDF and saving these names in RDB$FUNCTION_ARGUMENT::RDB$ARGUMENT_NAME.

UDF

DECLARE EXTERNAL FUNCTION UDF_DUMMY4_RPN_2 smallint, integer, float, double precision RETURNS PARAMETER 2 ENTRY_POINT 'IB_UDF_abs' MODULE_NAME 'ib_udf';

Metadata

select x.RDB$ARGUMENT_POSITION, x.RDB$ARGUMENT_NAME from RDB$FUNCTION_ARGUMENTS x where x.RDB$FUNCTION_NAME='UDF_DUMMY4_RPN_2'
image
  1. Passing to client the names of UDF and SCALAR_ARRAY-argument those are linked with DSQL parameter.
DECLARE EXTERNAL FUNCTION MY_UDF__GET_DIM INTEGER BY SCALAR_ARRAY RETURNS INTEGER BY VALUE ENTRY_POINT 'fn_get_dim__i4__sa' MODULE_NAME 'lcpi.test.udf.01.dll' select MY_UDF__GET_DIM(?) from rdb$database; -- ISQL info: INPUT message field count: 1 01: sqltype: 540 ARRAY Nullable scale: 0 subtype: 0 len: 8 : name: ARG1 alias: : table: MY_UDF__GET_DIM owner: OUTPUT message field count: 1 01: sqltype: 496 LONG Nullable scale: 0 subtype: 0 len: 4 : name: MY_UDF__GET_DIM alias: MY_UDF__GET_DIM : table: owner: 

It allows client to read the information about array element (type id, subtype, scale, charset id) and create a correct array.


If this patch is OK, I will create more complex tests for it on my side before final merging.

Thanks.

It is the implementation of the second solution to issue FirebirdSQL#7843. 1. Server generates UDF argument names and saves them in RDB$ARGUMENT_NAME column. Structure of name: ARG<number of input argument>. src\dsql\DdlNodes.epp - CreateAlterFunctionNode::dsqlPass 2. Server provides client with name of UDF and SCALAR_ARRAY argument those are linked with DSQL parameter: select UDF(?) from rdb$database. work\src\dsql\ExprNodes.cpp - UdfCallNode::dsqlPass

fb_assert(!parameter->name.hasData());

if (this->returnType == NULL && this->udfReturnPos == (i + 1))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure that the condition 'this->returnType == NULL' is required here.

CreateAlterFunctionNode::dsqlPass: - we will use only udfReturnPos for detection PARAMETER that is marked as return-value - debug checks were added --- Database with different test UDFs (8246) is created without problems.
Comment on lines +13171 to +13181
if (udfArg.desc.dsc_dtype != dtype_array)
{
// It is not array and will be ignored.
}
else
if (!node->dsqlFunction->udf_name.package.isEmpty())
{
// We should complain here in the future! The parameter is
// out of bounds or the function doesn't declare input params.
// We can't provide with the exact information about package objects.
}
else
if (nodeArg->getType() == ExprNode::TYPE_PARAMETER)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want, I will move these conditions into standalone method.

@dmitry-lipetsk
Copy link
Contributor Author

Test database with generated names for UDF input-arguments. Number of UDFs - 9905.

IBP_TEST_FB40_D3.ZIP

@dmitry-lipetsk
Copy link
Contributor Author

dmitry-lipetsk commented Nov 15, 2023

SQL for check the names of argument (in IBP_TEST_FB40_D3)

/*check argument positions*/ select 'arg pos', T0.RDB$FUNCTION_NAME as FUNC, T0.RDB$ARGUMENT_NAME as ARG_NAME from RDB$FUNCTION_ARGUMENTS T0 where T0.RDB$ARGUMENT_POSITION is NULL union all /*check udf input-argument names*/ select 'udf in-arg', T1.FUNC, T1.ARG_NAME from (select count(*) N, x.RDB$FUNCTION_NAME FUNC, x.RDB$ARGUMENT_NAME ARG_NAME from RDB$FUNCTIONS f join RDB$FUNCTION_ARGUMENTS x join RDB$FUNCTION_ARGUMENTS x2 on x.RDB$FUNCTION_NAME=x2.RDB$FUNCTION_NAME and x.RDB$ARGUMENT_POSITION>=x2.RDB$ARGUMENT_POSITION and (x.RDB$PACKAGE_NAME=x2.RDB$PACKAGE_NAME or x.RDB$PACKAGE_NAME is null and x2.RDB$PACKAGE_NAME is null) on f.RDB$FUNCTION_NAME=x.RDB$FUNCTION_NAME and (f.RDB$PACKAGE_NAME=x.RDB$PACKAGE_NAME or f.RDB$PACKAGE_NAME is null and x.RDB$PACKAGE_NAME is null) where coalesce(f.RDB$RETURN_ARGUMENT,0)<>x.RDB$ARGUMENT_POSITION and coalesce(f.RDB$RETURN_ARGUMENT,0)<>x2.RDB$ARGUMENT_POSITION and f.RDB$LEGACY_FLAG=1 group by x.RDB$FUNCTION_NAME, x.RDB$ARGUMENT_POSITION, x.RDB$ARGUMENT_NAME order by x.RDB$FUNCTION_NAME, x.RDB$ARGUMENT_POSITION, x.RDB$ARGUMENT_NAME) as T1 where ('ARG'||T1.N)<>coalesce(T1.ARG_NAME,'') union all /*check stored function argument names*/ select 'sf in-arg', T2.FUNC, T2.ARG_NAME from (select x.RDB$FUNCTION_NAME FUNC, x.RDB$ARGUMENT_NAME ARG_NAME from RDB$FUNCTIONS f join RDB$FUNCTION_ARGUMENTS x on f.RDB$FUNCTION_NAME=x.RDB$FUNCTION_NAME and (f.RDB$PACKAGE_NAME=x.RDB$PACKAGE_NAME or f.RDB$PACKAGE_NAME is null and x.RDB$PACKAGE_NAME is null) where coalesce(f.RDB$RETURN_ARGUMENT,0)<>x.RDB$ARGUMENT_POSITION and f.RDB$LEGACY_FLAG=0) T2 where coalesce(T2.ARG_NAME,'')=''

Database is OK, when this query returns an empty result set.

dmitry-lipetsk added a commit to dmitry-lipetsk/firebird that referenced this pull request Nov 17, 2023
It is additional change for patch FirebirdSQL#7845. Main issue is FirebirdSQL#7843. -------- This change adds the new feature of gbak.exe - generation UDF argument names during restore. This feature works only when database with ODS 13.0 (FB4) is restored. By default this feature is disabled. -------- New gbak command line switch: GEN_UDF_ARG_NAMES. New parameter for isc_action_svc_restore: isc_spb_res_gen_udf_arg_names=21 New burp-message with code 411 - "-GEN_UDF_ARG_NAMES generate udf argument names (ODS 13.0 and older)"
dmitry-lipetsk added a commit to dmitry-lipetsk/firebird that referenced this pull request Nov 22, 2023
Common issue is FirebirdSQL#7843 It is additional changes for PR FirebirdSQL#7845. ---- This patch allows gbak to correct data in RDB$ARGUMENT_NAME column of RDB$FUNCTION_ARGUMENTS table during restore. Two mode were implemented: for upgrade and for downgrade. By default, gbak does nothing but can check some data. The mode for disable any work and checks was added, too. ### Changes in GBAK.EXE To use a new functional is needed to define in command line new switch FIX_UDF_ARG_NAMES with one of additional parameters: DO_NOTHING, GEN_IF_NULL or SET_NULL - DO_NOTHING explicitly disables any manipulations and checks. - GEN_IF_NULL generates a new name of UDF input-argument if it is NULL. This is upgrade mode and allowed only for target ODS>=13 (FB4+). When gbak generates new name, it writes about it into log. For example: >gbak:restoring function UDF_DUMMY2_RPN_1 >gbak: restoring argument for function UDF_DUMMY2_RPN_1 >gbak: restoring argument for function UDF_DUMMY2_RPN_1 >gbak: argument name ARG1 for position 2 is generated >gbak: restoring argument for function UDF_DUMMY2_RPN_1 >gbak: argument name ARG2 for position 3 is generated >gbak: restoring argument for function UDF_DUMMY2_RPN_1 >gbak: argument name ARG3 for position 4 is generated - SET_NULL sets NULL into UDF input-argument. This is downgrade mode and allowed only for target ODS 12.x (FB3). When gbak resets name, it write about it into log. For example: >gbak:restoring function UDF_DUMMY2_RPN_1 >gbak: restoring argument for function UDF_DUMMY2_RPN_1 >gbak: restoring argument for function UDF_DUMMY2_RPN_1 >gbak: argument name ARG1 for position 2 is set to NULL >gbak: restoring argument for function UDF_DUMMY2_RPN_1 >gbak: argument name ARG2 for position 3 is set to NULL >gbak: restoring argument for function UDF_DUMMY2_RPN_1 >gbak: argument name ARG3 for position 4 is set to NULL Note that gbak.exe, by fact, does not support the work with FB2.5 and earlier but can work with GBK-files those created with ones. When FIX_UDF_ARG_NAMES is used with incorrect parameter, gbak stops with the error. For example: - gbak: ERROR:FIX_UDF_ARG_NAMES mode GEN_IF_NULL is not supported for target ODS with runtime id 120 - gbak: ERROR:FIX_UDF_ARG_NAMES mode SET_NULL is not supported for target ODS with runtime id 130 ### Changes in GBAK.Service - New parameter for isc_action_svc_restore: isc_spb_res_fix_udf_arg_names=21 - The mode is passed as string: "DO_NOTHING", "GEN_IF_NULL" or "SET_NULL" Usage of isc_spb_res_fix_udf_arg_names has not been tested yet. ### Changes in source code - New internal gbak-error messages with codes 411-420 - GBAK-error messages with codes 406-410 are marked as used in FB5 ### Tests Updated gbak.exe was tested with: - backups of FB2, FB2.1, FB3 and FB4.0.4 - FB3
@dmitry-lipetsk dmitry-lipetsk changed the title [FB4] Improving the support of UDF SCALAR_ARRAY-arguments [FB4] An improved support of UDF SCALAR_ARRAY-arguments Nov 25, 2023
@dmitry-lipetsk
Copy link
Contributor Author

Hello,

I added the support of theses things in my code and made tests for them.

It is an archive with test logs and test database (without UDF dlls) -https://dropmefiles.com/dgfM4 (this link is valid within 2 weeks)

These tests check the following things:

  1. database metadata (MSSQL linked server compliance tests)
  2. types of scalar_array arguments in DSQL - select UDF(?) from rdb$database.
  3. The transfer of arrays in UDF through DSQL-parameters.

I tested all the standard types plus CSTRING.

All is OK. There are only one problem with UDF_DUMMY2_BSA__BLOB (see #7877).


I wait when you approve the PR #7870.

After that I will merge with this PR the update of GBAK

These changes in GBAK are not necessary to me but they allows to upgrade/downgrade exist databases and make this PR more clear.

I can apply changes in GBAK later (in separate PR) to reduce the number of changes.

Thanks.

The check of udfReturnPos was moved from CreateAlterFunctionNode::executeAlter in CreateAlterFunctionNode::dsqlPass.
@dmitry-lipetsk
Copy link
Contributor Author

Hello,

https://dropmefiles.com/yYJqu (this link is valid within 2 weeks)

This archive contains results of updated gbak tests

  • restore to FB4.0.5 from FB2.0-FB4.0.4 backups with different FIX_UDF_ARG_NAMES modes
  • restore to FB3
  • C++ test of restore through FB-Services

All works OK.

@dmitry-lipetsk
Copy link
Contributor Author

An additional idea about UDF-argument naming.

It might make sense to use the "RDB$ARG" format for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant