diff options
author | Teodor Sigaev <teodor@sigaev.ru> | 2015-11-27 19:11:22 +0300 |
---|---|---|
committer | Teodor Sigaev <teodor@sigaev.ru> | 2015-11-27 19:11:22 +0300 |
commit | 92e38182d7c8947a4ebbc1123b44f1245e232e85 (patch) | |
tree | f01ec11404a9b554cd9dc108409701e0fc86e001 /src/backend/commands/copy.c | |
parent | 0da3a9bef7ad36dc640aebf2d0482e18f21561f6 (diff) | |
download | postgresql-92e38182d7c8947a4ebbc1123b44f1245e232e85.tar.gz postgresql-92e38182d7c8947a4ebbc1123b44f1245e232e85.zip |
COPY (INSERT/UPDATE/DELETE .. RETURNING ..)
Attached is a patch for being able to do COPY (query) without a CTE.
Author: Marko Tiikkaja
Review: Michael Paquier
Diffstat (limited to 'src/backend/commands/copy.c')
-rw-r--r-- | src/backend/commands/copy.c | 59 |
1 files changed, 51 insertions, 8 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 47c6262ec2b..7dbe04e5138 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -201,7 +201,7 @@ typedef struct CopyStateData int raw_buf_len; /* total # of bytes stored */ } CopyStateData; -/* DestReceiver for COPY (SELECT) TO */ +/* DestReceiver for COPY (query) TO */ typedef struct { DestReceiver pub; /* publicly-known function pointers */ @@ -772,7 +772,8 @@ CopyLoadRawBuf(CopyState cstate) * * Either unload or reload contents of table <relation>, depending on <from>. * (<from> = TRUE means we are inserting into the table.) In the "TO" case - * we also support copying the output of an arbitrary SELECT query. + * we also support copying the output of an arbitrary SELECT, INSERT, UPDATE + * or DELETE query. * * If <pipe> is false, transfer is between the table and the file named * <filename>. Otherwise, transfer is between the table and our regular @@ -1374,11 +1375,11 @@ BeginCopy(bool is_from, Assert(!is_from); cstate->rel = NULL; - /* Don't allow COPY w/ OIDs from a select */ + /* Don't allow COPY w/ OIDs from a query */ if (cstate->oids) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("COPY (SELECT) WITH OIDS is not supported"))); + errmsg("COPY (query) WITH OIDS is not supported"))); /* * Run parse analysis and rewrite. Note this also acquires sufficient @@ -1393,9 +1394,36 @@ BeginCopy(bool is_from, rewritten = pg_analyze_and_rewrite((Node *) copyObject(raw_query), queryString, NULL, 0); - /* We don't expect more or less than one result query */ - if (list_length(rewritten) != 1) - elog(ERROR, "unexpected rewrite result"); + /* check that we got back something we can work with */ + if (rewritten == NIL) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("DO INSTEAD NOTHING rules are not supported for COPY"))); + } + else if (list_length(rewritten) > 1) + { + ListCell *lc; + + /* examine queries to determine which error message to issue */ + foreach(lc, rewritten) + { + Query *q = (Query *) lfirst(lc); + + if (q->querySource == QSRC_QUAL_INSTEAD_RULE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("conditional DO INSTEAD rules are not supported for COPY"))); + if (q->querySource == QSRC_NON_INSTEAD_RULE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("DO ALSO rules are not supported for the COPY"))); + } + + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("multi-statement DO INSTEAD rules are not supported for COPY"))); + } query = (Query *) linitial(rewritten); @@ -1406,9 +1434,24 @@ BeginCopy(bool is_from, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("COPY (SELECT INTO) is not supported"))); - Assert(query->commandType == CMD_SELECT); Assert(query->utilityStmt == NULL); + /* + * Similarly the grammar doesn't enforce the presence of a RETURNING + * clause, but this is required here. + */ + if (query->commandType != CMD_SELECT && + query->returningList == NIL) + { + Assert(query->commandType == CMD_INSERT || + query->commandType == CMD_UPDATE || + query->commandType == CMD_DELETE); + + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("COPY query must have a RETURNING clause"))); + } + /* plan the query */ plan = pg_plan_query(query, 0, NULL); |