Skip to content

[FB4] An improved support of UDF SCALAR_ARRAY-arguments #7845

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: v4.0-release
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 52 additions & 7 deletions src/dsql/DdlNodes.epp
Original file line number Diff line number Diff line change
Expand Up @@ -1635,19 +1635,64 @@ DdlNode* CreateAlterFunctionNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)

StrArray names;

for (FB_SIZE_T i = 0; i < parameters.getCount(); ++i)
if (this->isUdf())
{
const ParameterClause* const parameter = parameters[i];
// Generation of UDF input argument names.
// They will be used for work with SCALAR_ARRAY-arguments.

if (names.exist(parameter->name.c_str()))
unsigned argNum = 0;

for (FB_SIZE_T i = 0; i < parameters.getCount(); ++i)
{
status_exception::raise(
Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
Arg::Gds(isc_dsql_duplicate_spec) << Arg::Str(parameter->name));
ParameterClause* const parameter = parameters[i];

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

if (this->udfReturnPos == (i + 1))
{
// It is a parameter that is marked as RETURN

fb_assert(this->returnType == nullptr); // research. it is assumed.
fb_assert(this->udfReturnPos > 0); // paranoia

fb_assert(!names.exist(parameter->name.c_str()));
continue;
}

// It is an input argument
++argNum;
parameter->name.printf("ARG%d", argNum);
fb_assert(parameter->name.hasData());

if (names.exist(parameter->name.c_str()))
{
status_exception::raise(
Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
Arg::Gds(isc_dsql_duplicate_spec) << Arg::Str(parameter->name));
}

names.add(parameter->name.c_str());
}
}
else
{
fb_assert(!this->isUdf());

for (FB_SIZE_T i = 0; i < parameters.getCount(); ++i)
{
const ParameterClause* const parameter = parameters[i];

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

if (names.exist(parameter->name.c_str()))
{
status_exception::raise(
Arg::Gds(isc_sqlerr) << Arg::Num(-901) <<
Arg::Gds(isc_dsql_duplicate_spec) << Arg::Str(parameter->name));
}

if (parameter->name.hasData()) // legacy UDFs has unnamed parameters
names.add(parameter->name.c_str());
}
}

PASS1_check_unique_fields_names(names, localDeclList);
Expand Down
49 changes: 41 additions & 8 deletions src/dsql/ExprNodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13140,21 +13140,54 @@ ValueExprNode* UdfCallNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)

unsigned pos = 0;

for (auto& arg : node->args->items)
for (auto p_nodeArg = node->args->items.begin(), e_nodeArg = node->args->items.end();
p_nodeArg != e_nodeArg;
++p_nodeArg, ++pos)
{
if (pos < node->dsqlFunction->udf_arguments.getCount())
if (node->dsqlFunction->udf_arguments.getCount() <= pos)
{
PASS1_set_parameter_type(dsqlScratch, arg,
[&] (dsc* desc) { *desc = node->dsqlFunction->udf_arguments[pos]; },
false);
// TODO: We should complain here in the future! The parameter is
// out of bounds or the function doesn't declare input params.

break;
}

auto& nodeArg = (*p_nodeArg);

if (!nodeArg)
{
continue;
}

const auto& udfArg = node->dsqlFunction->udf_arguments[pos];

PASS1_set_parameter_type(dsqlScratch, nodeArg,
[&] (dsc* desc) { *desc = udfArg.desc; },
false);

// We will provide a client with the additional information about
// the linked UDF argument of DSQL parameter with array.

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)
Comment on lines +13146 to +13156
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.

{
ParameterNode* const paramNode = nodeAs<ParameterNode>(nodeArg);
dsql_par* const parameter = paramNode->dsqlParameter;
parameter->par_rel_name = node->dsqlFunction->udf_name.identifier;
parameter->par_name = udfArg.name;

++pos;
fb_assert(!parameter->par_rel_name.isEmpty());
fb_assert(!parameter->par_name.isEmpty());
}
}

return node;
Expand Down
2 changes: 1 addition & 1 deletion src/dsql/StmtNodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1657,7 +1657,7 @@ DeclareSubFuncNode* DeclareSubFuncNode::dsqlPass(DsqlCompilerScratch* dsqlScratc
if (!implemetingForward)
{
// ASF: dsqlFunction->udf_arguments is only checked for its count for now.
dsqlFunction->udf_arguments.add(dsc());
dsqlFunction->udf_arguments.add(dsql_udf_arg(pool, dsc(), nullptr));
}

if (param->defaultClause)
Expand Down
14 changes: 13 additions & 1 deletion src/dsql/dsql.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,18 @@ enum prc_flags_vals {
PRC_subproc = 4 // Sub procedure
};

//! User defined function argument
struct dsql_udf_arg
{
dsc desc;
MetaName name;

dsql_udf_arg(MemoryPool& p, const dsc& d, const char* n)
:desc(d), name(p, n)
{
}
};

//! User defined function block
class dsql_udf : public pool_alloc<dsql_type_udf>
{
Expand All @@ -375,7 +387,7 @@ class dsql_udf : public pool_alloc<dsql_type_udf>
//USHORT udf_character_length;
USHORT udf_flags;
QualifiedName udf_name;
Firebird::Array<dsc> udf_arguments;
Firebird::Array<dsql_udf_arg> udf_arguments;
bool udf_private; // Packaged private function
SSHORT udf_def_count; // number of inputs with default values
};
Expand Down
4 changes: 2 additions & 2 deletions src/dsql/metd.epp
Original file line number Diff line number Diff line change
Expand Up @@ -790,7 +790,7 @@ dsql_udf* METD_get_function(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat
defaults++;
}

userFunc->udf_arguments.add(d);
userFunc->udf_arguments.add(dsql_udf_arg(dbb->dbb_pool, d, X.RDB$ARGUMENT_NAME));
}
}
END_FOR
Expand Down Expand Up @@ -875,7 +875,7 @@ dsql_udf* METD_get_function(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat
defaults++;
}

userFunc->udf_arguments.add(d);
userFunc->udf_arguments.add(dsql_udf_arg(dbb->dbb_pool, d, X.RDB$ARGUMENT_NAME));
}
}
}
Expand Down