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:
parent
49ad32d5d9
commit
631d749007
@ -3011,16 +3011,9 @@ CommandComplete (B)
|
|||||||
<literal>INSERT <replaceable>oid</replaceable>
|
<literal>INSERT <replaceable>oid</replaceable>
|
||||||
<replaceable>rows</replaceable></literal>, where
|
<replaceable>rows</replaceable></literal>, where
|
||||||
<replaceable>rows</replaceable> is the number of rows
|
<replaceable>rows</replaceable> is the number of rows
|
||||||
inserted. However, if and only if <literal>ON CONFLICT
|
inserted. <replaceable>oid</replaceable> is the object ID
|
||||||
UPDATE</> is specified, then the tag is <literal>UPSERT
|
of the inserted row if <replaceable>rows</replaceable> is 1
|
||||||
<replaceable>oid</replaceable>
|
and the target table has OIDs;
|
||||||
<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;
|
|
||||||
otherwise <replaceable>oid</replaceable> is 0.
|
otherwise <replaceable>oid</replaceable> is 0.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
@ -497,20 +497,13 @@ INSERT INTO <replaceable class="PARAMETER">table_name</replaceable> [ AS <replac
|
|||||||
<screen>
|
<screen>
|
||||||
INSERT <replaceable>oid</replaceable> <replaceable class="parameter">count</replaceable>
|
INSERT <replaceable>oid</replaceable> <replaceable class="parameter">count</replaceable>
|
||||||
</screen>
|
</screen>
|
||||||
However, in the event of an <literal>ON CONFLICT DO UPDATE</> clause
|
The <replaceable class="parameter">count</replaceable> is the
|
||||||
(but <emphasis>not</emphasis> in the event of an <literal>ON
|
number of rows inserted or updated. If <replaceable
|
||||||
CONFLICT DO NOTHING</> clause), the command tag reports the number of
|
class="parameter">count</replaceable> is exactly one, and the
|
||||||
rows inserted or updated together, of the form
|
target table has OIDs, then <replaceable
|
||||||
<screen>
|
class="parameter">oid</replaceable> is the <acronym>OID</acronym>
|
||||||
UPSERT <replaceable>oid</replaceable> <replaceable class="parameter">count</replaceable>
|
assigned to the inserted row. The single row must have been
|
||||||
</screen>
|
inserted rather than updated. Otherwise <replaceable
|
||||||
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
|
|
||||||
class="parameter">oid</replaceable> is zero.
|
class="parameter">oid</replaceable> is zero.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
@ -81,7 +81,6 @@ _copyPlannedStmt(const PlannedStmt *from)
|
|||||||
COPY_SCALAR_FIELD(queryId);
|
COPY_SCALAR_FIELD(queryId);
|
||||||
COPY_SCALAR_FIELD(hasReturning);
|
COPY_SCALAR_FIELD(hasReturning);
|
||||||
COPY_SCALAR_FIELD(hasModifyingCTE);
|
COPY_SCALAR_FIELD(hasModifyingCTE);
|
||||||
COPY_SCALAR_FIELD(isUpsert);
|
|
||||||
COPY_SCALAR_FIELD(canSetTag);
|
COPY_SCALAR_FIELD(canSetTag);
|
||||||
COPY_SCALAR_FIELD(transientPlan);
|
COPY_SCALAR_FIELD(transientPlan);
|
||||||
COPY_NODE_FIELD(planTree);
|
COPY_NODE_FIELD(planTree);
|
||||||
|
@ -243,7 +243,6 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node)
|
|||||||
WRITE_UINT_FIELD(queryId);
|
WRITE_UINT_FIELD(queryId);
|
||||||
WRITE_BOOL_FIELD(hasReturning);
|
WRITE_BOOL_FIELD(hasReturning);
|
||||||
WRITE_BOOL_FIELD(hasModifyingCTE);
|
WRITE_BOOL_FIELD(hasModifyingCTE);
|
||||||
WRITE_BOOL_FIELD(isUpsert);
|
|
||||||
WRITE_BOOL_FIELD(canSetTag);
|
WRITE_BOOL_FIELD(canSetTag);
|
||||||
WRITE_BOOL_FIELD(transientPlan);
|
WRITE_BOOL_FIELD(transientPlan);
|
||||||
WRITE_NODE_FIELD(planTree);
|
WRITE_NODE_FIELD(planTree);
|
||||||
|
@ -261,8 +261,6 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
|
|||||||
result->queryId = parse->queryId;
|
result->queryId = parse->queryId;
|
||||||
result->hasReturning = (parse->returningList != NIL);
|
result->hasReturning = (parse->returningList != NIL);
|
||||||
result->hasModifyingCTE = parse->hasModifyingCTE;
|
result->hasModifyingCTE = parse->hasModifyingCTE;
|
||||||
result->isUpsert =
|
|
||||||
(parse->onConflict && parse->onConflict->action == ONCONFLICT_UPDATE);
|
|
||||||
result->canSetTag = parse->canSetTag;
|
result->canSetTag = parse->canSetTag;
|
||||||
result->transientPlan = glob->transientPlan;
|
result->transientPlan = glob->transientPlan;
|
||||||
result->planTree = top_plan;
|
result->planTree = top_plan;
|
||||||
|
@ -202,14 +202,8 @@ ProcessQuery(PlannedStmt *plan,
|
|||||||
lastOid = queryDesc->estate->es_lastoid;
|
lastOid = queryDesc->estate->es_lastoid;
|
||||||
else
|
else
|
||||||
lastOid = InvalidOid;
|
lastOid = InvalidOid;
|
||||||
if (plan->isUpsert)
|
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
||||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
"INSERT %u %u", lastOid, queryDesc->estate->es_processed);
|
||||||
"UPSERT %u %u",
|
|
||||||
lastOid, queryDesc->estate->es_processed);
|
|
||||||
else
|
|
||||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
|
||||||
"INSERT %u %u",
|
|
||||||
lastOid, queryDesc->estate->es_processed);
|
|
||||||
break;
|
break;
|
||||||
case CMD_UPDATE:
|
case CMD_UPDATE:
|
||||||
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
|
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,
|
* 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,
|
* 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
|
* 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"
|
* one row was updated. See QueryRewrite(), step 3, for details.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
if (completionTag && completionTag[0] == '\0')
|
if (completionTag && completionTag[0] == '\0')
|
||||||
{
|
{
|
||||||
@ -1375,8 +1366,6 @@ PortalRunMulti(Portal portal, bool isTopLevel,
|
|||||||
sprintf(completionTag, "SELECT 0 0");
|
sprintf(completionTag, "SELECT 0 0");
|
||||||
else if (strcmp(completionTag, "INSERT") == 0)
|
else if (strcmp(completionTag, "INSERT") == 0)
|
||||||
strcpy(completionTag, "INSERT 0 0");
|
strcpy(completionTag, "INSERT 0 0");
|
||||||
else if (strcmp(completionTag, "UPSERT") == 0)
|
|
||||||
strcpy(completionTag, "UPSERT 0 0");
|
|
||||||
else if (strcmp(completionTag, "UPDATE") == 0)
|
else if (strcmp(completionTag, "UPDATE") == 0)
|
||||||
strcpy(completionTag, "UPDATE 0");
|
strcpy(completionTag, "UPDATE 0");
|
||||||
else if (strcmp(completionTag, "DELETE") == 0)
|
else if (strcmp(completionTag, "DELETE") == 0)
|
||||||
|
@ -894,12 +894,9 @@ PrintQueryResults(PGresult *results)
|
|||||||
success = StoreQueryTuple(results);
|
success = StoreQueryTuple(results);
|
||||||
else
|
else
|
||||||
success = PrintQueryTuples(results);
|
success = PrintQueryTuples(results);
|
||||||
/*
|
/* if it's INSERT/UPDATE/DELETE RETURNING, also print status */
|
||||||
* if it's INSERT/UPSERT/UPDATE/DELETE RETURNING, also print status
|
|
||||||
*/
|
|
||||||
cmdstatus = PQcmdStatus(results);
|
cmdstatus = PQcmdStatus(results);
|
||||||
if (strncmp(cmdstatus, "INSERT", 6) == 0 ||
|
if (strncmp(cmdstatus, "INSERT", 6) == 0 ||
|
||||||
strncmp(cmdstatus, "UPSERT", 6) == 0 ||
|
|
||||||
strncmp(cmdstatus, "UPDATE", 6) == 0 ||
|
strncmp(cmdstatus, "UPDATE", 6) == 0 ||
|
||||||
strncmp(cmdstatus, "DELETE", 6) == 0)
|
strncmp(cmdstatus, "DELETE", 6) == 0)
|
||||||
PrintQueryStatus(results);
|
PrintQueryStatus(results);
|
||||||
|
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 201505191
|
#define CATALOG_VERSION_NO 201505231
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -45,8 +45,6 @@ typedef struct PlannedStmt
|
|||||||
|
|
||||||
bool hasModifyingCTE; /* has insert|update|delete in WITH? */
|
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 canSetTag; /* do I set the command result tag? */
|
||||||
|
|
||||||
bool transientPlan; /* redo plan when TransactionXmin changes? */
|
bool transientPlan; /* redo plan when TransactionXmin changes? */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user