@ -869,25 +869,27 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
attr_num - FirstLowInvalidHeapAttributeNumber ) ;
attr_num - FirstLowInvalidHeapAttributeNumber ) ;
}
}
/* Process ON CONFLICT, if any. */
if ( stmt - > onConflictClause )
qry - > onConflict = transformOnConflictClause ( pstate ,
stmt - > onConflictClause ) ;
/*
/*
* If we have a RETURNING clause , we need to add the target relation to
* If we have any clauses yet to process , set the query namespace to
* the query namespace before processing it , so that Var references in
* contain only the target relation , removing any entries added in a
* RETURNING will work . Also , remove any namespace entries added in a
* sub - SELECT or VALUES list .
* sub - SELECT or VALUES list .
*/
*/
if ( stmt - > returningList )
if ( stmt - > onConflictClause | | stmt - > returningList )
{
{
pstate - > p_namespace = NIL ;
pstate - > p_namespace = NIL ;
addNSItemToQuery ( pstate , pstate - > p_target_nsitem ,
addNSItemToQuery ( pstate , pstate - > p_target_nsitem ,
false , true , true ) ;
false , true , true ) ;
}
/* Process ON CONFLICT, if any. */
if ( stmt - > onConflictClause )
qry - > onConflict = transformOnConflictClause ( pstate ,
stmt - > onConflictClause ) ;
/* Process RETURNING, if any. */
if ( stmt - > returningList )
qry - > returningList = transformReturningList ( pstate ,
qry - > returningList = transformReturningList ( pstate ,
stmt - > returningList ) ;
stmt - > returningList ) ;
}
/* done building the range table and jointree */
/* done building the range table and jointree */
qry - > rtable = pstate - > p_rtable ;
qry - > rtable = pstate - > p_rtable ;
@ -1014,6 +1016,7 @@ static OnConflictExpr *
transformOnConflictClause ( ParseState * pstate ,
transformOnConflictClause ( ParseState * pstate ,
OnConflictClause * onConflictClause )
OnConflictClause * onConflictClause )
{
{
ParseNamespaceItem * exclNSItem = NULL ;
List * arbiterElems ;
List * arbiterElems ;
Node * arbiterWhere ;
Node * arbiterWhere ;
Oid arbiterConstraint ;
Oid arbiterConstraint ;
@ -1023,29 +1026,17 @@ transformOnConflictClause(ParseState *pstate,
List * exclRelTlist = NIL ;
List * exclRelTlist = NIL ;
OnConflictExpr * result ;
OnConflictExpr * result ;
/* Process the arbiter clause, ON CONFLICT ON (...) */
/*
transformOnConflictArbiter ( pstate , onConflictClause , & arbiterElems ,
* If this is ON CONFLICT . . . UPDATE , first create the range table entry
& arbiterWhere , & arbiterConstraint ) ;
* for the EXCLUDED pseudo relation , so that that will be present while
* processing arbiter expressions . ( You can ' t actually reference it from
/* Process DO UPDATE */
* there , but this provides a useful error message if you try . )
*/
if ( onConflictClause - > action = = ONCONFLICT_UPDATE )
if ( onConflictClause - > action = = ONCONFLICT_UPDATE )
{
{
Relation targetrel = pstate - > p_target_relation ;
Relation targetrel = pstate - > p_target_relation ;
ParseNamespaceItem * exclNSItem ;
RangeTblEntry * exclRte ;
RangeTblEntry * exclRte ;
/*
* All INSERT expressions have been parsed , get ready for potentially
* existing SET statements that need to be processed like an UPDATE .
*/
pstate - > p_is_insert = false ;
/*
* Add range table entry for the EXCLUDED pseudo relation . relkind is
* set to composite to signal that we ' re not dealing with an actual
* relation , and no permission checks are required on it . ( We ' ll
* check the actual target relation , instead . )
*/
exclNSItem = addRangeTableEntryForRelation ( pstate ,
exclNSItem = addRangeTableEntryForRelation ( pstate ,
targetrel ,
targetrel ,
RowExclusiveLock ,
RowExclusiveLock ,
@ -1054,6 +1045,11 @@ transformOnConflictClause(ParseState *pstate,
exclRte = exclNSItem - > p_rte ;
exclRte = exclNSItem - > p_rte ;
exclRelIndex = exclNSItem - > p_rtindex ;
exclRelIndex = exclNSItem - > p_rtindex ;
/*
* relkind is set to composite to signal that we ' re not dealing with
* an actual relation , and no permission checks are required on it .
* ( We ' ll check the actual target relation , instead . )
*/
exclRte - > relkind = RELKIND_COMPOSITE_TYPE ;
exclRte - > relkind = RELKIND_COMPOSITE_TYPE ;
exclRte - > requiredPerms = 0 ;
exclRte - > requiredPerms = 0 ;
/* other permissions fields in exclRte are already empty */
/* other permissions fields in exclRte are already empty */
@ -1061,14 +1057,27 @@ transformOnConflictClause(ParseState *pstate,
/* Create EXCLUDED rel's targetlist for use by EXPLAIN */
/* Create EXCLUDED rel's targetlist for use by EXPLAIN */
exclRelTlist = BuildOnConflictExcludedTargetlist ( targetrel ,
exclRelTlist = BuildOnConflictExcludedTargetlist ( targetrel ,
exclRelIndex ) ;
exclRelIndex ) ;
}
/* Process the arbiter clause, ON CONFLICT ON (...) */
transformOnConflictArbiter ( pstate , onConflictClause , & arbiterElems ,
& arbiterWhere , & arbiterConstraint ) ;
/* Process DO UPDATE */
if ( onConflictClause - > action = = ONCONFLICT_UPDATE )
{
/*
* Expressions in the UPDATE targetlist need to be handled like UPDATE
* not INSERT . We don ' t need to save / restore this because all INSERT
* expressions have been parsed already .
*/
pstate - > p_is_insert = false ;
/*
/*
* Add EXCLUDED and the target RTE to the namespace , so that they can
* Add the EXCLUDED pseudo relation to the query namespace , making it
* be used in the UPDATE subexpressions .
* available in the UPDATE subexpressions .
*/
*/
addNSItemToQuery ( pstate , exclNSItem , false , true , true ) ;
addNSItemToQuery ( pstate , exclNSItem , false , true , true ) ;
addNSItemToQuery ( pstate , pstate - > p_target_nsitem ,
false , true , true ) ;
/*
/*
* Now transform the UPDATE subexpressions .
* Now transform the UPDATE subexpressions .
@ -1079,6 +1088,14 @@ transformOnConflictClause(ParseState *pstate,
onConflictWhere = transformWhereClause ( pstate ,
onConflictWhere = transformWhereClause ( pstate ,
onConflictClause - > whereClause ,
onConflictClause - > whereClause ,
EXPR_KIND_WHERE , " WHERE " ) ;
EXPR_KIND_WHERE , " WHERE " ) ;
/*
* Remove the EXCLUDED pseudo relation from the query namespace , since
* it ' s not supposed to be available in RETURNING . ( Maybe someday we
* could allow that , and drop this step . )
*/
Assert ( ( ParseNamespaceItem * ) llast ( pstate - > p_namespace ) = = exclNSItem ) ;
pstate - > p_namespace = list_delete_last ( pstate - > p_namespace ) ;
}
}
/* Finally, build ON CONFLICT DO [NOTHING | UPDATE] expression */
/* Finally, build ON CONFLICT DO [NOTHING | UPDATE] expression */