|
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 | boolconvert_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 | constchar*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 | boolvolatile_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 | Relationrel;
|
801 | 807 | Oidrelid;
|
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 | +elseif (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 | {
|
|