|
56 | 56 | #include <string> |
57 | 57 | #include <vector> |
58 | 58 | #include <memory> |
| 59 | +#include <cstdlib> |
| 60 | +#include <cstring> |
59 | 61 |
|
60 | 62 | namespace sql_engine { |
61 | 63 |
|
@@ -846,15 +848,128 @@ class PlanExecutor { |
846 | 848 | return ptr; |
847 | 849 | } |
848 | 850 |
|
| 851 | + static bool same_agg_call(const sql_parser::AstNode* a, const sql_parser::AstNode* b) { |
| 852 | + if (!a || !b) return false; |
| 853 | + if (a->type != sql_parser::NodeType::NODE_FUNCTION_CALL || |
| 854 | + b->type != sql_parser::NodeType::NODE_FUNCTION_CALL) return false; |
| 855 | + return a->value().equals_ci(b->value().ptr, b->value().len); |
| 856 | + } |
| 857 | + |
| 858 | + const sql_parser::AstNode* rewrite_having_expr(const sql_parser::AstNode* expr, |
| 859 | + PlanNode* agg_node) { |
| 860 | + if (!expr || !agg_node) return expr; |
| 861 | + uint16_t group_count = 0; |
| 862 | + uint16_t agg_count = 0; |
| 863 | + const sql_parser::AstNode** agg_exprs = nullptr; |
| 864 | + const sql_parser::AstNode** group_by = nullptr; |
| 865 | + if (agg_node->type == PlanNodeType::AGGREGATE) { |
| 866 | + group_count = agg_node->aggregate.group_count; |
| 867 | + agg_count = agg_node->aggregate.agg_count; |
| 868 | + agg_exprs = agg_node->aggregate.agg_exprs; |
| 869 | + group_by = agg_node->aggregate.group_by; |
| 870 | + } else if (agg_node->type == PlanNodeType::MERGE_AGGREGATE) { |
| 871 | + group_count = agg_node->merge_aggregate.group_key_count; |
| 872 | + if (agg_node->merge_aggregate.output_exprs && |
| 873 | + agg_node->merge_aggregate.output_expr_count > group_count) { |
| 874 | + agg_exprs = agg_node->merge_aggregate.output_exprs + group_count; |
| 875 | + agg_count = static_cast<uint16_t>( |
| 876 | + agg_node->merge_aggregate.output_expr_count - group_count); |
| 877 | + group_by = agg_node->merge_aggregate.output_exprs; |
| 878 | + } |
| 879 | + } else { |
| 880 | + return expr; |
| 881 | + } |
| 882 | + |
| 883 | + if (expr->type == sql_parser::NodeType::NODE_FUNCTION_CALL && agg_exprs) { |
| 884 | + for (uint16_t i = 0; i < agg_count; ++i) { |
| 885 | + if (same_agg_call(expr, agg_exprs[i])) { |
| 886 | + sql_parser::StringRef name = expr->value(); |
| 887 | + return sql_parser::make_node( |
| 888 | + arena_, sql_parser::NodeType::NODE_IDENTIFIER, name); |
| 889 | + } |
| 890 | + } |
| 891 | + } |
| 892 | + |
| 893 | + bool changed = false; |
| 894 | + sql_parser::AstNode* clone = sql_parser::make_node( |
| 895 | + arena_, expr->type, expr->value(), expr->flags); |
| 896 | + for (const sql_parser::AstNode* c = expr->first_child; c; c = c->next_sibling) { |
| 897 | + const sql_parser::AstNode* rw = rewrite_having_expr(c, agg_node); |
| 898 | + if (rw != c) changed = true; |
| 899 | + if (rw) clone->add_child(const_cast<sql_parser::AstNode*>(rw)); |
| 900 | + } |
| 901 | + (void)group_count; |
| 902 | + (void)group_by; |
| 903 | + return changed ? clone : expr; |
| 904 | + } |
| 905 | + |
| 906 | + const TableInfo* make_agg_output_table(PlanNode* agg_node) { |
| 907 | + if (!agg_node) return nullptr; |
| 908 | + uint16_t group_count = 0; |
| 909 | + uint16_t agg_count = 0; |
| 910 | + const sql_parser::AstNode** group_by = nullptr; |
| 911 | + const sql_parser::AstNode** agg_exprs = nullptr; |
| 912 | + if (agg_node->type == PlanNodeType::AGGREGATE) { |
| 913 | + group_count = agg_node->aggregate.group_count; |
| 914 | + agg_count = agg_node->aggregate.agg_count; |
| 915 | + group_by = agg_node->aggregate.group_by; |
| 916 | + agg_exprs = agg_node->aggregate.agg_exprs; |
| 917 | + } else if (agg_node->type == PlanNodeType::MERGE_AGGREGATE && |
| 918 | + agg_node->merge_aggregate.output_exprs) { |
| 919 | + group_count = agg_node->merge_aggregate.group_key_count; |
| 920 | + group_by = agg_node->merge_aggregate.output_exprs; |
| 921 | + if (agg_node->merge_aggregate.output_expr_count > group_count) { |
| 922 | + agg_exprs = agg_node->merge_aggregate.output_exprs + group_count; |
| 923 | + agg_count = static_cast<uint16_t>( |
| 924 | + agg_node->merge_aggregate.output_expr_count - group_count); |
| 925 | + } |
| 926 | + } else { |
| 927 | + return nullptr; |
| 928 | + } |
| 929 | + |
| 930 | + uint16_t n = static_cast<uint16_t>(group_count + agg_count); |
| 931 | + if (n == 0) return nullptr; |
| 932 | + auto* cols = static_cast<ColumnInfo*>(arena_.allocate(sizeof(ColumnInfo) * n)); |
| 933 | + if (!cols) return nullptr; |
| 934 | + for (uint16_t i = 0; i < group_count; ++i) { |
| 935 | + cols[i].ordinal = i; |
| 936 | + cols[i].nullable = true; |
| 937 | + cols[i].type = SqlType::make_int(); |
| 938 | + cols[i].name = (group_by && group_by[i]) ? group_by[i]->value() |
| 939 | + : sql_parser::StringRef{}; |
| 940 | + } |
| 941 | + for (uint16_t i = 0; i < agg_count; ++i) { |
| 942 | + cols[group_count + i].ordinal = static_cast<uint16_t>(group_count + i); |
| 943 | + cols[group_count + i].nullable = true; |
| 944 | + cols[group_count + i].type = SqlType::make_int(); |
| 945 | + cols[group_count + i].name = (agg_exprs && agg_exprs[i]) |
| 946 | + ? agg_exprs[i]->value() : sql_parser::StringRef{}; |
| 947 | + } |
| 948 | + auto* ti = static_cast<TableInfo*>(arena_.allocate(sizeof(TableInfo))); |
| 949 | + if (!ti) return nullptr; |
| 950 | + std::memset(ti, 0, sizeof(TableInfo)); |
| 951 | + ti->columns = cols; |
| 952 | + ti->column_count = n; |
| 953 | + return ti; |
| 954 | + } |
| 955 | + |
849 | 956 | Operator* build_filter(PlanNode* node) { |
850 | 957 | Operator* child = build_operator(node->left); |
851 | 958 | if (!child && node->left) return nullptr; |
852 | 959 |
|
853 | 960 | std::vector<const TableInfo*> tables; |
854 | | - collect_tables(node->left, tables); |
| 961 | + const sql_parser::AstNode* expr = node->filter.expr; |
| 962 | + if (node->left && (node->left->type == PlanNodeType::AGGREGATE || |
| 963 | + node->left->type == PlanNodeType::MERGE_AGGREGATE)) { |
| 964 | + expr = rewrite_having_expr(expr, node->left); |
| 965 | + const TableInfo* synth = make_agg_output_table(node->left); |
| 966 | + if (synth) tables.push_back(synth); |
| 967 | + } else { |
| 968 | + collect_tables(node->left, tables); |
| 969 | + } |
855 | 970 |
|
856 | 971 | auto op = std::make_unique<FilterOperator<D>>( |
857 | | - child, node->filter.expr, catalog_, tables, functions_, arena_, |
| 972 | + child, expr, catalog_, tables, functions_, arena_, |
858 | 973 | &subquery_exec_, outer_resolver_); |
859 | 974 | Operator* ptr = op.get(); |
860 | 975 | operators_.push_back(std::move(op)); |
@@ -1170,12 +1285,21 @@ class PlanExecutor { |
1170 | 1285 |
|
1171 | 1286 | uint16_t resolve_column_index(const sql_parser::AstNode* key, const TableInfo* table) { |
1172 | 1287 | if (!key || !table) return 0; |
| 1288 | + if (key->type == sql_parser::NodeType::NODE_LITERAL_INT) { |
| 1289 | + sql_parser::StringRef sv = key->value(); |
| 1290 | + if (!sv.ptr || sv.len == 0) return 0; |
| 1291 | + int64_t n = std::strtoll(sv.ptr, nullptr, 10); |
| 1292 | + if (n < 1) return 0; |
| 1293 | + if (n > static_cast<int64_t>(table->column_count)) { |
| 1294 | + return static_cast<uint16_t>(table->column_count - 1); |
| 1295 | + } |
| 1296 | + return static_cast<uint16_t>(n - 1); |
| 1297 | + } |
1173 | 1298 | sql_parser::StringRef col_name; |
1174 | 1299 | if (key->type == sql_parser::NodeType::NODE_COLUMN_REF || |
1175 | 1300 | key->type == sql_parser::NodeType::NODE_IDENTIFIER) { |
1176 | 1301 | col_name = key->value(); |
1177 | 1302 | } else if (key->type == sql_parser::NodeType::NODE_QUALIFIED_NAME) { |
1178 | | - // table.column -- get the column part |
1179 | 1303 | const sql_parser::AstNode* c = key->first_child; |
1180 | 1304 | if (c && c->next_sibling) col_name = c->next_sibling->value(); |
1181 | 1305 | else if (c) col_name = c->value(); |
|
0 commit comments