duckdb 0.7.2-dev16.0 → 0.7.2-dev314.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/binding.gyp +2 -0
- package/package.json +1 -1
- package/src/duckdb/extension/icu/icu-extension.cpp +2 -0
- package/src/duckdb/extension/icu/icu-table-range.cpp +194 -0
- package/src/duckdb/extension/icu/include/icu-table-range.hpp +17 -0
- package/src/duckdb/extension/parquet/column_reader.cpp +5 -6
- package/src/duckdb/extension/parquet/column_writer.cpp +0 -1
- package/src/duckdb/extension/parquet/include/column_reader.hpp +1 -2
- package/src/duckdb/extension/parquet/include/generated_column_reader.hpp +1 -11
- package/src/duckdb/extension/parquet/parquet-extension.cpp +11 -2
- package/src/duckdb/extension/parquet/parquet_statistics.cpp +26 -32
- package/src/duckdb/src/catalog/catalog_entry/duck_schema_entry.cpp +4 -0
- package/src/duckdb/src/catalog/catalog_entry/scalar_function_catalog_entry.cpp +7 -6
- package/src/duckdb/src/catalog/catalog_entry/table_function_catalog_entry.cpp +20 -1
- package/src/duckdb/src/common/enums/statement_type.cpp +2 -0
- package/src/duckdb/src/common/sort/sort_state.cpp +5 -7
- package/src/duckdb/src/common/types/bit.cpp +95 -58
- package/src/duckdb/src/common/types/value.cpp +149 -53
- package/src/duckdb/src/common/types/vector.cpp +13 -10
- package/src/duckdb/src/execution/column_binding_resolver.cpp +6 -0
- package/src/duckdb/src/execution/operator/aggregate/physical_perfecthash_aggregate.cpp +4 -5
- package/src/duckdb/src/execution/operator/aggregate/physical_window.cpp +1 -1
- package/src/duckdb/src/execution/operator/helper/physical_vacuum.cpp +2 -3
- package/src/duckdb/src/execution/operator/join/physical_blockwise_nl_join.cpp +32 -6
- package/src/duckdb/src/execution/operator/persistent/buffered_csv_reader.cpp +1 -1
- package/src/duckdb/src/execution/physical_plan/plan_aggregate.cpp +15 -15
- package/src/duckdb/src/execution/physical_plan/plan_comparison_join.cpp +18 -12
- package/src/duckdb/src/function/aggregate/algebraic/avg.cpp +0 -6
- package/src/duckdb/src/function/aggregate/distributive/bitagg.cpp +99 -95
- package/src/duckdb/src/function/aggregate/distributive/bitstring_agg.cpp +254 -0
- package/src/duckdb/src/function/aggregate/distributive/count.cpp +2 -4
- package/src/duckdb/src/function/aggregate/distributive/sum.cpp +11 -16
- package/src/duckdb/src/function/aggregate/distributive_functions.cpp +1 -0
- package/src/duckdb/src/function/aggregate/sorted_aggregate_function.cpp +16 -5
- package/src/duckdb/src/function/cast/bit_cast.cpp +0 -2
- package/src/duckdb/src/function/cast/blob_cast.cpp +0 -1
- package/src/duckdb/src/function/scalar/bit/bitstring.cpp +99 -0
- package/src/duckdb/src/function/scalar/date/date_diff.cpp +0 -1
- package/src/duckdb/src/function/scalar/date/date_part.cpp +17 -25
- package/src/duckdb/src/function/scalar/date/date_sub.cpp +0 -1
- package/src/duckdb/src/function/scalar/date/date_trunc.cpp +10 -14
- package/src/duckdb/src/function/scalar/generic/stats.cpp +2 -4
- package/src/duckdb/src/function/scalar/list/flatten.cpp +5 -12
- package/src/duckdb/src/function/scalar/list/list_concat.cpp +3 -8
- package/src/duckdb/src/function/scalar/list/list_extract.cpp +5 -12
- package/src/duckdb/src/function/scalar/list/list_value.cpp +5 -9
- package/src/duckdb/src/function/scalar/map/map_entries.cpp +61 -0
- package/src/duckdb/src/function/scalar/map/map_keys_values.cpp +97 -0
- package/src/duckdb/src/function/scalar/math/numeric.cpp +14 -17
- package/src/duckdb/src/function/scalar/nested_functions.cpp +3 -0
- package/src/duckdb/src/function/scalar/operators/add.cpp +0 -9
- package/src/duckdb/src/function/scalar/operators/arithmetic.cpp +29 -48
- package/src/duckdb/src/function/scalar/operators/bitwise.cpp +0 -63
- package/src/duckdb/src/function/scalar/operators/multiply.cpp +0 -6
- package/src/duckdb/src/function/scalar/operators/subtract.cpp +0 -6
- package/src/duckdb/src/function/scalar/string/caseconvert.cpp +2 -6
- package/src/duckdb/src/function/scalar/string/instr.cpp +2 -6
- package/src/duckdb/src/function/scalar/string/length.cpp +2 -6
- package/src/duckdb/src/function/scalar/string/like.cpp +2 -6
- package/src/duckdb/src/function/scalar/string/substring.cpp +2 -6
- package/src/duckdb/src/function/scalar/string_functions.cpp +1 -0
- package/src/duckdb/src/function/scalar/struct/struct_extract.cpp +4 -9
- package/src/duckdb/src/function/scalar/struct/struct_insert.cpp +10 -13
- package/src/duckdb/src/function/scalar/struct/struct_pack.cpp +5 -6
- package/src/duckdb/src/function/table/read_csv.cpp +9 -0
- package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
- package/src/duckdb/src/function/table_function.cpp +19 -0
- package/src/duckdb/src/include/duckdb/catalog/catalog_entry/table_function_catalog_entry.hpp +6 -8
- package/src/duckdb/src/include/duckdb/common/constants.hpp +0 -19
- package/src/duckdb/src/include/duckdb/common/enums/statement_type.hpp +2 -1
- package/src/duckdb/src/include/duckdb/common/enums/tableref_type.hpp +2 -1
- package/src/duckdb/src/include/duckdb/common/types/bit.hpp +5 -1
- package/src/duckdb/src/include/duckdb/common/types/value.hpp +2 -8
- package/src/duckdb/src/include/duckdb/common/types.hpp +1 -2
- package/src/duckdb/src/include/duckdb/execution/operator/aggregate/physical_perfecthash_aggregate.hpp +1 -1
- package/src/duckdb/src/include/duckdb/function/aggregate/distributive_functions.hpp +5 -0
- package/src/duckdb/src/include/duckdb/function/aggregate_function.hpp +12 -3
- package/src/duckdb/src/include/duckdb/function/scalar/bit_functions.hpp +4 -0
- package/src/duckdb/src/include/duckdb/function/scalar/nested_functions.hpp +12 -0
- package/src/duckdb/src/include/duckdb/function/scalar_function.hpp +2 -2
- package/src/duckdb/src/include/duckdb/function/table_function.hpp +2 -0
- package/src/duckdb/src/include/duckdb/main/capi/capi_internal.hpp +2 -0
- package/src/duckdb/src/include/duckdb/main/config.hpp +3 -0
- package/src/duckdb/src/include/duckdb/main/database.hpp +1 -0
- package/src/duckdb/src/include/duckdb/optimizer/join_order/cardinality_estimator.hpp +2 -2
- package/src/duckdb/src/include/duckdb/parser/common_table_expression_info.hpp +2 -0
- package/src/duckdb/src/include/duckdb/parser/parsed_data/alter_info.hpp +2 -1
- package/src/duckdb/src/include/duckdb/parser/parsed_data/{alter_function_info.hpp → alter_scalar_function_info.hpp} +13 -13
- package/src/duckdb/src/include/duckdb/parser/parsed_data/alter_table_function_info.hpp +47 -0
- package/src/duckdb/src/include/duckdb/parser/parsed_data/create_table_function_info.hpp +2 -1
- package/src/duckdb/src/include/duckdb/parser/query_node.hpp +2 -1
- package/src/duckdb/src/include/duckdb/parser/statement/multi_statement.hpp +28 -0
- package/src/duckdb/src/include/duckdb/parser/tableref/list.hpp +1 -0
- package/src/duckdb/src/include/duckdb/parser/tableref/pivotref.hpp +76 -0
- package/src/duckdb/src/include/duckdb/parser/tokens.hpp +2 -0
- package/src/duckdb/src/include/duckdb/parser/transformer.hpp +28 -0
- package/src/duckdb/src/include/duckdb/planner/bind_context.hpp +2 -0
- package/src/duckdb/src/include/duckdb/planner/binder.hpp +8 -0
- package/src/duckdb/src/include/duckdb/storage/buffer/block_handle.hpp +2 -0
- package/src/duckdb/src/include/duckdb/storage/buffer_manager.hpp +76 -44
- package/src/duckdb/src/include/duckdb/storage/checkpoint/table_data_writer.hpp +3 -2
- package/src/duckdb/src/include/duckdb/storage/compression/chimp/chimp_compress.hpp +2 -2
- package/src/duckdb/src/include/duckdb/storage/compression/chimp/chimp_fetch.hpp +1 -1
- package/src/duckdb/src/include/duckdb/storage/compression/chimp/chimp_scan.hpp +1 -1
- package/src/duckdb/src/include/duckdb/storage/compression/patas/patas_compress.hpp +2 -2
- package/src/duckdb/src/include/duckdb/storage/compression/patas/patas_fetch.hpp +1 -1
- package/src/duckdb/src/include/duckdb/storage/compression/patas/patas_scan.hpp +1 -1
- package/src/duckdb/src/include/duckdb/storage/data_pointer.hpp +5 -2
- package/src/duckdb/src/include/duckdb/storage/data_table.hpp +1 -1
- package/src/duckdb/src/include/duckdb/storage/statistics/base_statistics.hpp +93 -29
- package/src/duckdb/src/include/duckdb/storage/statistics/column_statistics.hpp +22 -3
- package/src/duckdb/src/include/duckdb/storage/statistics/distinct_statistics.hpp +6 -6
- package/src/duckdb/src/include/duckdb/storage/statistics/list_stats.hpp +41 -0
- package/src/duckdb/src/include/duckdb/storage/statistics/node_statistics.hpp +26 -0
- package/src/duckdb/src/include/duckdb/storage/statistics/numeric_stats.hpp +157 -0
- package/src/duckdb/src/include/duckdb/storage/statistics/segment_statistics.hpp +2 -7
- package/src/duckdb/src/include/duckdb/storage/statistics/string_stats.hpp +74 -0
- package/src/duckdb/src/include/duckdb/storage/statistics/struct_stats.hpp +42 -0
- package/src/duckdb/src/include/duckdb/storage/string_uncompressed.hpp +2 -3
- package/src/duckdb/src/include/duckdb/storage/table/column_segment.hpp +2 -2
- package/src/duckdb/src/include/duckdb/storage/table/list_column_data.hpp +1 -1
- package/src/duckdb/src/include/duckdb/storage/table/persistent_table_data.hpp +2 -1
- package/src/duckdb/src/include/duckdb/storage/table/row_group.hpp +4 -3
- package/src/duckdb/src/include/duckdb/storage/table/row_group_collection.hpp +3 -2
- package/src/duckdb/src/include/duckdb/storage/table/scan_state.hpp +2 -0
- package/src/duckdb/src/include/duckdb/storage/table/table_statistics.hpp +5 -0
- package/src/duckdb/src/include/duckdb.h +49 -1
- package/src/duckdb/src/include/duckdb.hpp +0 -1
- package/src/duckdb/src/main/capi/pending-c.cpp +16 -3
- package/src/duckdb/src/main/capi/result-c.cpp +27 -1
- package/src/duckdb/src/main/capi/stream-c.cpp +25 -0
- package/src/duckdb/src/main/client_context.cpp +8 -1
- package/src/duckdb/src/main/config.cpp +66 -1
- package/src/duckdb/src/main/database.cpp +10 -2
- package/src/duckdb/src/optimizer/join_order/cardinality_estimator.cpp +98 -67
- package/src/duckdb/src/optimizer/join_order/join_order_optimizer.cpp +16 -3
- package/src/duckdb/src/optimizer/statistics/expression/propagate_aggregate.cpp +9 -3
- package/src/duckdb/src/optimizer/statistics/expression/propagate_and_compress.cpp +6 -7
- package/src/duckdb/src/optimizer/statistics/expression/propagate_cast.cpp +14 -11
- package/src/duckdb/src/optimizer/statistics/expression/propagate_columnref.cpp +1 -1
- package/src/duckdb/src/optimizer/statistics/expression/propagate_comparison.cpp +13 -15
- package/src/duckdb/src/optimizer/statistics/expression/propagate_conjunction.cpp +0 -1
- package/src/duckdb/src/optimizer/statistics/expression/propagate_constant.cpp +3 -75
- package/src/duckdb/src/optimizer/statistics/expression/propagate_function.cpp +7 -2
- package/src/duckdb/src/optimizer/statistics/expression/propagate_operator.cpp +10 -0
- package/src/duckdb/src/optimizer/statistics/operator/propagate_aggregate.cpp +2 -3
- package/src/duckdb/src/optimizer/statistics/operator/propagate_filter.cpp +28 -31
- package/src/duckdb/src/optimizer/statistics/operator/propagate_join.cpp +4 -5
- package/src/duckdb/src/optimizer/statistics/operator/propagate_set_operation.cpp +3 -3
- package/src/duckdb/src/optimizer/statistics_propagator.cpp +1 -1
- package/src/duckdb/src/parser/parsed_data/alter_info.cpp +7 -3
- package/src/duckdb/src/parser/parsed_data/alter_scalar_function_info.cpp +56 -0
- package/src/duckdb/src/parser/parsed_data/alter_table_function_info.cpp +51 -0
- package/src/duckdb/src/parser/parsed_data/create_scalar_function_info.cpp +3 -2
- package/src/duckdb/src/parser/parsed_data/create_table_function_info.cpp +6 -0
- package/src/duckdb/src/parser/parsed_expression_iterator.cpp +8 -0
- package/src/duckdb/src/parser/query_node.cpp +1 -1
- package/src/duckdb/src/parser/statement/multi_statement.cpp +18 -0
- package/src/duckdb/src/parser/tableref/pivotref.cpp +296 -0
- package/src/duckdb/src/parser/tableref.cpp +3 -0
- package/src/duckdb/src/parser/transform/helpers/transform_alias.cpp +12 -6
- package/src/duckdb/src/parser/transform/helpers/transform_cte.cpp +24 -0
- package/src/duckdb/src/parser/transform/statement/transform_create_function.cpp +4 -0
- package/src/duckdb/src/parser/transform/statement/transform_create_view.cpp +4 -0
- package/src/duckdb/src/parser/transform/statement/transform_pivot_stmt.cpp +150 -0
- package/src/duckdb/src/parser/transform/statement/transform_select.cpp +8 -0
- package/src/duckdb/src/parser/transform/statement/transform_select_node.cpp +1 -1
- package/src/duckdb/src/parser/transform/tableref/transform_join.cpp +4 -0
- package/src/duckdb/src/parser/transform/tableref/transform_pivot.cpp +105 -0
- package/src/duckdb/src/parser/transform/tableref/transform_tableref.cpp +2 -0
- package/src/duckdb/src/parser/transformer.cpp +15 -3
- package/src/duckdb/src/planner/bind_context.cpp +16 -0
- package/src/duckdb/src/planner/binder/query_node/bind_select_node.cpp +11 -3
- package/src/duckdb/src/planner/binder/query_node/plan_select_node.cpp +0 -1
- package/src/duckdb/src/planner/binder/statement/bind_create.cpp +1 -1
- package/src/duckdb/src/planner/binder/statement/bind_logical_plan.cpp +17 -0
- package/src/duckdb/src/planner/binder/tableref/bind_joinref.cpp +9 -0
- package/src/duckdb/src/planner/binder/tableref/bind_pivot.cpp +365 -0
- package/src/duckdb/src/planner/binder.cpp +7 -1
- package/src/duckdb/src/planner/bound_result_modifier.cpp +1 -1
- package/src/duckdb/src/planner/expression/bound_window_expression.cpp +1 -1
- package/src/duckdb/src/planner/filter/constant_filter.cpp +4 -6
- package/src/duckdb/src/planner/pragma_handler.cpp +10 -2
- package/src/duckdb/src/storage/buffer_manager.cpp +44 -46
- package/src/duckdb/src/storage/checkpoint/row_group_writer.cpp +1 -1
- package/src/duckdb/src/storage/checkpoint/table_data_reader.cpp +1 -4
- package/src/duckdb/src/storage/checkpoint/table_data_writer.cpp +4 -4
- package/src/duckdb/src/storage/compression/bitpacking.cpp +28 -24
- package/src/duckdb/src/storage/compression/fixed_size_uncompressed.cpp +43 -45
- package/src/duckdb/src/storage/compression/numeric_constant.cpp +9 -10
- package/src/duckdb/src/storage/compression/patas.cpp +1 -1
- package/src/duckdb/src/storage/compression/rle.cpp +19 -15
- package/src/duckdb/src/storage/compression/validity_uncompressed.cpp +5 -5
- package/src/duckdb/src/storage/data_table.cpp +4 -6
- package/src/duckdb/src/storage/statistics/base_statistics.cpp +373 -128
- package/src/duckdb/src/storage/statistics/column_statistics.cpp +58 -3
- package/src/duckdb/src/storage/statistics/distinct_statistics.cpp +4 -9
- package/src/duckdb/src/storage/statistics/list_stats.cpp +117 -0
- package/src/duckdb/src/storage/statistics/numeric_stats.cpp +529 -0
- package/src/duckdb/src/storage/statistics/segment_statistics.cpp +2 -11
- package/src/duckdb/src/storage/statistics/string_stats.cpp +273 -0
- package/src/duckdb/src/storage/statistics/struct_stats.cpp +131 -0
- package/src/duckdb/src/storage/storage_info.cpp +1 -1
- package/src/duckdb/src/storage/table/column_checkpoint_state.cpp +3 -4
- package/src/duckdb/src/storage/table/column_data.cpp +16 -11
- package/src/duckdb/src/storage/table/column_data_checkpointer.cpp +2 -3
- package/src/duckdb/src/storage/table/column_segment.cpp +6 -8
- package/src/duckdb/src/storage/table/list_column_data.cpp +39 -58
- package/src/duckdb/src/storage/table/row_group.cpp +24 -23
- package/src/duckdb/src/storage/table/row_group_collection.cpp +12 -12
- package/src/duckdb/src/storage/table/standard_column_data.cpp +6 -6
- package/src/duckdb/src/storage/table/struct_column_data.cpp +15 -16
- package/src/duckdb/src/storage/table/table_statistics.cpp +27 -7
- package/src/duckdb/src/storage/table/update_segment.cpp +10 -12
- package/src/duckdb/third_party/libpg_query/include/nodes/nodes.hpp +3 -0
- package/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp +34 -1
- package/src/duckdb/third_party/libpg_query/include/parser/gram.hpp +1020 -530
- package/src/duckdb/third_party/libpg_query/include/parser/kwlist.hpp +7 -0
- package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +23560 -22737
- package/src/duckdb/ub_src_function_aggregate_distributive.cpp +2 -0
- package/src/duckdb/ub_src_function_scalar_bit.cpp +2 -0
- package/src/duckdb/ub_src_function_scalar_map.cpp +4 -0
- package/src/duckdb/ub_src_main_capi.cpp +2 -0
- package/src/duckdb/ub_src_parser_parsed_data.cpp +4 -2
- package/src/duckdb/ub_src_parser_statement.cpp +2 -0
- package/src/duckdb/ub_src_parser_tableref.cpp +2 -0
- package/src/duckdb/ub_src_parser_transform_statement.cpp +2 -0
- package/src/duckdb/ub_src_parser_transform_tableref.cpp +2 -0
- package/src/duckdb/ub_src_planner_binder_tableref.cpp +2 -0
- package/src/duckdb/ub_src_storage_statistics.cpp +4 -6
- package/src/duckdb/src/include/duckdb/main/loadable_extension.hpp +0 -59
- package/src/duckdb/src/include/duckdb/storage/statistics/list_statistics.hpp +0 -36
- package/src/duckdb/src/include/duckdb/storage/statistics/numeric_statistics.hpp +0 -75
- package/src/duckdb/src/include/duckdb/storage/statistics/string_statistics.hpp +0 -49
- package/src/duckdb/src/include/duckdb/storage/statistics/struct_statistics.hpp +0 -36
- package/src/duckdb/src/include/duckdb/storage/statistics/validity_statistics.hpp +0 -45
- package/src/duckdb/src/parser/parsed_data/alter_function_info.cpp +0 -55
- package/src/duckdb/src/storage/statistics/list_statistics.cpp +0 -94
- package/src/duckdb/src/storage/statistics/numeric_statistics.cpp +0 -307
- package/src/duckdb/src/storage/statistics/string_statistics.cpp +0 -220
- package/src/duckdb/src/storage/statistics/struct_statistics.cpp +0 -108
- package/src/duckdb/src/storage/statistics/validity_statistics.cpp +0 -91
@@ -0,0 +1,105 @@
|
|
1
|
+
#include "duckdb/common/exception.hpp"
|
2
|
+
#include "duckdb/parser/tableref/pivotref.hpp"
|
3
|
+
#include "duckdb/parser/transformer.hpp"
|
4
|
+
#include "duckdb/parser/expression/columnref_expression.hpp"
|
5
|
+
#include "duckdb/parser/expression/constant_expression.hpp"
|
6
|
+
#include "duckdb/parser/expression/function_expression.hpp"
|
7
|
+
|
8
|
+
namespace duckdb {
|
9
|
+
|
10
|
+
static void TransformPivotInList(unique_ptr<ParsedExpression> &expr, PivotColumnEntry &entry, bool root_entry = true) {
|
11
|
+
if (expr->type == ExpressionType::COLUMN_REF) {
|
12
|
+
auto &colref = (ColumnRefExpression &)*expr;
|
13
|
+
if (colref.IsQualified()) {
|
14
|
+
throw ParserException("PIVOT IN list cannot contain qualified column references");
|
15
|
+
}
|
16
|
+
entry.values.emplace_back(colref.GetColumnName());
|
17
|
+
} else if (expr->type == ExpressionType::VALUE_CONSTANT) {
|
18
|
+
auto &constant_expr = (ConstantExpression &)*expr;
|
19
|
+
entry.values.push_back(std::move(constant_expr.value));
|
20
|
+
} else if (root_entry && expr->type == ExpressionType::FUNCTION) {
|
21
|
+
auto &function = (FunctionExpression &)*expr;
|
22
|
+
if (function.function_name != "row") {
|
23
|
+
throw ParserException("PIVOT IN list must contain columns or lists of columns");
|
24
|
+
}
|
25
|
+
for (auto &child : function.children) {
|
26
|
+
TransformPivotInList(child, entry, false);
|
27
|
+
}
|
28
|
+
} else if (root_entry && expr->type == ExpressionType::STAR) {
|
29
|
+
entry.star_expr = std::move(expr);
|
30
|
+
} else {
|
31
|
+
throw ParserException("PIVOT IN list must contain columns or lists of columns");
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
PivotColumn Transformer::TransformPivotColumn(duckdb_libpgquery::PGPivot *pivot) {
|
36
|
+
PivotColumn col;
|
37
|
+
col.names = TransformStringList(pivot->pivot_columns);
|
38
|
+
if (pivot->pivot_value) {
|
39
|
+
for (auto node = pivot->pivot_value->head; node != nullptr; node = node->next) {
|
40
|
+
auto n = (duckdb_libpgquery::PGNode *)node->data.ptr_value;
|
41
|
+
auto expr = TransformExpression(n);
|
42
|
+
PivotColumnEntry entry;
|
43
|
+
entry.alias = expr->alias;
|
44
|
+
TransformPivotInList(expr, entry);
|
45
|
+
col.entries.push_back(std::move(entry));
|
46
|
+
}
|
47
|
+
}
|
48
|
+
if (pivot->pivot_enum) {
|
49
|
+
col.pivot_enum = pivot->pivot_enum;
|
50
|
+
}
|
51
|
+
return col;
|
52
|
+
}
|
53
|
+
|
54
|
+
vector<PivotColumn> Transformer::TransformPivotList(duckdb_libpgquery::PGList *list) {
|
55
|
+
vector<PivotColumn> result;
|
56
|
+
for (auto node = list->head; node != nullptr; node = node->next) {
|
57
|
+
auto pivot = (duckdb_libpgquery::PGPivot *)node->data.ptr_value;
|
58
|
+
result.push_back(TransformPivotColumn(pivot));
|
59
|
+
}
|
60
|
+
return result;
|
61
|
+
}
|
62
|
+
|
63
|
+
unique_ptr<TableRef> Transformer::TransformPivot(duckdb_libpgquery::PGPivotExpr *root) {
|
64
|
+
auto result = make_unique<PivotRef>();
|
65
|
+
result->source = TransformTableRefNode(root->source);
|
66
|
+
if (root->aggrs) {
|
67
|
+
TransformExpressionList(*root->aggrs, result->aggregates);
|
68
|
+
}
|
69
|
+
if (root->unpivots) {
|
70
|
+
result->unpivot_names = TransformStringList(root->unpivots);
|
71
|
+
}
|
72
|
+
result->pivots = TransformPivotList(root->pivots);
|
73
|
+
if (root->groups) {
|
74
|
+
result->groups = TransformStringList(root->groups);
|
75
|
+
}
|
76
|
+
for (auto &pivot : result->pivots) {
|
77
|
+
idx_t expected_size;
|
78
|
+
bool is_pivot = result->unpivot_names.empty();
|
79
|
+
if (!result->unpivot_names.empty()) {
|
80
|
+
// unpivot
|
81
|
+
if (pivot.names.size() != 1) {
|
82
|
+
throw ParserException("UNPIVOT requires a single column name for the PIVOT IN clause");
|
83
|
+
}
|
84
|
+
expected_size = pivot.entries[0].values.size();
|
85
|
+
} else {
|
86
|
+
// pivot
|
87
|
+
expected_size = pivot.names.size();
|
88
|
+
}
|
89
|
+
for (auto &entry : pivot.entries) {
|
90
|
+
if (entry.star_expr && is_pivot) {
|
91
|
+
throw ParserException("PIVOT IN list must contain columns or lists of columns - star expressions are "
|
92
|
+
"only supported for UNPIVOT");
|
93
|
+
}
|
94
|
+
if (entry.values.size() != expected_size) {
|
95
|
+
throw ParserException("PIVOT IN list - inconsistent amount of rows - expected %d but got %d",
|
96
|
+
expected_size, entry.values.size());
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
result->include_nulls = root->include_nulls;
|
101
|
+
result->alias = TransformAlias(root->alias, result->column_name_alias);
|
102
|
+
return std::move(result);
|
103
|
+
}
|
104
|
+
|
105
|
+
} // namespace duckdb
|
@@ -16,6 +16,8 @@ unique_ptr<TableRef> Transformer::TransformTableRefNode(duckdb_libpgquery::PGNod
|
|
16
16
|
return TransformRangeSubselect(reinterpret_cast<duckdb_libpgquery::PGRangeSubselect *>(n));
|
17
17
|
case duckdb_libpgquery::T_PGRangeFunction:
|
18
18
|
return TransformRangeFunction(reinterpret_cast<duckdb_libpgquery::PGRangeFunction *>(n));
|
19
|
+
case duckdb_libpgquery::T_PGPivotExpr:
|
20
|
+
return TransformPivot(reinterpret_cast<duckdb_libpgquery::PGPivotExpr *>(n));
|
19
21
|
default:
|
20
22
|
throw NotImplementedException("From Type %d not supported", n->type);
|
21
23
|
}
|
@@ -3,6 +3,7 @@
|
|
3
3
|
#include "duckdb/parser/expression/list.hpp"
|
4
4
|
#include "duckdb/parser/statement/list.hpp"
|
5
5
|
#include "duckdb/parser/tableref/emptytableref.hpp"
|
6
|
+
#include "duckdb/parser/query_node/select_node.hpp"
|
6
7
|
|
7
8
|
namespace duckdb {
|
8
9
|
|
@@ -28,12 +29,24 @@ Transformer::Transformer(Transformer *parent)
|
|
28
29
|
: parent(parent), max_expression_depth(parent->max_expression_depth), stack_depth(DConstants::INVALID_INDEX) {
|
29
30
|
}
|
30
31
|
|
32
|
+
Transformer::~Transformer() {
|
33
|
+
}
|
34
|
+
|
35
|
+
void Transformer::Clear() {
|
36
|
+
SetParamCount(0);
|
37
|
+
pivot_entries.clear();
|
38
|
+
}
|
39
|
+
|
31
40
|
bool Transformer::TransformParseTree(duckdb_libpgquery::PGList *tree, vector<unique_ptr<SQLStatement>> &statements) {
|
32
41
|
InitializeStackCheck();
|
33
42
|
for (auto entry = tree->head; entry != nullptr; entry = entry->next) {
|
34
|
-
|
35
|
-
auto
|
43
|
+
Clear();
|
44
|
+
auto n = (duckdb_libpgquery::PGNode *)entry->data.ptr_value;
|
45
|
+
auto stmt = TransformStatement(n);
|
36
46
|
D_ASSERT(stmt);
|
47
|
+
if (HasPivotEntries()) {
|
48
|
+
stmt = CreatePivotStatement(std::move(stmt));
|
49
|
+
}
|
37
50
|
stmt->n_param = ParamCount();
|
38
51
|
statements.push_back(std::move(stmt));
|
39
52
|
}
|
@@ -154,7 +167,6 @@ unique_ptr<SQLStatement> Transformer::TransformStatementInternal(duckdb_libpgque
|
|
154
167
|
default:
|
155
168
|
throw NotImplementedException(NodetypeToString(stmt->type));
|
156
169
|
}
|
157
|
-
return nullptr;
|
158
170
|
}
|
159
171
|
|
160
172
|
} // namespace duckdb
|
@@ -555,4 +555,20 @@ void BindContext::AddContext(BindContext other) {
|
|
555
555
|
}
|
556
556
|
}
|
557
557
|
|
558
|
+
void BindContext::RemoveContext(vector<std::pair<string, duckdb::Binding *>> &other_bindings_list) {
|
559
|
+
for (auto &other_binding : other_bindings_list) {
|
560
|
+
if (bindings.find(other_binding.first) != bindings.end()) {
|
561
|
+
bindings.erase(other_binding.first);
|
562
|
+
}
|
563
|
+
}
|
564
|
+
|
565
|
+
vector<idx_t> delete_list_indexes;
|
566
|
+
for (auto &other_binding : other_bindings_list) {
|
567
|
+
auto it =
|
568
|
+
std::remove_if(bindings_list.begin(), bindings_list.end(),
|
569
|
+
[other_binding](std::pair<string, Binding *> &x) { return x.first == other_binding.first; });
|
570
|
+
bindings_list.erase(it, bindings_list.end());
|
571
|
+
}
|
572
|
+
}
|
573
|
+
|
558
574
|
} // namespace duckdb
|
@@ -328,6 +328,16 @@ void Binder::ExpandStarExpressions(vector<unique_ptr<ParsedExpression>> &select_
|
|
328
328
|
}
|
329
329
|
|
330
330
|
unique_ptr<BoundQueryNode> Binder::BindNode(SelectNode &statement) {
|
331
|
+
D_ASSERT(statement.from_table);
|
332
|
+
// first bind the FROM table statement
|
333
|
+
auto from = std::move(statement.from_table);
|
334
|
+
auto from_table = Bind(*from);
|
335
|
+
return BindSelectNode(statement, std::move(from_table));
|
336
|
+
}
|
337
|
+
|
338
|
+
unique_ptr<BoundQueryNode> Binder::BindSelectNode(SelectNode &statement, unique_ptr<BoundTableRef> from_table) {
|
339
|
+
D_ASSERT(from_table);
|
340
|
+
D_ASSERT(!statement.from_table);
|
331
341
|
auto result = make_unique<BoundSelectNode>();
|
332
342
|
result->projection_index = GenerateTableIndex();
|
333
343
|
result->group_index = GenerateTableIndex();
|
@@ -337,9 +347,7 @@ unique_ptr<BoundQueryNode> Binder::BindNode(SelectNode &statement) {
|
|
337
347
|
result->unnest_index = GenerateTableIndex();
|
338
348
|
result->prune_index = GenerateTableIndex();
|
339
349
|
|
340
|
-
|
341
|
-
result->from_table = Bind(*statement.from_table);
|
342
|
-
|
350
|
+
result->from_table = std::move(from_table);
|
343
351
|
// bind the sample clause
|
344
352
|
if (statement.sample) {
|
345
353
|
result->sample_options = std::move(statement.sample);
|
@@ -104,7 +104,6 @@ unique_ptr<LogicalOperator> Binder::CreatePlan(BoundSelectNode &statement) {
|
|
104
104
|
PlanSubqueries(&expr, &root);
|
105
105
|
}
|
106
106
|
|
107
|
-
// create the projection
|
108
107
|
auto proj = make_unique<LogicalProjection>(statement.projection_index, std::move(statement.select_list));
|
109
108
|
auto &projection = *proj;
|
110
109
|
proj->AddChild(std::move(root));
|
@@ -467,7 +467,6 @@ BoundStatement Binder::Bind(CreateStatement &stmt) {
|
|
467
467
|
BoundStatement result;
|
468
468
|
result.names = {"Count"};
|
469
469
|
result.types = {LogicalType::BIGINT};
|
470
|
-
properties.return_type = StatementReturnType::NOTHING;
|
471
470
|
|
472
471
|
auto catalog_type = stmt.info->type;
|
473
472
|
switch (catalog_type) {
|
@@ -675,6 +674,7 @@ BoundStatement Binder::Bind(CreateStatement &stmt) {
|
|
675
674
|
default:
|
676
675
|
throw Exception("Unrecognized type!");
|
677
676
|
}
|
677
|
+
properties.return_type = StatementReturnType::NOTHING;
|
678
678
|
properties.allow_stream_result = false;
|
679
679
|
return result;
|
680
680
|
}
|
@@ -4,6 +4,19 @@
|
|
4
4
|
|
5
5
|
namespace duckdb {
|
6
6
|
|
7
|
+
idx_t GetMaxTableIndex(LogicalOperator &op) {
|
8
|
+
idx_t result = 0;
|
9
|
+
for (auto &child : op.children) {
|
10
|
+
auto max_child_index = GetMaxTableIndex(*child);
|
11
|
+
result = MaxValue<idx_t>(result, max_child_index);
|
12
|
+
}
|
13
|
+
auto indexes = op.GetTableIndex();
|
14
|
+
for (auto &index : indexes) {
|
15
|
+
result = MaxValue<idx_t>(result, index);
|
16
|
+
}
|
17
|
+
return result;
|
18
|
+
}
|
19
|
+
|
7
20
|
BoundStatement Binder::Bind(LogicalPlanStatement &stmt) {
|
8
21
|
BoundStatement result;
|
9
22
|
result.types = stmt.plan->types;
|
@@ -14,6 +27,10 @@ BoundStatement Binder::Bind(LogicalPlanStatement &stmt) {
|
|
14
27
|
properties.allow_stream_result = true;
|
15
28
|
properties.return_type = StatementReturnType::QUERY_RESULT; // TODO could also be something else
|
16
29
|
|
30
|
+
if (parent) {
|
31
|
+
throw InternalException("LogicalPlanStatement should be bound in root binder");
|
32
|
+
}
|
33
|
+
bound_tables = GetMaxTableIndex(*result.plan) + 1;
|
17
34
|
return result;
|
18
35
|
}
|
19
36
|
|
@@ -7,9 +7,11 @@
|
|
7
7
|
#include "duckdb/parser/expression/constant_expression.hpp"
|
8
8
|
#include "duckdb/parser/expression/conjunction_expression.hpp"
|
9
9
|
#include "duckdb/parser/expression/bound_expression.hpp"
|
10
|
+
#include "duckdb/parser/expression/star_expression.hpp"
|
10
11
|
#include "duckdb/common/string_util.hpp"
|
11
12
|
#include "duckdb/common/case_insensitive_map.hpp"
|
12
13
|
#include "duckdb/planner/expression_binder/lateral_binder.hpp"
|
14
|
+
#include "duckdb/planner/query_node/bound_select_node.hpp"
|
13
15
|
|
14
16
|
namespace duckdb {
|
15
17
|
|
@@ -253,6 +255,8 @@ unique_ptr<BoundTableRef> Binder::Bind(JoinRef &ref) {
|
|
253
255
|
}
|
254
256
|
}
|
255
257
|
|
258
|
+
auto right_bindings_list_copy = right_binder.bind_context.GetBindingsList();
|
259
|
+
|
256
260
|
bind_context.AddContext(std::move(left_binder.bind_context));
|
257
261
|
bind_context.AddContext(std::move(right_binder.bind_context));
|
258
262
|
MoveCorrelatedExpressions(left_binder);
|
@@ -269,6 +273,11 @@ unique_ptr<BoundTableRef> Binder::Bind(JoinRef &ref) {
|
|
269
273
|
WhereBinder binder(*this, context);
|
270
274
|
result->condition = binder.Bind(ref.condition);
|
271
275
|
}
|
276
|
+
|
277
|
+
if (result->type == JoinType::SEMI || result->type == JoinType::ANTI) {
|
278
|
+
bind_context.RemoveContext(right_bindings_list_copy);
|
279
|
+
}
|
280
|
+
|
272
281
|
return std::move(result);
|
273
282
|
}
|
274
283
|
|
@@ -0,0 +1,365 @@
|
|
1
|
+
#include "duckdb/planner/binder.hpp"
|
2
|
+
#include "duckdb/parser/tableref/pivotref.hpp"
|
3
|
+
#include "duckdb/parser/tableref/subqueryref.hpp"
|
4
|
+
#include "duckdb/parser/query_node/select_node.hpp"
|
5
|
+
#include "duckdb/parser/expression/case_expression.hpp"
|
6
|
+
#include "duckdb/parser/expression/columnref_expression.hpp"
|
7
|
+
#include "duckdb/parser/expression/comparison_expression.hpp"
|
8
|
+
#include "duckdb/parser/expression/conjunction_expression.hpp"
|
9
|
+
#include "duckdb/parser/expression/constant_expression.hpp"
|
10
|
+
#include "duckdb/parser/expression/function_expression.hpp"
|
11
|
+
#include "duckdb/planner/query_node/bound_select_node.hpp"
|
12
|
+
#include "duckdb/parser/expression/star_expression.hpp"
|
13
|
+
#include "duckdb/common/types/value_map.hpp"
|
14
|
+
#include "duckdb/parser/parsed_expression_iterator.hpp"
|
15
|
+
#include "duckdb/parser/expression/operator_expression.hpp"
|
16
|
+
#include "duckdb/planner/tableref/bound_subqueryref.hpp"
|
17
|
+
|
18
|
+
namespace duckdb {
|
19
|
+
|
20
|
+
static void ConstructPivots(PivotRef &ref, idx_t pivot_idx, vector<unique_ptr<ParsedExpression>> &pivot_expressions,
|
21
|
+
unique_ptr<ParsedExpression> current_expr = nullptr,
|
22
|
+
const string ¤t_name = string()) {
|
23
|
+
auto &pivot = ref.pivots[pivot_idx];
|
24
|
+
bool last_pivot = pivot_idx + 1 == ref.pivots.size();
|
25
|
+
for (auto &entry : pivot.entries) {
|
26
|
+
unique_ptr<ParsedExpression> expr = current_expr ? current_expr->Copy() : nullptr;
|
27
|
+
string name = entry.alias;
|
28
|
+
D_ASSERT(entry.values.size() == pivot.names.size());
|
29
|
+
for (idx_t v = 0; v < entry.values.size(); v++) {
|
30
|
+
auto &value = entry.values[v];
|
31
|
+
auto column_ref = make_unique<ColumnRefExpression>(pivot.names[v]);
|
32
|
+
auto constant_value = make_unique<ConstantExpression>(value);
|
33
|
+
auto comp_expr = make_unique<ComparisonExpression>(ExpressionType::COMPARE_NOT_DISTINCT_FROM,
|
34
|
+
std::move(column_ref), std::move(constant_value));
|
35
|
+
if (expr) {
|
36
|
+
expr = make_unique<ConjunctionExpression>(ExpressionType::CONJUNCTION_AND, std::move(expr),
|
37
|
+
std::move(comp_expr));
|
38
|
+
} else {
|
39
|
+
expr = std::move(comp_expr);
|
40
|
+
}
|
41
|
+
if (entry.alias.empty()) {
|
42
|
+
if (name.empty()) {
|
43
|
+
name = value.ToString();
|
44
|
+
} else {
|
45
|
+
name += "_" + value.ToString();
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
if (!current_name.empty()) {
|
50
|
+
name = current_name + "_" + name;
|
51
|
+
}
|
52
|
+
if (last_pivot) {
|
53
|
+
// construct the aggregates
|
54
|
+
for (auto &aggr : ref.aggregates) {
|
55
|
+
auto copy = aggr->Copy();
|
56
|
+
auto &function = (FunctionExpression &)*copy;
|
57
|
+
// add the filter and alias to the aggregate function
|
58
|
+
function.filter = expr->Copy();
|
59
|
+
if (ref.aggregates.size() > 1) {
|
60
|
+
// if there are multiple aggregates specified we add the name of the aggregate as well
|
61
|
+
function.alias = name + "_" + function.GetName();
|
62
|
+
} else {
|
63
|
+
function.alias = name;
|
64
|
+
}
|
65
|
+
pivot_expressions.push_back(std::move(copy));
|
66
|
+
}
|
67
|
+
} else {
|
68
|
+
// need to recurse
|
69
|
+
ConstructPivots(ref, pivot_idx + 1, pivot_expressions, std::move(expr), name);
|
70
|
+
}
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
static void ExtractPivotExpressions(ParsedExpression &expr, case_insensitive_set_t &handled_columns) {
|
75
|
+
if (expr.type == ExpressionType::COLUMN_REF) {
|
76
|
+
auto &child_colref = (ColumnRefExpression &)expr;
|
77
|
+
if (child_colref.IsQualified()) {
|
78
|
+
throw BinderException("PIVOT expression cannot contain qualified columns");
|
79
|
+
}
|
80
|
+
handled_columns.insert(child_colref.GetColumnName());
|
81
|
+
}
|
82
|
+
ParsedExpressionIterator::EnumerateChildren(
|
83
|
+
expr, [&](ParsedExpression &child) { ExtractPivotExpressions(child, handled_columns); });
|
84
|
+
}
|
85
|
+
|
86
|
+
unique_ptr<SelectNode> Binder::BindPivot(PivotRef &ref, vector<unique_ptr<ParsedExpression>> all_columns) {
|
87
|
+
const static idx_t PIVOT_EXPRESSION_LIMIT = 10000;
|
88
|
+
// keep track of the columns by which we pivot/aggregate
|
89
|
+
// any columns which are not pivoted/aggregated on are added to the GROUP BY clause
|
90
|
+
case_insensitive_set_t handled_columns;
|
91
|
+
// parse the aggregate, and extract the referenced columns from the aggregate
|
92
|
+
for (auto &aggr : ref.aggregates) {
|
93
|
+
if (aggr->type != ExpressionType::FUNCTION) {
|
94
|
+
throw BinderException(FormatError(*aggr, "Pivot expression must be an aggregate"));
|
95
|
+
}
|
96
|
+
if (aggr->HasSubquery()) {
|
97
|
+
throw BinderException(FormatError(*aggr, "Pivot expression cannot contain subqueries"));
|
98
|
+
}
|
99
|
+
if (aggr->IsWindow()) {
|
100
|
+
throw BinderException(FormatError(*aggr, "Pivot expression cannot contain window functions"));
|
101
|
+
}
|
102
|
+
ExtractPivotExpressions(*aggr, handled_columns);
|
103
|
+
}
|
104
|
+
value_set_t pivots;
|
105
|
+
|
106
|
+
// now handle the pivots
|
107
|
+
auto select_node = make_unique<SelectNode>();
|
108
|
+
// first add all pivots to the set of handled columns, and check for duplicates
|
109
|
+
idx_t total_pivots = 1;
|
110
|
+
for (auto &pivot : ref.pivots) {
|
111
|
+
if (!pivot.pivot_enum.empty()) {
|
112
|
+
auto type = Catalog::GetType(context, INVALID_CATALOG, INVALID_SCHEMA, pivot.pivot_enum);
|
113
|
+
if (type.id() != LogicalTypeId::ENUM) {
|
114
|
+
throw BinderException(
|
115
|
+
FormatError(ref, StringUtil::Format("Pivot must reference an ENUM type: \"%s\" is of type \"%s\"",
|
116
|
+
pivot.pivot_enum, type.ToString())));
|
117
|
+
}
|
118
|
+
auto enum_size = EnumType::GetSize(type);
|
119
|
+
for (idx_t i = 0; i < enum_size; i++) {
|
120
|
+
auto enum_value = EnumType::GetValue(Value::ENUM(i, type));
|
121
|
+
PivotColumnEntry entry;
|
122
|
+
entry.values.emplace_back(enum_value);
|
123
|
+
entry.alias = std::move(enum_value);
|
124
|
+
pivot.entries.push_back(std::move(entry));
|
125
|
+
}
|
126
|
+
}
|
127
|
+
total_pivots *= pivot.entries.size();
|
128
|
+
// add the pivoted column to the columns that have been handled
|
129
|
+
for (auto &pivot_name : pivot.names) {
|
130
|
+
handled_columns.insert(pivot_name);
|
131
|
+
}
|
132
|
+
value_set_t pivots;
|
133
|
+
for (auto &entry : pivot.entries) {
|
134
|
+
D_ASSERT(!entry.star_expr);
|
135
|
+
Value val;
|
136
|
+
if (entry.values.size() == 1) {
|
137
|
+
val = entry.values[0];
|
138
|
+
} else {
|
139
|
+
val = Value::LIST(LogicalType::VARCHAR, entry.values);
|
140
|
+
}
|
141
|
+
if (pivots.find(val) != pivots.end()) {
|
142
|
+
throw BinderException(FormatError(
|
143
|
+
ref, StringUtil::Format("The value \"%s\" was specified multiple times in the IN clause",
|
144
|
+
val.ToString())));
|
145
|
+
}
|
146
|
+
if (entry.values.size() != pivot.names.size()) {
|
147
|
+
throw ParserException("PIVOT IN list - inconsistent amount of rows - expected %d but got %d",
|
148
|
+
pivot.names.size(), entry.values.size());
|
149
|
+
}
|
150
|
+
pivots.insert(val);
|
151
|
+
}
|
152
|
+
}
|
153
|
+
if (total_pivots >= PIVOT_EXPRESSION_LIMIT) {
|
154
|
+
throw BinderException("Pivot column limit of %llu exceeded", PIVOT_EXPRESSION_LIMIT);
|
155
|
+
}
|
156
|
+
// now construct the actual aggregates
|
157
|
+
// note that we construct a cross-product of all pivots
|
158
|
+
// we do this recursively
|
159
|
+
vector<unique_ptr<ParsedExpression>> pivot_expressions;
|
160
|
+
ConstructPivots(ref, 0, pivot_expressions);
|
161
|
+
|
162
|
+
if (ref.groups.empty()) {
|
163
|
+
// if rows are not specified any columns that are not pivoted/aggregated on are added to the GROUP BY clause
|
164
|
+
for (auto &entry : all_columns) {
|
165
|
+
if (entry->type != ExpressionType::COLUMN_REF) {
|
166
|
+
throw InternalException("Unexpected child of pivot source - not a ColumnRef");
|
167
|
+
}
|
168
|
+
auto &columnref = (ColumnRefExpression &)*entry;
|
169
|
+
if (handled_columns.find(columnref.GetColumnName()) == handled_columns.end()) {
|
170
|
+
// not handled - add to grouping set
|
171
|
+
select_node->groups.group_expressions.push_back(
|
172
|
+
make_unique<ConstantExpression>(Value::INTEGER(select_node->select_list.size() + 1)));
|
173
|
+
select_node->select_list.push_back(std::move(entry));
|
174
|
+
}
|
175
|
+
}
|
176
|
+
} else {
|
177
|
+
// if rows are specified only the columns mentioned in rows are added as groups
|
178
|
+
for (auto &row : ref.groups) {
|
179
|
+
select_node->groups.group_expressions.push_back(
|
180
|
+
make_unique<ConstantExpression>(Value::INTEGER(select_node->select_list.size() + 1)));
|
181
|
+
select_node->select_list.push_back(make_unique<ColumnRefExpression>(row));
|
182
|
+
}
|
183
|
+
}
|
184
|
+
// add the pivot expressions to the select list
|
185
|
+
for (auto &pivot_expr : pivot_expressions) {
|
186
|
+
select_node->select_list.push_back(std::move(pivot_expr));
|
187
|
+
}
|
188
|
+
return select_node;
|
189
|
+
}
|
190
|
+
|
191
|
+
unique_ptr<SelectNode> Binder::BindUnpivot(Binder &child_binder, PivotRef &ref,
|
192
|
+
vector<unique_ptr<ParsedExpression>> all_columns,
|
193
|
+
unique_ptr<ParsedExpression> &where_clause) {
|
194
|
+
D_ASSERT(ref.groups.empty());
|
195
|
+
D_ASSERT(ref.pivots.size() == 1);
|
196
|
+
|
197
|
+
unique_ptr<ParsedExpression> expr;
|
198
|
+
auto select_node = make_unique<SelectNode>();
|
199
|
+
|
200
|
+
// handle the pivot
|
201
|
+
auto &unpivot = ref.pivots[0];
|
202
|
+
|
203
|
+
// handle star expressions in any entries
|
204
|
+
vector<PivotColumnEntry> new_entries;
|
205
|
+
for (auto &entry : unpivot.entries) {
|
206
|
+
if (entry.star_expr) {
|
207
|
+
D_ASSERT(entry.values.empty());
|
208
|
+
vector<unique_ptr<ParsedExpression>> star_columns;
|
209
|
+
child_binder.ExpandStarExpression(std::move(entry.star_expr), star_columns);
|
210
|
+
|
211
|
+
for (auto &col : star_columns) {
|
212
|
+
if (col->type != ExpressionType::COLUMN_REF) {
|
213
|
+
throw InternalException("Unexpected child of unpivot star - not a ColumnRef");
|
214
|
+
}
|
215
|
+
auto &columnref = (ColumnRefExpression &)*col;
|
216
|
+
PivotColumnEntry new_entry;
|
217
|
+
new_entry.values.emplace_back(columnref.GetColumnName());
|
218
|
+
new_entry.alias = columnref.GetColumnName();
|
219
|
+
new_entries.push_back(std::move(new_entry));
|
220
|
+
}
|
221
|
+
} else {
|
222
|
+
new_entries.push_back(std::move(entry));
|
223
|
+
}
|
224
|
+
}
|
225
|
+
unpivot.entries = std::move(new_entries);
|
226
|
+
|
227
|
+
case_insensitive_set_t handled_columns;
|
228
|
+
case_insensitive_map_t<string> name_map;
|
229
|
+
for (auto &entry : unpivot.entries) {
|
230
|
+
for (auto &value : entry.values) {
|
231
|
+
handled_columns.insert(value.ToString());
|
232
|
+
}
|
233
|
+
}
|
234
|
+
|
235
|
+
for (auto &col_expr : all_columns) {
|
236
|
+
if (col_expr->type != ExpressionType::COLUMN_REF) {
|
237
|
+
throw InternalException("Unexpected child of pivot source - not a ColumnRef");
|
238
|
+
}
|
239
|
+
auto &columnref = (ColumnRefExpression &)*col_expr;
|
240
|
+
auto &column_name = columnref.GetColumnName();
|
241
|
+
auto entry = handled_columns.find(column_name);
|
242
|
+
if (entry == handled_columns.end()) {
|
243
|
+
// not handled - add to the set of regularly selected columns
|
244
|
+
select_node->select_list.push_back(std::move(col_expr));
|
245
|
+
} else {
|
246
|
+
name_map[column_name] = column_name;
|
247
|
+
handled_columns.erase(entry);
|
248
|
+
}
|
249
|
+
}
|
250
|
+
if (!handled_columns.empty()) {
|
251
|
+
for (auto &entry : handled_columns) {
|
252
|
+
throw BinderException("Column \"%s\" referenced in UNPIVOT but no matching entry was found in the table",
|
253
|
+
entry);
|
254
|
+
}
|
255
|
+
}
|
256
|
+
vector<Value> unpivot_names;
|
257
|
+
for (auto &entry : unpivot.entries) {
|
258
|
+
string generated_name;
|
259
|
+
for (auto &val : entry.values) {
|
260
|
+
auto name_entry = name_map.find(val.ToString());
|
261
|
+
if (name_entry == name_map.end()) {
|
262
|
+
throw InternalException("Unpivot - could not find column name in name map");
|
263
|
+
}
|
264
|
+
if (!generated_name.empty()) {
|
265
|
+
generated_name += "_";
|
266
|
+
}
|
267
|
+
generated_name += name_entry->second;
|
268
|
+
}
|
269
|
+
unpivot_names.emplace_back(!entry.alias.empty() ? entry.alias : generated_name);
|
270
|
+
}
|
271
|
+
vector<vector<unique_ptr<ParsedExpression>>> unpivot_expressions;
|
272
|
+
for (idx_t v_idx = 0; v_idx < unpivot.entries[0].values.size(); v_idx++) {
|
273
|
+
vector<unique_ptr<ParsedExpression>> expressions;
|
274
|
+
for (auto &entry : unpivot.entries) {
|
275
|
+
expressions.push_back(make_unique<ColumnRefExpression>(entry.values[v_idx].ToString()));
|
276
|
+
}
|
277
|
+
unpivot_expressions.push_back(std::move(expressions));
|
278
|
+
}
|
279
|
+
|
280
|
+
// construct the UNNEST expression for the set of names (constant)
|
281
|
+
auto unpivot_list = Value::LIST(LogicalType::VARCHAR, std::move(unpivot_names));
|
282
|
+
auto unpivot_name_expr = make_unique<ConstantExpression>(std::move(unpivot_list));
|
283
|
+
vector<unique_ptr<ParsedExpression>> unnest_name_children;
|
284
|
+
unnest_name_children.push_back(std::move(unpivot_name_expr));
|
285
|
+
auto unnest_name_expr = make_unique<FunctionExpression>("unnest", std::move(unnest_name_children));
|
286
|
+
unnest_name_expr->alias = unpivot.names[0];
|
287
|
+
select_node->select_list.push_back(std::move(unnest_name_expr));
|
288
|
+
|
289
|
+
// construct the UNNEST expression for the set of unpivoted columns
|
290
|
+
if (ref.unpivot_names.size() != unpivot_expressions.size()) {
|
291
|
+
throw BinderException("UNPIVOT name count mismatch - got %d names but %d expressions", ref.unpivot_names.size(),
|
292
|
+
unpivot_expressions.size());
|
293
|
+
}
|
294
|
+
for (idx_t i = 0; i < unpivot_expressions.size(); i++) {
|
295
|
+
auto list_expr = make_unique<FunctionExpression>("list_value", std::move(unpivot_expressions[i]));
|
296
|
+
vector<unique_ptr<ParsedExpression>> unnest_val_children;
|
297
|
+
unnest_val_children.push_back(std::move(list_expr));
|
298
|
+
auto unnest_val_expr = make_unique<FunctionExpression>("unnest", std::move(unnest_val_children));
|
299
|
+
auto unnest_name = i < ref.column_name_alias.size() ? ref.column_name_alias[i] : ref.unpivot_names[i];
|
300
|
+
unnest_val_expr->alias = unnest_name;
|
301
|
+
select_node->select_list.push_back(std::move(unnest_val_expr));
|
302
|
+
if (!ref.include_nulls) {
|
303
|
+
// if we are running with EXCLUDE NULLS we need to add an IS NOT NULL filter
|
304
|
+
auto colref = make_unique<ColumnRefExpression>(unnest_name);
|
305
|
+
auto filter = make_unique<OperatorExpression>(ExpressionType::OPERATOR_IS_NOT_NULL, std::move(colref));
|
306
|
+
if (where_clause) {
|
307
|
+
where_clause = make_unique<ConjunctionExpression>(ExpressionType::CONJUNCTION_AND,
|
308
|
+
std::move(where_clause), std::move(filter));
|
309
|
+
} else {
|
310
|
+
where_clause = std::move(filter);
|
311
|
+
}
|
312
|
+
}
|
313
|
+
}
|
314
|
+
return select_node;
|
315
|
+
}
|
316
|
+
|
317
|
+
unique_ptr<BoundTableRef> Binder::Bind(PivotRef &ref) {
|
318
|
+
if (!ref.source) {
|
319
|
+
throw InternalException("Pivot without a source!?");
|
320
|
+
}
|
321
|
+
|
322
|
+
// bind the source of the pivot
|
323
|
+
auto child_binder = Binder::CreateBinder(context, this);
|
324
|
+
auto from_table = child_binder->Bind(*ref.source);
|
325
|
+
|
326
|
+
// figure out the set of column names that are in the source of the pivot
|
327
|
+
vector<unique_ptr<ParsedExpression>> all_columns;
|
328
|
+
child_binder->ExpandStarExpression(make_unique<StarExpression>(), all_columns);
|
329
|
+
|
330
|
+
unique_ptr<SelectNode> select_node;
|
331
|
+
unique_ptr<ParsedExpression> where_clause;
|
332
|
+
if (!ref.aggregates.empty()) {
|
333
|
+
select_node = BindPivot(ref, std::move(all_columns));
|
334
|
+
} else {
|
335
|
+
select_node = BindUnpivot(*child_binder, ref, std::move(all_columns), where_clause);
|
336
|
+
}
|
337
|
+
// bind the generated select node
|
338
|
+
auto bound_select_node = child_binder->BindSelectNode(*select_node, std::move(from_table));
|
339
|
+
auto root_index = bound_select_node->GetRootIndex();
|
340
|
+
BoundQueryNode *bound_select_ptr = bound_select_node.get();
|
341
|
+
|
342
|
+
unique_ptr<BoundTableRef> result;
|
343
|
+
MoveCorrelatedExpressions(*child_binder);
|
344
|
+
result = make_unique<BoundSubqueryRef>(std::move(child_binder), std::move(bound_select_node));
|
345
|
+
auto alias = ref.alias.empty() ? "__unnamed_pivot" : ref.alias;
|
346
|
+
SubqueryRef subquery_ref(nullptr, alias);
|
347
|
+
subquery_ref.column_name_alias = std::move(ref.column_name_alias);
|
348
|
+
if (where_clause) {
|
349
|
+
// if a WHERE clause was provided - bind a subquery holding the WHERE clause
|
350
|
+
// we need to bind a new subquery here because the WHERE clause has to be applied AFTER the unnest
|
351
|
+
child_binder = Binder::CreateBinder(context, this);
|
352
|
+
child_binder->bind_context.AddSubquery(root_index, subquery_ref.alias, subquery_ref, *bound_select_ptr);
|
353
|
+
auto where_query = make_unique<SelectNode>();
|
354
|
+
where_query->select_list.push_back(make_unique<StarExpression>());
|
355
|
+
where_query->where_clause = std::move(where_clause);
|
356
|
+
bound_select_node = child_binder->BindSelectNode(*where_query, std::move(result));
|
357
|
+
bound_select_ptr = bound_select_node.get();
|
358
|
+
root_index = bound_select_node->GetRootIndex();
|
359
|
+
result = make_unique<BoundSubqueryRef>(std::move(child_binder), std::move(bound_select_node));
|
360
|
+
}
|
361
|
+
bind_context.AddSubquery(root_index, subquery_ref.alias, subquery_ref, *bound_select_ptr);
|
362
|
+
return result;
|
363
|
+
}
|
364
|
+
|
365
|
+
} // namespace duckdb
|