From 390c3edd08ecd847e0e49128dbeb5f9a70e49950 Mon Sep 17 00:00:00 2001 From: Dmitry Yemanov Date: Thu, 25 Dec 2025 11:47:22 +0300 Subject: [PATCH] Fix #8822: Some procedures containing LIST aggregate function are not restored in Firebird 6.0 --- src/dsql/AggNodes.cpp | 10 +++++++--- src/dsql/parse.y | 2 +- src/include/firebird/impl/blr.h | 6 +++++- src/jrd/blp.h | 7 ++++--- src/yvalve/gds.cpp | 19 ++++++++++++++++++- 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/dsql/AggNodes.cpp b/src/dsql/AggNodes.cpp index 87fd272e1e1..77d4bce5abb 100644 --- a/src/dsql/AggNodes.cpp +++ b/src/dsql/AggNodes.cpp @@ -935,8 +935,12 @@ DmlNode* ListAggNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* ListAggNode* node = FB_NEW_POOL(pool) ListAggNode(pool, (blrOp == blr_agg_list_distinct)); node->arg = PAR_parse_value(tdbb, csb); node->delimiter = PAR_parse_value(tdbb, csb); - if (csb->csb_blr_reader.peekByte() == blr_sort) - node->sort = PAR_sort(tdbb, csb, blr_sort, true); + if (csb->csb_blr_reader.peekByte() == blr_within_group_order) + { + csb->csb_blr_reader.getByte(); // skip blr_within_group_order + if (const auto count = csb->csb_blr_reader.getByte()) + node->sort = PAR_sort_internal(tdbb, csb, true, count); + } return node; } @@ -966,7 +970,7 @@ void ListAggNode::genBlr(DsqlCompilerScratch* dsqlScratch) { AggNode::genBlr(dsqlScratch); if (dsqlOrderClause) - GEN_sort(dsqlScratch, blr_sort, dsqlOrderClause); + GEN_sort(dsqlScratch, blr_within_group_order, dsqlOrderClause); } bool ListAggNode::setParameterType(DsqlCompilerScratch* dsqlScratch, diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 01eae97c432..f31f7c02324 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -8685,7 +8685,7 @@ listagg_count_indication %type within_group_specification_opt within_group_specification_opt - : /* nothing */ { $$ = newNode(0); } + : /* nothing */ { $$ = nullptr; } | within_group_specification { $$ = $1; } ; diff --git a/src/include/firebird/impl/blr.h b/src/include/firebird/impl/blr.h index bb7825e3d4a..4fc7669a807 100644 --- a/src/include/firebird/impl/blr.h +++ b/src/include/firebird/impl/blr.h @@ -507,10 +507,12 @@ // Table value function #define blr_table_value_fun (unsigned char) 229 +// subcodes of blr_table_value_fun #define blr_table_value_fun_unlist (unsigned char) 1 #define blr_table_value_fun_gen_series (unsigned char) 2 #define blr_for_range (unsigned char) 230 +// subcodes of blr_for_range #define blr_for_range_variable (unsigned char) 1 #define blr_for_range_initial_value (unsigned char) 2 #define blr_for_range_final_value (unsigned char) 3 @@ -523,9 +525,11 @@ #define blr_gen_id3 (unsigned char) 231 #define blr_default2 (unsigned char) 232 #define blr_current_schema (unsigned char) 233 -#define blr_flags (unsigned char) 234 +#define blr_flags (unsigned char) 234 // subcodes of blr_flags #define blr_flags_search_system_schema (unsigned char) 1 +#define blr_within_group_order (unsigned char) 235 + #endif // FIREBIRD_IMPL_BLR_H diff --git a/src/jrd/blp.h b/src/jrd/blp.h index ef29ce55567..57e6e079d2b 100644 --- a/src/jrd/blp.h +++ b/src/jrd/blp.h @@ -196,8 +196,8 @@ static inline constexpr struct {"cursor_stmt", cursor_stmt}, {"current_timestamp2", byte_line}, {"current_time2", byte_line}, - {"agg_list", two}, // 170 - {"agg_list_distinct", two}, + {"agg_list", list_function}, // 170 + {"agg_list_distinct", list_function}, {"modify2", modify2}, {"erase2", erase2}, // New BLR in FB1 @@ -229,7 +229,7 @@ static inline constexpr struct {"partition_by", partition_by}, {"continue_loop", byte_line}, {"procedure4", procedure4}, - {"agg_function", function}, + {"agg_function", agg_function}, {"substring_similar", three}, // 200 {"bool_as_value", one}, {"coalesce", byte_args}, @@ -267,5 +267,6 @@ static inline constexpr struct {"default2", default2}, {"current_schema", zero}, {NULL, NULL}, // flags - part of header + {NULL, NULL}, {0, 0} }; diff --git a/src/yvalve/gds.cpp b/src/yvalve/gds.cpp index ce575729601..e114def3ad7 100644 --- a/src/yvalve/gds.cpp +++ b/src/yvalve/gds.cpp @@ -327,6 +327,7 @@ constexpr int op_invoke_function = 33; constexpr int op_invsel_procedure = 34; constexpr int op_table_value_fun = 35; constexpr int op_for_range = 36; +constexpr int op_within_group_order = 37; static constexpr UCHAR // generic print formats @@ -433,7 +434,9 @@ static constexpr UCHAR default2[] = { op_line, op_indent, op_byte, op_literal, op_line, op_indent, op_byte, op_literal, op_line, op_indent, op_byte, op_literal, - op_pad, op_line, 0}; + op_pad, op_line, 0 }, + list_function[] = { op_line, op_verb, op_verb, op_within_group_order, 0 }, + agg_function[] = { op_byte, op_literal, op_byte, op_line, op_args, op_within_group_order, 0 }; #include "../jrd/blp.h" @@ -4432,6 +4435,20 @@ static void blr_print_verb(gds_ctl* control, SSHORT level) break; } + case op_within_group_order: + { + if (control->ctl_blr_reader.peekByte() == blr_within_group_order) + { + blr_indent(control, level); + blr_print_blr(control, control->ctl_blr_reader.getByte()); + n = blr_print_byte(control); + blr_print_line(control, (SSHORT) offset); + while (--n >= 0) + blr_print_verb(control, level + 1); + } + break; + } + default: fb_assert(false); break;