diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 3201476..66ae54e 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -279,12 +279,12 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0"; /* non-export function prototypes */ -static CopyState BeginCopy(bool is_from, Relation rel, Node *raw_query, +static CopyState BeginCopy(bool is_from, Relation rel, Node *raw_query, ParamListInfo params, const char *queryString, const Oid queryRelId, List *attnamelist, List *options); static void EndCopy(CopyState cstate); static void ClosePipeToProgram(CopyState cstate); -static CopyState BeginCopyTo(Relation rel, Node *query, const char *queryString, +static CopyState BeginCopyTo(Relation rel, Node *query, ParamListInfo params, const char *queryString, const Oid queryRelId, const char *filename, bool is_program, List *attnamelist, List *options); static void EndCopyTo(CopyState cstate); @@ -787,7 +787,7 @@ CopyLoadRawBuf(CopyState cstate) * the table or the specifically requested columns. */ Oid -DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) +DoCopy(const CopyStmt *stmt, const char *queryString, ParamListInfo params, uint64 *processed) { CopyState cstate; bool is_from = stmt->is_from; @@ -944,7 +944,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) } else { - cstate = BeginCopyTo(rel, query, queryString, relid, + cstate = BeginCopyTo(rel, query, params, queryString, relid, stmt->filename, stmt->is_program, stmt->attlist, stmt->options); *processed = DoCopyTo(cstate); /* copy from database to file */ @@ -1321,6 +1321,7 @@ static CopyState BeginCopy(bool is_from, Relation rel, Node *raw_query, + ParamListInfo params, const char *queryString, const Oid queryRelId, List *attnamelist, @@ -1391,11 +1392,16 @@ BeginCopy(bool is_from, * function and is executed repeatedly. (See also the same hack in * DECLARE CURSOR and PREPARE.) XXX FIXME someday. */ - rewritten = pg_analyze_and_rewrite((Node *) copyObject(raw_query), - queryString, NULL, 0); + if (!IsA(raw_query,List)) + { + rewritten = pg_analyze_and_rewrite((Node *) copyObject(raw_query), + queryString, NULL, 0); + } + else + rewritten = (List *) raw_query; /* check that we got back something we can work with */ - if (rewritten == NIL) + if (rewritten == NIL || linitial(rewritten) == NIL) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -1453,7 +1459,7 @@ BeginCopy(bool is_from, } /* plan the query */ - plan = pg_plan_query(query, 0, NULL); + plan = pg_plan_query(query, 0, params); /* * With row level security and a user using "COPY relation TO", we @@ -1495,7 +1501,7 @@ BeginCopy(bool is_from, cstate->queryDesc = CreateQueryDesc(plan, queryString, GetActiveSnapshot(), InvalidSnapshot, - dest, NULL, 0); + dest, params, 0); /* * Call ExecutorStart to prepare the plan for execution. @@ -1682,6 +1688,7 @@ EndCopy(CopyState cstate) static CopyState BeginCopyTo(Relation rel, Node *query, + ParamListInfo params, const char *queryString, const Oid queryRelId, const char *filename, @@ -1725,7 +1732,7 @@ BeginCopyTo(Relation rel, RelationGetRelationName(rel)))); } - cstate = BeginCopy(false, rel, query, queryString, queryRelId, attnamelist, + cstate = BeginCopy(false, rel, query, params, queryString, queryRelId, attnamelist, options); oldcontext = MemoryContextSwitchTo(cstate->copycontext); @@ -2670,7 +2677,7 @@ BeginCopyFrom(Relation rel, MemoryContext oldcontext; bool volatile_defexprs; - cstate = BeginCopy(true, rel, NULL, NULL, InvalidOid, attnamelist, options); + cstate = BeginCopy(true, rel, NULL, NULL, NULL, InvalidOid, attnamelist, options); oldcontext = MemoryContextSwitchTo(cstate->copycontext); /* Initialize state variables */ diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 29c8c4e..a6d9dd6 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -299,6 +299,13 @@ transformStmt(ParseState *pstate, Node *parseTree) result = makeNode(Query); result->commandType = CMD_UTILITY; result->utilityStmt = (Node *) parseTree; + + if (IsA(parseTree,CopyStmt) + && ((CopyStmt *)parseTree)->query != NIL) + { + CopyStmt *stmt = (CopyStmt *) parseTree; + stmt->query = transformStmt(pstate, stmt->query); + } break; } @@ -343,6 +350,7 @@ analyze_requires_snapshot(Node *parseTree) case T_ExplainStmt: case T_CreateTableAsStmt: + case T_CopyStmt: /* yes, because we must analyze the contained statement */ result = true; break; diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 68811f1..4a18fec 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -739,6 +739,16 @@ pg_rewrite_query(Query *query) if (query->commandType == CMD_UTILITY) { + if (query->utilityStmt + && IsA(query->utilityStmt,CopyStmt) + && ((CopyStmt *)(query->utilityStmt))->query) + { + CopyStmt *stmt = (CopyStmt *)(query->utilityStmt); + Assert(IsA(stmt->query,Query)); + stmt->query = (Node *) QueryRewrite((Query *)(stmt->query)); + if (stmt->query == (Node *) NIL) + stmt->query = (Node *) list_make1(NIL); + } /* don't rewrite utilities, just dump 'em into result list */ querytree_list = list_make1(query); } diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index ac50c2a..a7deead 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -540,7 +540,7 @@ standard_ProcessUtility(Node *parsetree, { uint64 processed; - DoCopy((CopyStmt *) parsetree, queryString, &processed); + DoCopy((CopyStmt *) parsetree, queryString, params, &processed); if (completionTag) snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "COPY " UINT64_FORMAT, processed); diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h index 314d1f7..44c2c66 100644 --- a/src/include/commands/copy.h +++ b/src/include/commands/copy.h @@ -21,7 +21,7 @@ /* CopyStateData is private in commands/copy.c */ typedef struct CopyStateData *CopyState; -extern Oid DoCopy(const CopyStmt *stmt, const char *queryString, +extern Oid DoCopy(const CopyStmt *stmt, const char *queryString, ParamListInfo params, uint64 *processed); extern void ProcessCopyOptions(CopyState cstate, bool is_from, List *options);