1 | #include "duckdb/planner/expression_binder/check_binder.hpp" |
2 | |
3 | #include "duckdb/planner/table_binding.hpp" |
4 | #include "duckdb/parser/expression/columnref_expression.hpp" |
5 | #include "duckdb/planner/expression/bound_reference_expression.hpp" |
6 | |
7 | namespace duckdb { |
8 | |
9 | CheckBinder::CheckBinder(Binder &binder, ClientContext &context, string table_p, const ColumnList &columns, |
10 | physical_index_set_t &bound_columns) |
11 | : ExpressionBinder(binder, context), table(std::move(table_p)), columns(columns), bound_columns(bound_columns) { |
12 | target_type = LogicalType::INTEGER; |
13 | } |
14 | |
15 | BindResult CheckBinder::BindExpression(unique_ptr<ParsedExpression> &expr_ptr, idx_t depth, bool root_expression) { |
16 | auto &expr = *expr_ptr; |
17 | switch (expr.GetExpressionClass()) { |
18 | case ExpressionClass::WINDOW: |
19 | return BindResult("window functions are not allowed in check constraints" ); |
20 | case ExpressionClass::SUBQUERY: |
21 | return BindResult("cannot use subquery in check constraint" ); |
22 | case ExpressionClass::COLUMN_REF: |
23 | return BindCheckColumn(expr&: expr.Cast<ColumnRefExpression>()); |
24 | default: |
25 | return ExpressionBinder::BindExpression(expr_ptr, depth); |
26 | } |
27 | } |
28 | |
29 | string CheckBinder::UnsupportedAggregateMessage() { |
30 | return "aggregate functions are not allowed in check constraints" ; |
31 | } |
32 | |
33 | BindResult ExpressionBinder::BindQualifiedColumnName(ColumnRefExpression &colref, const string &table_name) { |
34 | idx_t struct_start = 0; |
35 | if (colref.column_names[0] == table_name) { |
36 | struct_start++; |
37 | } |
38 | auto result = make_uniq_base<ParsedExpression, ColumnRefExpression>(args&: colref.column_names.back()); |
39 | for (idx_t i = struct_start; i + 1 < colref.column_names.size(); i++) { |
40 | result = CreateStructExtract(base: std::move(result), field_name: colref.column_names[i]); |
41 | } |
42 | return BindExpression(expr_ptr&: result, depth: 0); |
43 | } |
44 | |
45 | BindResult CheckBinder::BindCheckColumn(ColumnRefExpression &colref) { |
46 | |
47 | // if this is a lambda parameters, then we temporarily add a BoundLambdaRef, |
48 | // which we capture and remove later |
49 | if (lambda_bindings) { |
50 | for (idx_t i = 0; i < lambda_bindings->size(); i++) { |
51 | if (colref.GetColumnName() == (*lambda_bindings)[i].dummy_name) { |
52 | // FIXME: support lambdas in CHECK constraints |
53 | // FIXME: like so: return (*lambda_bindings)[i].Bind(colref, i, depth); |
54 | throw NotImplementedException("Lambda functions are currently not supported in CHECK constraints." ); |
55 | } |
56 | } |
57 | } |
58 | |
59 | if (colref.column_names.size() > 1) { |
60 | return BindQualifiedColumnName(colref, table_name: table); |
61 | } |
62 | if (!columns.ColumnExists(name: colref.column_names[0])) { |
63 | throw BinderException("Table does not contain column %s referenced in check constraint!" , |
64 | colref.column_names[0]); |
65 | } |
66 | auto &col = columns.GetColumn(name: colref.column_names[0]); |
67 | if (col.Generated()) { |
68 | auto bound_expression = col.GeneratedExpression().Copy(); |
69 | return BindExpression(expr_ptr&: bound_expression, depth: 0, root_expression: false); |
70 | } |
71 | bound_columns.insert(x: col.Physical()); |
72 | D_ASSERT(col.StorageOid() != DConstants::INVALID_INDEX); |
73 | return BindResult(make_uniq<BoundReferenceExpression>(args: col.Type(), args: col.StorageOid())); |
74 | } |
75 | |
76 | } // namespace duckdb |
77 | |