Remove the new UPSERT command tag and use INSERT instead.

Previously, INSERT with ON CONFLICT DO UPDATE specified used a new
command tag -- UPSERT.  It was introduced out of concern that INSERT as
a command tag would be a misrepresentation for ON CONFLICT DO UPDATE, as
some affected rows may actually have been updated.

Alvaro Herrera noticed that the implementation of that new command tag
was incomplete; in subsequent discussion we concluded that having it
doesn't provide benefits that are in line with the compatibility breaks
it requires.

Catversion bump due to the removal of PlannedStmt->isUpsert.

Author: Peter Geoghegan
Discussion: 20150520215816.GI5885@postgresql.org
This commit is contained in:
Andres Freund 2015-05-23 00:49:27 +02:00
parent 49ad32d5d9
commit 631d749007
9 changed files with 15 additions and 49 deletions

View File

@ -3011,16 +3011,9 @@ CommandComplete (B)
<literal>INSERT <replaceable>oid</replaceable>
<replaceable>rows</replaceable></literal>, where
<replaceable>rows</replaceable> is the number of rows
inserted. However, if and only if <literal>ON CONFLICT
UPDATE</> is specified, then the tag is <literal>UPSERT
<replaceable>oid</replaceable>
<replaceable>rows</replaceable></literal>, where
<replaceable>rows</replaceable> is the number of rows inserted
<emphasis>or updated</emphasis>.
<replaceable>oid</replaceable> is the object ID of the
inserted row if <replaceable>rows</replaceable> is 1 and the
target table has OIDs, and (for the <literal>UPSERT</literal>
tag), the row was actually inserted rather than updated;
inserted. <replaceable>oid</replaceable> is the object ID
of the inserted row if <replaceable>rows</replaceable> is 1
and the target table has OIDs;
otherwise <replaceable>oid</replaceable> is 0.
</para>

View File

@ -497,20 +497,13 @@ INSERT INTO <replaceable class="PARAMETER">table_name</replaceable> [ AS <replac
<screen>
INSERT <replaceable>oid</replaceable> <replaceable class="parameter">count</replaceable>
</screen>
However, in the event of an <literal>ON CONFLICT DO UPDATE</> clause
(but <emphasis>not</emphasis> in the event of an <literal>ON
CONFLICT DO NOTHING</> clause), the command tag reports the number of
rows inserted or updated together, of the form
<screen>
UPSERT <replaceable>oid</replaceable> <replaceable class="parameter">count</replaceable>
</screen>
The <replaceable class="parameter">count</replaceable> is the number
of rows inserted. If <replaceable class="parameter">count</replaceable>
is exactly one, and the target table has OIDs, then
<replaceable class="parameter">oid</replaceable> is the
<acronym>OID</acronym>
assigned to the inserted row (but not if there is only a single
updated row). Otherwise <replaceable
The <replaceable class="parameter">count</replaceable> is the
number of rows inserted or updated. If <replaceable
class="parameter">count</replaceable> is exactly one, and the
target table has OIDs, then <replaceable
class="parameter">oid</replaceable> is the <acronym>OID</acronym>
assigned to the inserted row. The single row must have been
inserted rather than updated. Otherwise <replaceable
class="parameter">oid</replaceable> is zero.
</para>

View File

@ -81,7 +81,6 @@ _copyPlannedStmt(const PlannedStmt *from)
COPY_SCALAR_FIELD(queryId);
COPY_SCALAR_FIELD(hasReturning);
COPY_SCALAR_FIELD(hasModifyingCTE);
COPY_SCALAR_FIELD(isUpsert);
COPY_SCALAR_FIELD(canSetTag);
COPY_SCALAR_FIELD(transientPlan);
COPY_NODE_FIELD(planTree);

View File

@ -243,7 +243,6 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node)
WRITE_UINT_FIELD(queryId);
WRITE_BOOL_FIELD(hasReturning);
WRITE_BOOL_FIELD(hasModifyingCTE);
WRITE_BOOL_FIELD(isUpsert);
WRITE_BOOL_FIELD(canSetTag);
WRITE_BOOL_FIELD(transientPlan);
WRITE_NODE_FIELD(planTree);

View File

@ -261,8 +261,6 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
result->queryId = parse->queryId;
result->hasReturning = (parse->returningList != NIL);
result->hasModifyingCTE = parse->hasModifyingCTE;
result->isUpsert =
(parse->onConflict && parse->onConflict->action == ONCONFLICT_UPDATE);
result->canSetTag = parse->canSetTag;
result->transientPlan = glob->transientPlan;
result->planTree = top_plan;

View File

@ -202,14 +202,8 @@ ProcessQuery(PlannedStmt *plan,
lastOid = queryDesc->estate->es_lastoid;
else
lastOid = InvalidOid;
if (plan->isUpsert)
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
"UPSERT %u %u",
lastOid, queryDesc->estate->es_processed);
else
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
"INSERT %u %u",
lastOid, queryDesc->estate->es_processed);
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
"INSERT %u %u", lastOid, queryDesc->estate->es_processed);
break;
case CMD_UPDATE:
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
@ -1362,10 +1356,7 @@ PortalRunMulti(Portal portal, bool isTopLevel,
* 0" here because technically there is no query of the matching tag type,
* and printing a non-zero count for a different query type seems wrong,
* e.g. an INSERT that does an UPDATE instead should not print "0 1" if
* one row was updated (unless the ON CONFLICT DO UPDATE, or "UPSERT"
* variant of INSERT was used to update the row, where it's logically a
* direct effect of the top level command). See QueryRewrite(), step 3,
* for details.
* one row was updated. See QueryRewrite(), step 3, for details.
*/
if (completionTag && completionTag[0] == '\0')
{
@ -1375,8 +1366,6 @@ PortalRunMulti(Portal portal, bool isTopLevel,
sprintf(completionTag, "SELECT 0 0");
else if (strcmp(completionTag, "INSERT") == 0)
strcpy(completionTag, "INSERT 0 0");
else if (strcmp(completionTag, "UPSERT") == 0)
strcpy(completionTag, "UPSERT 0 0");
else if (strcmp(completionTag, "UPDATE") == 0)
strcpy(completionTag, "UPDATE 0");
else if (strcmp(completionTag, "DELETE") == 0)

View File

@ -894,12 +894,9 @@ PrintQueryResults(PGresult *results)
success = StoreQueryTuple(results);
else
success = PrintQueryTuples(results);
/*
* if it's INSERT/UPSERT/UPDATE/DELETE RETURNING, also print status
*/
/* if it's INSERT/UPDATE/DELETE RETURNING, also print status */
cmdstatus = PQcmdStatus(results);
if (strncmp(cmdstatus, "INSERT", 6) == 0 ||
strncmp(cmdstatus, "UPSERT", 6) == 0 ||
strncmp(cmdstatus, "UPDATE", 6) == 0 ||
strncmp(cmdstatus, "DELETE", 6) == 0)
PrintQueryStatus(results);

View File

@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201505191
#define CATALOG_VERSION_NO 201505231
#endif

View File

@ -45,8 +45,6 @@ typedef struct PlannedStmt
bool hasModifyingCTE; /* has insert|update|delete in WITH? */
bool isUpsert; /* is it insert ... ON CONFLICT UPDATE? */
bool canSetTag; /* do I set the command result tag? */
bool transientPlan; /* redo plan when TransactionXmin changes? */