mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 17:23:03 +01:00
Allow mixed (positional, named) arguments.
This commit is contained in:
parent
e452238cec
commit
5dbd5a46ef
@ -1,12 +1,15 @@
|
||||
# Named arguments for function and procedure calling (FB 6.0)
|
||||
|
||||
Named arguments allows you to specify function and procedure arguments by their names, rather than only by their positions.
|
||||
Named arguments allows you to specify function and procedure arguments by their names, rather than only
|
||||
by their positions.
|
||||
|
||||
It is especially useful when the routine have a lot of parameters and you want to specify them in arbitrary order or not specify some of them who have default values.
|
||||
It is especially useful when the routine have a lot of parameters and you want to specify them in arbitrary
|
||||
order or not specify some of those who have default values.
|
||||
|
||||
As the positional syntax, all arguments without default values are required to be present in the call.
|
||||
|
||||
It's currently not possible to mix positional and named arguments in the same call.
|
||||
A call can use positional, named or mixed arguments. In mixed syntax, positional arguments must appear before
|
||||
named arguments.
|
||||
|
||||
## Syntax
|
||||
|
||||
@ -23,8 +26,11 @@ It's currently not possible to mix positional and named arguments in the same ca
|
||||
[RETURNING_VALUES ...]
|
||||
|
||||
<arguments> ::=
|
||||
<named arguments>
|
||||
<positional arguments>
|
||||
<positional arguments> |
|
||||
[ {<positional arguments>,} ] <named arguments>
|
||||
|
||||
<positional arguments> ::=
|
||||
<value> [ {, <value>}... ]
|
||||
|
||||
<named arguments> ::=
|
||||
<named argument> [ {, <named argument>}... ]
|
||||
@ -40,6 +46,11 @@ select function_name(parameter2 => 'Two', parameter1 => 1)
|
||||
from rdb$database
|
||||
```
|
||||
|
||||
```
|
||||
select function_name(1, parameter2 => 'Two')
|
||||
from rdb$database
|
||||
```
|
||||
|
||||
```
|
||||
execute procedure insert_customer(
|
||||
last_name => 'SCHUMACHER',
|
||||
|
@ -12976,7 +12976,7 @@ DmlNode* UdfCallNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch*
|
||||
predateCheck(node->function, "blr_invoke_function_type", "blr_invoke_function_args");
|
||||
|
||||
argCount = blrReader.getWord();
|
||||
node->args = PAR_args(tdbb, csb, argCount, (argNames ? argCount : MAX(argCount, node->function->fun_inputs)));
|
||||
node->args = PAR_args(tdbb, csb, argCount, MAX(argCount, node->function->fun_inputs));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -13013,6 +13013,14 @@ DmlNode* UdfCallNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch*
|
||||
node->args = PAR_args(tdbb, csb, argCount, node->function->fun_inputs);
|
||||
}
|
||||
|
||||
if (argNames && argNames->getCount() > argCount)
|
||||
{
|
||||
blrReader.setPos(argNamesPos);
|
||||
PAR_error(csb,
|
||||
Arg::Gds(isc_random) <<
|
||||
"blr_invoke_function_arg_names count cannot be greater than blr_invoke_function_args");
|
||||
}
|
||||
|
||||
if (!node->function)
|
||||
{
|
||||
blrReader.setPos(startPos);
|
||||
@ -13038,29 +13046,41 @@ DmlNode* UdfCallNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch*
|
||||
node->isSubRoutine = node->function->isSubRoutine();
|
||||
|
||||
Arg::StatusVector mismatchStatus;
|
||||
mismatchStatus << Arg::Gds(isc_fun_param_mismatch) << name.toString();
|
||||
const auto mismatchInitialLength = mismatchStatus.length();
|
||||
|
||||
if (!node->args)
|
||||
node->args = FB_NEW_POOL(pool) ValueListNode(pool);
|
||||
|
||||
if (argNames && argNames->getCount() != node->args->items.getCount())
|
||||
const auto positionalArgCount = argNames ? argCount - argNames->getCount() : argCount;
|
||||
auto argIt = node->args->items.begin();
|
||||
LeftPooledMap<MetaName, NestConst<ValueExprNode>> argsByName;
|
||||
|
||||
if (positionalArgCount)
|
||||
{
|
||||
blrReader.setPos(argNamesPos);
|
||||
PAR_error(csb,
|
||||
Arg::Gds(isc_random) << "blr_invoke_function_arg_names count differs from blr_invoke_function_args");
|
||||
if (argCount > node->function->fun_inputs)
|
||||
mismatchStatus << Arg::Gds(isc_wronumarg);
|
||||
|
||||
for (auto pos = 0; pos < positionalArgCount; ++pos)
|
||||
{
|
||||
if (pos < node->function->fun_inputs)
|
||||
{
|
||||
const auto& parameter = node->function->getInputFields()[pos];
|
||||
|
||||
if (argsByName.put(parameter->prm_name, *argIt))
|
||||
mismatchStatus << Arg::Gds(isc_param_multiple_assignments) << parameter->prm_name;
|
||||
}
|
||||
|
||||
++argIt;
|
||||
}
|
||||
}
|
||||
|
||||
if (argNames)
|
||||
{
|
||||
LeftPooledMap<MetaName, NestConst<ValueExprNode>> argsByName;
|
||||
auto argIt = node->args->items.begin();
|
||||
|
||||
for (const auto& argName : *argNames)
|
||||
{
|
||||
if (argsByName.put(argName, *argIt++))
|
||||
mismatchStatus << Arg::Gds(isc_param_multiple_assignments) << argName;
|
||||
}
|
||||
}
|
||||
|
||||
node->args->items.resize(node->function->getInputFields().getCount());
|
||||
argIt = node->args->items.begin();
|
||||
@ -13088,41 +13108,9 @@ DmlNode* UdfCallNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch*
|
||||
for (const auto& argPair : argsByName)
|
||||
mismatchStatus << Arg::Gds(isc_param_not_exist) << argPair.first;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check to see if the argument count matches.
|
||||
|
||||
if (argCount > node->function->fun_inputs)
|
||||
mismatchStatus << Arg::Gds(isc_wronumarg);
|
||||
else if (argCount < node->function->fun_inputs - node->function->getDefaultCount())
|
||||
{
|
||||
unsigned pos = 0;
|
||||
|
||||
for (auto& parameter : node->function->getInputFields())
|
||||
{
|
||||
if (++pos <= argCount)
|
||||
continue;
|
||||
|
||||
mismatchStatus << Arg::Gds(isc_param_no_default_not_specified) << parameter->prm_name;
|
||||
|
||||
if (pos >= node->function->fun_inputs - node->function->getDefaultCount())
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned pos = argCount; pos < node->function->getInputFields().getCount(); ++pos)
|
||||
{
|
||||
auto parameter = node->function->getInputFields()[pos];
|
||||
fb_assert(parameter->prm_default_value);
|
||||
node->args->items[pos] = CMP_clone_node(tdbb, csb, parameter->prm_default_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mismatchStatus.length() > mismatchInitialLength)
|
||||
status_exception::raise(mismatchStatus);
|
||||
if (mismatchStatus.hasData())
|
||||
status_exception::raise(Arg::Gds(isc_fun_param_mismatch) << name.toString() << mismatchStatus);
|
||||
|
||||
// CVC: I will track ufds only if a function is not being dropped.
|
||||
if (!node->function->isSubRoutine() && csb->collectingDependencies())
|
||||
@ -13589,20 +13577,31 @@ ValueExprNode* UdfCallNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
Arg::Gds(isc_random) << Arg::Str(name.toString()));
|
||||
}
|
||||
|
||||
auto argIt = node->args->items.begin();
|
||||
unsigned pos = 0;
|
||||
|
||||
while (pos < node->args->items.getCount() - (node->dsqlArgNames ? node->dsqlArgNames->getCount() : 0))
|
||||
{
|
||||
if (pos < node->dsqlFunction->udf_arguments.getCount())
|
||||
{
|
||||
PASS1_set_parameter_type(dsqlScratch, *argIt++,
|
||||
[&] (dsc* desc) { *desc = node->dsqlFunction->udf_arguments[pos].desc; },
|
||||
false);
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
|
||||
if (node->dsqlArgNames)
|
||||
{
|
||||
fb_assert(node->dsqlArgNames->getCount() == node->args->items.getCount());
|
||||
fb_assert(node->dsqlArgNames->getCount() <= node->args->items.getCount());
|
||||
|
||||
LeftPooledMap<MetaName, const dsc*> argsByName;
|
||||
|
||||
for (const auto& arg : node->dsqlFunction->udf_arguments)
|
||||
argsByName.put(arg.name, &arg.desc);
|
||||
|
||||
bool mismatchError = false;
|
||||
Arg::StatusVector mismatchStatus;
|
||||
mismatchStatus << Arg::Gds(isc_fun_param_mismatch) << Arg::Str(name.toString());
|
||||
|
||||
auto argIt = node->args->items.begin();
|
||||
|
||||
for (const auto& argName : *node->dsqlArgNames)
|
||||
{
|
||||
@ -13613,32 +13612,13 @@ ValueExprNode* UdfCallNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
false);
|
||||
}
|
||||
else
|
||||
{
|
||||
mismatchError = true;
|
||||
mismatchStatus << Arg::Gds(isc_param_not_exist) << argName;
|
||||
}
|
||||
|
||||
++argIt;
|
||||
}
|
||||
|
||||
if (mismatchError)
|
||||
status_exception::raise(mismatchStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned pos = 0;
|
||||
|
||||
for (auto& arg : node->args->items)
|
||||
{
|
||||
if (pos < node->dsqlFunction->udf_arguments.getCount())
|
||||
{
|
||||
PASS1_set_parameter_type(dsqlScratch, arg,
|
||||
[&] (dsc* desc) { *desc = node->dsqlFunction->udf_arguments[pos].desc; },
|
||||
false);
|
||||
}
|
||||
|
||||
++pos;
|
||||
}
|
||||
if (mismatchStatus.hasData())
|
||||
status_exception::raise(Arg::Gds(isc_fun_param_mismatch) << name.toString() << mismatchStatus);
|
||||
}
|
||||
|
||||
return node;
|
||||
|
@ -3003,7 +3003,7 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr
|
||||
predateCheck(node->procedure, "blr_invsel_procedure_type", "blr_invsel_procedure_in_args");
|
||||
inArgCount = blrReader.getWord();
|
||||
node->inputSources = PAR_args(tdbb, csb, inArgCount,
|
||||
(inArgNames ? inArgCount : MAX(inArgCount, node->procedure->getInputFields().getCount())));
|
||||
MAX(inArgCount, node->procedure->getInputFields().getCount()));
|
||||
break;
|
||||
|
||||
case blr_invsel_procedure_out_arg_names:
|
||||
@ -3071,6 +3071,14 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr
|
||||
break;
|
||||
}
|
||||
|
||||
if (inArgNames && inArgNames->getCount() > node->inputSources->items.getCount())
|
||||
{
|
||||
blrReader.setPos(inArgNamesPos);
|
||||
PAR_error(csb,
|
||||
Arg::Gds(isc_random) <<
|
||||
"blr_invsel_procedure_in_arg_names count cannot be greater than blr_invsel_procedure_in_args");
|
||||
}
|
||||
|
||||
if (!node->procedure)
|
||||
{
|
||||
blrReader.setPos(blrStartPos);
|
||||
@ -3092,14 +3100,6 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr
|
||||
if (!node->outputTargets)
|
||||
node->outputTargets = FB_NEW_POOL(pool) ValueListNode(pool);
|
||||
|
||||
if (inArgNames && inArgNames->getCount() != node->inputSources->items.getCount())
|
||||
{
|
||||
blrReader.setPos(inArgNamesPos);
|
||||
PAR_error(csb,
|
||||
Arg::Gds(isc_random) <<
|
||||
"blr_invsel_procedure_in_arg_names count differs from blr_invsel_procedure_in_args");
|
||||
}
|
||||
|
||||
if (outArgNames && outArgNames->getCount() != node->outputTargets->items.getCount())
|
||||
{
|
||||
blrReader.setPos(outArgNamesPos);
|
||||
@ -3125,13 +3125,9 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr
|
||||
}
|
||||
}
|
||||
|
||||
Arg::StatusVector mismatchStatus;
|
||||
mismatchStatus << Arg::Gds(isc_prcmismat) << node->procedure->getName().toString();
|
||||
const auto mismatchInitialLength = mismatchStatus.length();
|
||||
|
||||
node->inputTargets = FB_NEW_POOL(pool) ValueListNode(pool, node->procedure->getInputFields().getCount());
|
||||
|
||||
mismatchStatus << CMP_procedure_arguments(
|
||||
Arg::StatusVector mismatchStatus = CMP_procedure_arguments(
|
||||
tdbb,
|
||||
csb,
|
||||
node->procedure,
|
||||
@ -3153,8 +3149,8 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr
|
||||
node->outputSources,
|
||||
node->outputMessage);
|
||||
|
||||
if (mismatchStatus.length() > mismatchInitialLength)
|
||||
status_exception::raise(mismatchStatus);
|
||||
if (mismatchStatus.hasData())
|
||||
status_exception::raise(Arg::Gds(isc_prcmismat) << node->procedure->getName().toString() << mismatchStatus);
|
||||
|
||||
if (csb->collectingDependencies() && !node->procedure->isSubRoutine())
|
||||
{
|
||||
@ -3246,20 +3242,39 @@ ExecProcedureNode* ExecProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
|
||||
// Handle input parameters.
|
||||
|
||||
if (inputSources && inputSources->items.hasData())
|
||||
{
|
||||
auto sourceArgIt = node->inputSources->items.begin();
|
||||
const auto sourceArgEnd = node->inputSources->items.end();
|
||||
const auto positionalArgCount = node->inputSources->items.getCount() -
|
||||
(node->dsqlInputArgNames ? node->dsqlInputArgNames->getCount() : 0);
|
||||
const auto* field = procedure->prc_inputs;
|
||||
unsigned pos = 0;
|
||||
|
||||
while (pos < positionalArgCount && field && sourceArgIt != sourceArgEnd)
|
||||
{
|
||||
dsc descNode;
|
||||
DsqlDescMaker::fromField(&descNode, field);
|
||||
|
||||
PASS1_set_parameter_type(dsqlScratch, *sourceArgIt,
|
||||
[&] (dsc* desc) { *desc = descNode; },
|
||||
false);
|
||||
|
||||
field = field->fld_next;
|
||||
++pos;
|
||||
++sourceArgIt;
|
||||
}
|
||||
|
||||
if (node->dsqlInputArgNames)
|
||||
{
|
||||
fb_assert(node->dsqlInputArgNames->getCount() == node->inputSources->items.getCount());
|
||||
fb_assert(node->dsqlInputArgNames->getCount() <= node->inputSources->items.getCount());
|
||||
|
||||
LeftPooledMap<MetaName, const dsql_fld*> argsByName;
|
||||
|
||||
for (const auto* field = procedure->prc_inputs; field; field = field->fld_next)
|
||||
argsByName.put(field->fld_name, field);
|
||||
|
||||
bool mismatchError = false;
|
||||
Arg::StatusVector mismatchStatus;
|
||||
mismatchStatus << Arg::Gds(isc_prcmismat) << dsqlName.toString();
|
||||
|
||||
auto argIt = node->inputSources->items.begin();
|
||||
|
||||
for (const auto& argName : *node->dsqlInputArgNames)
|
||||
{
|
||||
@ -3268,41 +3283,18 @@ ExecProcedureNode* ExecProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch)
|
||||
dsc descNode;
|
||||
DsqlDescMaker::fromField(&descNode, *field);
|
||||
|
||||
PASS1_set_parameter_type(dsqlScratch, *argIt,
|
||||
PASS1_set_parameter_type(dsqlScratch, *sourceArgIt,
|
||||
[&] (dsc* desc) { *desc = descNode; },
|
||||
false);
|
||||
}
|
||||
else
|
||||
{
|
||||
mismatchError = true;
|
||||
mismatchStatus << Arg::Gds(isc_param_not_exist) << argName;
|
||||
|
||||
++sourceArgIt;
|
||||
}
|
||||
|
||||
++argIt;
|
||||
}
|
||||
|
||||
if (mismatchError)
|
||||
status_exception::raise(mismatchStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inputSources && inputSources->items.hasData())
|
||||
{
|
||||
// Initialize this stack variable, and make it look like a node.
|
||||
dsc descNode;
|
||||
|
||||
auto ptr = node->inputSources->items.begin();
|
||||
const auto end = node->inputSources->items.end();
|
||||
|
||||
for (const dsql_fld* field = procedure->prc_inputs; field && ptr != end; ++ptr, field = field->fld_next)
|
||||
{
|
||||
DEV_BLKCHK(field, dsql_type_fld);
|
||||
DEV_BLKCHK(*ptr, dsql_type_nod);
|
||||
DsqlDescMaker::fromField(&descNode, field);
|
||||
PASS1_set_parameter_type(dsqlScratch, *ptr,
|
||||
[&] (dsc* desc) { *desc = descNode; },
|
||||
false);
|
||||
}
|
||||
if (mismatchStatus.hasData())
|
||||
status_exception::raise(Arg::Gds(isc_prcmismat) << dsqlName.toString() << mismatchStatus);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8618,12 +8618,21 @@ argument_list_opt
|
||||
%type <namedArguments> argument_list
|
||||
argument_list
|
||||
: named_argument_list
|
||||
{ $$ = $1; }
|
||||
| value_list
|
||||
{
|
||||
$$ = newNode<NonPooledPair<ObjectsArray<MetaName>*, ValueListNode*>>();
|
||||
$$->second = $1;
|
||||
}
|
||||
| value_list ',' named_argument_list
|
||||
{
|
||||
$$ = $3;
|
||||
|
||||
for (auto item : $$->second->items)
|
||||
$1->add(item);
|
||||
|
||||
delete $$->second;
|
||||
$$->second = $1;
|
||||
}
|
||||
;
|
||||
|
||||
%type <namedArguments> named_argument_list
|
||||
|
@ -544,21 +544,38 @@ dsql_ctx* PASS1_make_context(DsqlCompilerScratch* dsqlScratch, RecordSourceNode*
|
||||
if (count)
|
||||
{
|
||||
auto inputList = context->ctx_proc_inputs;
|
||||
auto argIt = inputList->items.begin();
|
||||
const auto argEnd = inputList->items.end();
|
||||
|
||||
const auto positionalArgCount = inputList->items.getCount() -
|
||||
(procNode->dsqlInputArgNames ? procNode->dsqlInputArgNames->getCount() : 0);
|
||||
const auto* field = procedure->prc_inputs;
|
||||
unsigned pos = 0;
|
||||
|
||||
while (pos < positionalArgCount && field && argIt != argEnd)
|
||||
{
|
||||
dsc descNode;
|
||||
DsqlDescMaker::fromField(&descNode, field);
|
||||
|
||||
PASS1_set_parameter_type(dsqlScratch, *argIt,
|
||||
[&] (dsc* desc) { *desc = descNode; },
|
||||
false);
|
||||
|
||||
field = field->fld_next;
|
||||
++pos;
|
||||
++argIt;
|
||||
}
|
||||
|
||||
if (procNode->dsqlInputArgNames)
|
||||
{
|
||||
fb_assert(procNode->dsqlInputArgNames->getCount() == inputList->items.getCount());
|
||||
fb_assert(procNode->dsqlInputArgNames->getCount() <= inputList->items.getCount());
|
||||
|
||||
LeftPooledMap<MetaName, const dsql_fld*> argsByName;
|
||||
|
||||
for (const auto* field = procedure->prc_inputs; field; field = field->fld_next)
|
||||
argsByName.put(field->fld_name, field);
|
||||
|
||||
bool mismatchError = false;
|
||||
Arg::StatusVector mismatchStatus;
|
||||
mismatchStatus << Arg::Gds(isc_prcmismat) << procNode->dsqlName.toString();
|
||||
|
||||
auto argIt = inputList->items.begin();
|
||||
|
||||
for (const auto& argName : *procNode->dsqlInputArgNames)
|
||||
{
|
||||
@ -572,34 +589,13 @@ dsql_ctx* PASS1_make_context(DsqlCompilerScratch* dsqlScratch, RecordSourceNode*
|
||||
false);
|
||||
}
|
||||
else
|
||||
{
|
||||
mismatchError = true;
|
||||
mismatchStatus << Arg::Gds(isc_param_not_exist) << argName;
|
||||
}
|
||||
|
||||
++argIt;
|
||||
}
|
||||
|
||||
if (mismatchError)
|
||||
status_exception::raise(mismatchStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Initialize this stack variable, and make it look like a node
|
||||
dsc descNode;
|
||||
|
||||
auto ptr = inputList->items.begin();
|
||||
const auto end = inputList->items.end();
|
||||
|
||||
for (const dsql_fld* field = procedure->prc_inputs; ptr != end; ++ptr, field = field->fld_next)
|
||||
{
|
||||
DEV_BLKCHK(field, dsql_type_fld);
|
||||
DEV_BLKCHK(*ptr, dsql_type_nod);
|
||||
DsqlDescMaker::fromField(&descNode, field);
|
||||
PASS1_set_parameter_type(dsqlScratch, *ptr,
|
||||
[&] (dsc* desc) { *desc = descNode; },
|
||||
false);
|
||||
}
|
||||
if (mismatchStatus.hasData())
|
||||
status_exception::raise(Arg::Gds(isc_prcmismat) << procNode->dsqlName.toString() << mismatchStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -987,7 +987,7 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch
|
||||
|
||||
inArgCount = blrReader.getWord();
|
||||
node->inputSources = PAR_args(tdbb, csb, inArgCount,
|
||||
(inArgNames ? inArgCount : MAX(inArgCount, node->procedure->getInputFields().getCount())));
|
||||
MAX(inArgCount, node->procedure->getInputFields().getCount()));
|
||||
break;
|
||||
|
||||
case blr_invsel_procedure_context:
|
||||
@ -1069,6 +1069,14 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch
|
||||
fb_assert(false);
|
||||
}
|
||||
|
||||
if (inArgNames && inArgNames->getCount() > node->inputSources->items.getCount())
|
||||
{
|
||||
blrReader.setPos(inArgNamesPos);
|
||||
PAR_error(csb,
|
||||
Arg::Gds(isc_random) <<
|
||||
"blr_invsel_procedure_in_arg_names count cannot be greater than blr_invsel_procedure_in_args");
|
||||
}
|
||||
|
||||
if (!node->procedure)
|
||||
{
|
||||
blrReader.setPos(blrStartPos);
|
||||
@ -1119,21 +1127,9 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch
|
||||
if (!node->inputSources)
|
||||
node->inputSources = FB_NEW_POOL(pool) ValueListNode(pool);
|
||||
|
||||
if (inArgNames && inArgNames->getCount() != node->inputSources->items.getCount())
|
||||
{
|
||||
blrReader.setPos(inArgNamesPos);
|
||||
PAR_error(csb,
|
||||
Arg::Gds(isc_random) <<
|
||||
"blr_invsel_procedure_in_arg_names count differs from blr_invsel_procedure_in_args");
|
||||
}
|
||||
|
||||
Arg::StatusVector mismatchStatus;
|
||||
mismatchStatus << Arg::Gds(isc_prcmismat) << node->procedure->getName().toString();
|
||||
const auto mismatchInitialLength = mismatchStatus.length();
|
||||
|
||||
node->inputTargets = FB_NEW_POOL(pool) ValueListNode(pool, node->procedure->getInputFields().getCount());
|
||||
|
||||
mismatchStatus << CMP_procedure_arguments(
|
||||
Arg::StatusVector mismatchStatus= CMP_procedure_arguments(
|
||||
tdbb,
|
||||
csb,
|
||||
node->procedure,
|
||||
@ -1144,8 +1140,8 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch
|
||||
node->inputTargets,
|
||||
node->inputMessage);
|
||||
|
||||
if (mismatchStatus.length() > mismatchInitialLength)
|
||||
status_exception::raise(mismatchStatus);
|
||||
if (mismatchStatus.hasData())
|
||||
status_exception::raise(Arg::Gds(isc_prcmismat) << node->procedure->getName().toString() << mismatchStatus);
|
||||
|
||||
if (csb->collectingDependencies() && !node->procedure->isSubRoutine())
|
||||
{
|
||||
|
@ -484,9 +484,6 @@ Arg::StatusVector CMP_procedure_arguments(
|
||||
else
|
||||
targets = FB_NEW_POOL(pool) ValueListNode(pool, argCount);
|
||||
|
||||
auto sourceArgIt = sources->items.begin();
|
||||
auto targetArgIt = targets->items.begin();
|
||||
|
||||
// We have a few parameters. Get on with creating the message block
|
||||
// Outer messages map may start with 2, but they are always in the routine start.
|
||||
USHORT n = ++csb->csb_msg_number;
|
||||
@ -519,17 +516,40 @@ Arg::StatusVector CMP_procedure_arguments(
|
||||
message->format = fmtCopy;
|
||||
// --- end of fix ---
|
||||
|
||||
if (argNames)
|
||||
{
|
||||
const auto positionalArgCount = argNames ? argCount - argNames->getCount() : argCount;
|
||||
auto sourceArgIt = sources->items.begin();
|
||||
LeftPooledMap<MetaName, NestConst<ValueExprNode>> argsByName;
|
||||
|
||||
if (positionalArgCount)
|
||||
{
|
||||
if (argCount > fields.getCount())
|
||||
mismatchStatus << Arg::Gds(isc_wronumarg);
|
||||
|
||||
for (auto pos = 0; pos < positionalArgCount; ++pos)
|
||||
{
|
||||
if (pos < fields.getCount())
|
||||
{
|
||||
const auto& parameter = fields[pos];
|
||||
|
||||
if (argsByName.put(parameter->prm_name, *sourceArgIt))
|
||||
mismatchStatus << Arg::Gds(isc_param_multiple_assignments) << parameter->prm_name;
|
||||
}
|
||||
|
||||
++sourceArgIt;
|
||||
}
|
||||
}
|
||||
|
||||
if (argNames)
|
||||
{
|
||||
for (const auto& argName : *argNames)
|
||||
{
|
||||
if (argsByName.put(argName, *sourceArgIt++))
|
||||
mismatchStatus << Arg::Gds(isc_param_multiple_assignments) << argName;
|
||||
}
|
||||
}
|
||||
|
||||
sourceArgIt = sources->items.begin();
|
||||
auto targetArgIt = targets->items.begin();
|
||||
|
||||
for (auto& parameter : fields)
|
||||
{
|
||||
@ -569,40 +589,6 @@ Arg::StatusVector CMP_procedure_arguments(
|
||||
mismatchStatus << Arg::Gds(isc_param_not_exist) << argPair.first;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned i = 0; i < (isInput ? fields.getCount() : argCount); ++i)
|
||||
{
|
||||
if (isInput)
|
||||
{
|
||||
// default value for parameter
|
||||
if (i >= argCount)
|
||||
{
|
||||
auto parameter = fields[i];
|
||||
|
||||
if (parameter->prm_default_value)
|
||||
*sourceArgIt = CMP_clone_node(tdbb, csb, parameter->prm_default_value);
|
||||
}
|
||||
|
||||
++sourceArgIt;
|
||||
}
|
||||
|
||||
const auto paramNode = FB_NEW_POOL(csb->csb_pool) ParameterNode(csb->csb_pool);
|
||||
paramNode->messageNumber = message->messageNumber;
|
||||
paramNode->message = message;
|
||||
paramNode->argNumber = i * 2;
|
||||
|
||||
const auto paramFlagNode = FB_NEW_POOL(csb->csb_pool) ParameterNode(csb->csb_pool);
|
||||
paramFlagNode->messageNumber = message->messageNumber;
|
||||
paramFlagNode->message = message;
|
||||
paramFlagNode->argNumber = i * 2 + 1;
|
||||
|
||||
paramNode->argFlag = paramFlagNode;
|
||||
|
||||
*targetArgIt++ = paramNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isInput && !argNames)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user