From 00a50429cb366556d1409d926ebf5b77b35d16d3 Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Tue, 19 Sep 2023 07:19:19 -0300 Subject: [PATCH] Feature #7566 - Allow DEFAULT keyword in argument list. --- doc/sql.extensions/README.named_arguments.md | 14 ++++++++++++-- src/dsql/ExprNodes.cpp | 11 +++++++---- src/dsql/StmtNodes.cpp | 13 +++++-------- src/dsql/gen.cpp | 11 +++++++++++ src/dsql/gen_proto.h | 1 + src/dsql/parse.y | 6 +++--- src/include/firebird/impl/blr.h | 2 ++ src/include/firebird/impl/msg/jrd.h | 2 +- src/jrd/RecordSourceNodes.cpp | 4 ++-- src/jrd/blp.h | 1 + src/jrd/cmp.cpp | 7 +++++-- src/jrd/par.cpp | 7 ++++++- 12 files changed, 56 insertions(+), 23 deletions(-) diff --git a/doc/sql.extensions/README.named_arguments.md b/doc/sql.extensions/README.named_arguments.md index 404b208530..5ccdfac253 100644 --- a/doc/sql.extensions/README.named_arguments.md +++ b/doc/sql.extensions/README.named_arguments.md @@ -30,13 +30,18 @@ named arguments. [ {,} ] ::= - [ {, }... ] + [ {, }... ] ::= [ {, }... ] ::= - => + => + + + ::= + | + DEFAULT ``` ## Examples @@ -51,6 +56,11 @@ select function_name(1, parameter2 => 'Two') from rdb$database ``` +``` +select function_name(default, parameter2 => 'Two') + from rdb$database +``` + ``` execute procedure insert_customer( last_name => 'SCHUMACHER', diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp index 8a9b42abf1..755c57630d 100644 --- a/src/dsql/ExprNodes.cpp +++ b/src/dsql/ExprNodes.cpp @@ -13087,12 +13087,15 @@ DmlNode* UdfCallNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* for (auto& parameter : node->function->getInputFields()) { - if (const auto argValue = argsByName.get(parameter->prm_name)) + const auto argValue = argsByName.get(parameter->prm_name); + + if (argValue) { *argIt = *argValue; argsByName.remove(parameter->prm_name); } - else + + if (!argValue || !*argValue) { if (parameter->prm_default_value) *argIt = CMP_clone_node(tdbb, csb, parameter->prm_default_value); @@ -13185,7 +13188,7 @@ void UdfCallNode::genBlr(DsqlCompilerScratch* dsqlScratch) dsqlScratch->appendUShort(args->items.getCount()); for (auto& arg : args->items) - GEN_expr(dsqlScratch, arg); + GEN_arg(dsqlScratch, arg); dsqlScratch->appendUChar(blr_end); @@ -13204,7 +13207,7 @@ void UdfCallNode::genBlr(DsqlCompilerScratch* dsqlScratch) dsqlScratch->appendUChar(args->items.getCount()); for (auto& arg : args->items) - GEN_expr(dsqlScratch, arg); + GEN_arg(dsqlScratch, arg); } void UdfCallNode::make(DsqlCompilerScratch* /*dsqlScratch*/, dsc* desc) diff --git a/src/dsql/StmtNodes.cpp b/src/dsql/StmtNodes.cpp index ace0998182..b095a6e57b 100644 --- a/src/dsql/StmtNodes.cpp +++ b/src/dsql/StmtNodes.cpp @@ -3430,7 +3430,7 @@ void ExecProcedureNode::genBlr(DsqlCompilerScratch* dsqlScratch) dsqlScratch->appendUShort(inputSources->items.getCount()); for (auto& arg : inputSources->items) - GEN_expr(dsqlScratch, arg); + GEN_arg(dsqlScratch, arg); } // Output parameters. @@ -3461,11 +3461,9 @@ void ExecProcedureNode::genBlr(DsqlCompilerScratch* dsqlScratch) if (inputSources) { dsqlScratch->appendUShort(inputSources->items.getCount()); - auto ptr = inputSources->items.begin(); - const auto end = inputSources->items.end(); - while (ptr < end) - GEN_expr(dsqlScratch, *ptr++); + for (auto& arg : inputSources->items) + GEN_arg(dsqlScratch, arg); } else dsqlScratch->appendUShort(0); @@ -3474,10 +3472,9 @@ void ExecProcedureNode::genBlr(DsqlCompilerScratch* dsqlScratch) if (outputSources) { dsqlScratch->appendUShort(outputSources->items.getCount()); - auto ptr = outputSources->items.begin(); - for (const auto end = outputSources->items.end(); ptr != end; ++ptr) - GEN_expr(dsqlScratch, *ptr); + for (auto& arg : outputSources->items) + GEN_expr(dsqlScratch, arg); } else dsqlScratch->appendUShort(0); diff --git a/src/dsql/gen.cpp b/src/dsql/gen.cpp index 2ccf3f3d18..ae55f6e6d4 100644 --- a/src/dsql/gen.cpp +++ b/src/dsql/gen.cpp @@ -65,6 +65,17 @@ using namespace Firebird; static void gen_plan(DsqlCompilerScratch*, const PlanNode*); +// Generate blr for an argument. +// When it is nullptr, generate blr_default_arg. +void GEN_arg(DsqlCompilerScratch* dsqlScratch, ExprNode* node) +{ + if (node) + GEN_expr(dsqlScratch, node); + else + dsqlScratch->appendUChar(blr_default_arg); +} + + void GEN_hidden_variables(DsqlCompilerScratch* dsqlScratch) { /************************************** diff --git a/src/dsql/gen_proto.h b/src/dsql/gen_proto.h index 6301fda05d..6edf97052b 100644 --- a/src/dsql/gen_proto.h +++ b/src/dsql/gen_proto.h @@ -30,6 +30,7 @@ namespace Jrd class ValueListNode; } +void GEN_arg(Jrd::DsqlCompilerScratch*, Jrd::ExprNode*); void GEN_descriptor(Jrd::DsqlCompilerScratch* dsqlScratch, const dsc* desc, bool texttype); void GEN_expr(Jrd::DsqlCompilerScratch*, Jrd::ExprNode*); void GEN_hidden_variables(Jrd::DsqlCompilerScratch* dsqlScratch); diff --git a/src/dsql/parse.y b/src/dsql/parse.y index bf7b8aeaa7..1f4e85a811 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -8618,12 +8618,12 @@ argument_list_opt %type argument_list argument_list : named_argument_list - | value_list + | value_or_default_list { $$ = newNode*, ValueListNode*>>(); $$->second = $1; } - | value_list ',' named_argument_list + | value_or_default_list ',' named_argument_list { $$ = $3; @@ -8655,7 +8655,7 @@ named_argument_list %type named_argument named_argument - : symbol_column_name NAMED_ARG_ASSIGN value + : symbol_column_name NAMED_ARG_ASSIGN value_or_default { $$ = newNode>($1, $3); } ; diff --git a/src/include/firebird/impl/blr.h b/src/include/firebird/impl/blr.h index 20197e135a..e65d1adadf 100644 --- a/src/include/firebird/impl/blr.h +++ b/src/include/firebird/impl/blr.h @@ -492,4 +492,6 @@ #define blr_invsel_procedure_context (unsigned char) 6 #define blr_invsel_procedure_alias (unsigned char) 7 +#define blr_default_arg (unsigned char) 227 + #endif // FIREBIRD_IMPL_BLR_H diff --git a/src/include/firebird/impl/msg/jrd.h b/src/include/firebird/impl/msg/jrd.h index 2a78d1c81e..76901784dc 100644 --- a/src/include/firebird/impl/msg/jrd.h +++ b/src/include/firebird/impl/msg/jrd.h @@ -970,5 +970,5 @@ FB_IMPL_MSG(JRD, 967, idx_expr_not_found, -902, "42", "000", "Definition of inde FB_IMPL_MSG(JRD, 968, idx_cond_not_found, -902, "42", "000", "Definition of index condition is not found for index @1") FB_IMPL_MSG(JRD, 969, uninitialized_var, -625, "42", "000", "Variable @1 is not initialized") FB_IMPL_MSG(JRD, 970, param_not_exist, -170, "07", "001", "Parameter @1 does not exist") -FB_IMPL_MSG(JRD, 971, param_no_default_not_specified, -170, "07", "001", "Parameter @1 has no default value and was not specified") +FB_IMPL_MSG(JRD, 971, param_no_default_not_specified, -170, "07", "001", "Parameter @1 has no default value and was not specified or was specified with DEFAULT") FB_IMPL_MSG(JRD, 972, param_multiple_assignments, -170, "07", "001", "Parameter @1 has multiple assignments") diff --git a/src/jrd/RecordSourceNodes.cpp b/src/jrd/RecordSourceNodes.cpp index 0a6a0ba511..8e563c79e4 100644 --- a/src/jrd/RecordSourceNodes.cpp +++ b/src/jrd/RecordSourceNodes.cpp @@ -1294,7 +1294,7 @@ void ProcedureSourceNode::genBlr(DsqlCompilerScratch* dsqlScratch) dsqlScratch->appendUShort(inputSources->items.getCount()); for (auto& arg : inputSources->items) - GEN_expr(dsqlScratch, arg); + GEN_arg(dsqlScratch, arg); } if (dsqlContext->ctx_context > MAX_UCHAR) @@ -1355,7 +1355,7 @@ void ProcedureSourceNode::genBlr(DsqlCompilerScratch* dsqlScratch) dsqlScratch->appendUShort(inputSources->items.getCount()); for (auto& arg : inputSources->items) - GEN_expr(dsqlScratch, arg); + GEN_arg(dsqlScratch, arg); } else dsqlScratch->appendUShort(0); diff --git a/src/jrd/blp.h b/src/jrd/blp.h index 738de16f50..c58833172c 100644 --- a/src/jrd/blp.h +++ b/src/jrd/blp.h @@ -258,5 +258,6 @@ static const struct {"invoke_function", invoke_function}, {"invoke_procedure", invsel_procedure}, {"select_procedure", invsel_procedure}, + {"blr_default_arg", zero}, {0, 0} }; diff --git a/src/jrd/cmp.cpp b/src/jrd/cmp.cpp index 7dde2a8927..ae2abe4d11 100644 --- a/src/jrd/cmp.cpp +++ b/src/jrd/cmp.cpp @@ -553,12 +553,15 @@ Arg::StatusVector CMP_procedure_arguments( for (auto& parameter : fields) { - if (const auto argValue = argsByName.get(parameter->prm_name)) + const auto argValue = argsByName.get(parameter->prm_name); + + if (argValue) { *sourceArgIt = *argValue; argsByName.remove(parameter->prm_name); } - else if (isInput) + + if (isInput && (!argValue || !*argValue)) { if (parameter->prm_default_value) *sourceArgIt = CMP_clone_node(tdbb, csb, parameter->prm_default_value); diff --git a/src/jrd/par.cpp b/src/jrd/par.cpp index a8837c2260..a5222260de 100644 --- a/src/jrd/par.cpp +++ b/src/jrd/par.cpp @@ -804,7 +804,12 @@ ValueListNode* PAR_args(thread_db* tdbb, CompilerScratch* csb, USHORT count, USH { do { - *ptr++ = PAR_parse_value(tdbb, csb); + if (csb->csb_blr_reader.peekByte() == blr_default_arg) + csb->csb_blr_reader.getByte(); + else + *ptr = PAR_parse_value(tdbb, csb); + + ++ptr; } while (--count); }