|
39 | 39 | #include "miscadmin.h" |
40 | 40 | #include "optimizer/clauses.h" |
41 | 41 | #include "optimizer/planner.h" |
| 42 | +#include "optimizer/prep.h" |
42 | 43 | #include "nodes/makefuncs.h" |
| 44 | +#include "parser/parse_coerce.h" |
| 45 | +#include "parser/parse_collate.h" |
| 46 | +#include "parser/parse_expr.h" |
43 | 47 | #include "parser/parse_relation.h" |
44 | 48 | #include "port/pg_bswap.h" |
45 | 49 | #include "rewrite/rewriteHandler.h" |
@@ -149,6 +153,7 @@ typedef struct CopyStateData |
149 | 153 | bool convert_selectively; /* do selective binary conversion? */ |
150 | 154 | List *convert_select; /* list of column names (can be NIL) */ |
151 | 155 | bool *convert_select_flags; /* per-column CSV/TEXT CS flags */ |
| 156 | + Node *whereClause; /* WHERE condition (or NULL) */ |
152 | 157 |
|
153 | 158 | /* these are just for error messages, see CopyFromErrorCallback */ |
154 | 159 | const char *cur_relname; /* table name for error messages */ |
@@ -179,6 +184,7 @@ typedef struct CopyStateData |
179 | 184 | ExprState **defexprs; /* array of default att expressions */ |
180 | 185 | bool volatile_defexprs; /* is any of defexprs volatile? */ |
181 | 186 | List *range_table; |
| 187 | + ExprState *qualexpr; |
182 | 188 |
|
183 | 189 | TransitionCaptureState *transition_capture; |
184 | 190 |
|
@@ -800,6 +806,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt, |
800 | 806 | Relation rel; |
801 | 807 | Oid relid; |
802 | 808 | RawStmt *query = NULL; |
| 809 | + Node *whereClause = NULL; |
803 | 810 |
|
804 | 811 | /* |
805 | 812 | * Disallow COPY to/from file or program except to users with the |
@@ -853,6 +860,26 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt, |
853 | 860 | NULL, false, false); |
854 | 861 | rte->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT); |
855 | 862 |
|
| 863 | + if (stmt->whereClause) |
| 864 | + { |
| 865 | + /* add rte to column namespace */ |
| 866 | + addRTEtoQuery(pstate, rte, false, true, true); |
| 867 | + |
| 868 | + /* Transform the raw expression tree */ |
| 869 | + whereClause = transformExpr(pstate, stmt->whereClause, EXPR_KIND_COPY_WHERE); |
| 870 | + |
| 871 | + /* Make sure it yields a boolean result. */ |
| 872 | + whereClause = coerce_to_boolean(pstate, whereClause, "WHERE"); |
| 873 | + |
| 874 | + /* we have to fix its collations too */ |
| 875 | + assign_expr_collations(pstate, whereClause); |
| 876 | + |
| 877 | + whereClause = eval_const_expressions(NULL, whereClause); |
| 878 | + |
| 879 | + whereClause = (Node *) canonicalize_qual((Expr *) whereClause, false); |
| 880 | + whereClause = (Node *) make_ands_implicit((Expr *) whereClause); |
| 881 | + } |
| 882 | + |
856 | 883 | tupDesc = RelationGetDescr(rel); |
857 | 884 | attnums = CopyGetAttnums(tupDesc, rel, stmt->attlist); |
858 | 885 | foreach(cur, attnums) |
@@ -1001,6 +1028,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt, |
1001 | 1028 |
|
1002 | 1029 | cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program, |
1003 | 1030 | NULL, stmt->attlist, stmt->options); |
| 1031 | + cstate->whereClause = whereClause; |
1004 | 1032 | *processed = CopyFrom(cstate); /* copy from file to database */ |
1005 | 1033 | EndCopyFrom(cstate); |
1006 | 1034 | } |
@@ -2535,6 +2563,10 @@ CopyFrom(CopyState cstate) |
2535 | 2563 | if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) |
2536 | 2564 | proute = ExecSetupPartitionTupleRouting(NULL, cstate->rel); |
2537 | 2565 |
|
| 2566 | + if (cstate->whereClause) |
| 2567 | + cstate->qualexpr = ExecInitQual(castNode(List, cstate->whereClause), |
| 2568 | + &mtstate->ps); |
| 2569 | + |
2538 | 2570 | /* |
2539 | 2571 | * It's more efficient to prepare a bunch of tuples for insertion, and |
2540 | 2572 | * insert them in one heap_multi_insert() call, than call heap_insert() |
@@ -2580,6 +2612,16 @@ CopyFrom(CopyState cstate) |
2580 | 2612 | */ |
2581 | 2613 | insertMethod = CIM_SINGLE; |
2582 | 2614 | } |
| 2615 | + else if (cstate->whereClause != NULL || |
| 2616 | + contain_volatile_functions(cstate->whereClause)) |
| 2617 | + { |
| 2618 | + /* |
| 2619 | + * Can't support multi-inserts if there are any volatile funcation |
| 2620 | + * expressions in WHERE clause. Similarly to the trigger case above, |
| 2621 | + * such expressions may query the table we're inserting into. |
| 2622 | + */ |
| 2623 | + insertMethod = CIM_SINGLE; |
| 2624 | + } |
2583 | 2625 | else |
2584 | 2626 | { |
2585 | 2627 | /* |
@@ -2683,6 +2725,13 @@ CopyFrom(CopyState cstate) |
2683 | 2725 | slot = myslot; |
2684 | 2726 | ExecStoreHeapTuple(tuple, slot, false); |
2685 | 2727 |
|
| 2728 | + if (cstate->whereClause) |
| 2729 | + { |
| 2730 | + econtext->ecxt_scantuple = myslot; |
| 2731 | + if (!ExecQual(cstate->qualexpr, econtext)) |
| 2732 | + continue; |
| 2733 | + } |
| 2734 | + |
2686 | 2735 | /* Determine the partition to heap_insert the tuple into */ |
2687 | 2736 | if (proute) |
2688 | 2737 | { |
|
0 commit comments