aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/gram.y92
-rw-r--r--src/backend/parser/parse_merge.c86
2 files changed, 75 insertions, 103 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 1592b58bb47..177906e083d 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -241,6 +241,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
PartitionSpec *partspec;
PartitionBoundSpec *partboundspec;
RoleSpec *rolespec;
+ MergeWhenClause *mergewhen;
}
%type <node> stmt schema_stmt
@@ -400,6 +401,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
TriggerTransitions TriggerReferencing
publication_name_list
vacuum_relation_list opt_vacuum_relation_list
+ merge_values_clause
%type <list> group_by_list
%type <node> group_by_item empty_grouping_set rollup_clause cube_clause
@@ -460,6 +462,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <istmt> insert_rest
%type <infer> opt_conf_expr
%type <onconflict> opt_on_conflict
+%type <mergewhen> merge_insert merge_update merge_delete
%type <vsetstmt> generic_set set_rest set_rest_more generic_reset reset_rest
SetResetClause FunctionSetResetClause
@@ -587,7 +590,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <node> merge_when_clause opt_merge_when_and_condition
%type <list> merge_when_list
-%type <node> merge_update merge_delete merge_insert
/*
* Non-keyword token types. These are hard-wired into the "flex" lexer.
@@ -11116,7 +11118,7 @@ MergeStmt:
m->relation = $4;
m->source_relation = $6;
m->join_condition = $8;
- m->mergeActionList = $9;
+ m->mergeWhenClauses = $9;
$$ = (Node *)m;
}
@@ -11131,45 +11133,37 @@ merge_when_list:
merge_when_clause:
WHEN MATCHED opt_merge_when_and_condition THEN merge_update
{
- MergeAction *m = makeNode(MergeAction);
+ $5->matched = true;
+ $5->commandType = CMD_UPDATE;
+ $5->condition = $3;
- m->matched = true;
- m->commandType = CMD_UPDATE;
- m->condition = $3;
- m->stmt = $5;
-
- $$ = (Node *)m;
+ $$ = (Node *) $5;
}
| WHEN MATCHED opt_merge_when_and_condition THEN merge_delete
{
- MergeAction *m = makeNode(MergeAction);
+ MergeWhenClause *m = makeNode(MergeWhenClause);
m->matched = true;
m->commandType = CMD_DELETE;
m->condition = $3;
- m->stmt = $5;
$$ = (Node *)m;
}
| WHEN NOT MATCHED opt_merge_when_and_condition THEN merge_insert
{
- MergeAction *m = makeNode(MergeAction);
+ $6->matched = false;
+ $6->commandType = CMD_INSERT;
+ $6->condition = $4;
- m->matched = false;
- m->commandType = CMD_INSERT;
- m->condition = $4;
- m->stmt = $6;
-
- $$ = (Node *)m;
+ $$ = (Node *) $6;
}
| WHEN NOT MATCHED opt_merge_when_and_condition THEN DO NOTHING
{
- MergeAction *m = makeNode(MergeAction);
+ MergeWhenClause *m = makeNode(MergeWhenClause);
m->matched = false;
m->commandType = CMD_NOTHING;
m->condition = $4;
- m->stmt = NULL;
$$ = (Node *)m;
}
@@ -11181,65 +11175,63 @@ opt_merge_when_and_condition:
;
merge_delete:
- DELETE_P
- {
- DeleteStmt *n = makeNode(DeleteStmt);
- $$ = (Node *)n;
- }
+ DELETE_P { $$ = NULL; }
;
merge_update:
UPDATE SET set_clause_list
{
- UpdateStmt *n = makeNode(UpdateStmt);
+ MergeWhenClause *n = makeNode(MergeWhenClause);
n->targetList = $3;
- $$ = (Node *)n;
+ $$ = n;
}
;
merge_insert:
- INSERT values_clause
+ INSERT merge_values_clause
{
- InsertStmt *n = makeNode(InsertStmt);
+ MergeWhenClause *n = makeNode(MergeWhenClause);
n->cols = NIL;
- n->selectStmt = $2;
-
- $$ = (Node *)n;
+ n->values = $2;
+ $$ = n;
}
- | INSERT OVERRIDING override_kind VALUE_P values_clause
+ | INSERT OVERRIDING override_kind VALUE_P merge_values_clause
{
- InsertStmt *n = makeNode(InsertStmt);
+ MergeWhenClause *n = makeNode(MergeWhenClause);
n->cols = NIL;
n->override = $3;
- n->selectStmt = $5;
-
- $$ = (Node *)n;
+ n->values = $5;
+ $$ = n;
}
- | INSERT '(' insert_column_list ')' values_clause
+ | INSERT '(' insert_column_list ')' merge_values_clause
{
- InsertStmt *n = makeNode(InsertStmt);
+ MergeWhenClause *n = makeNode(MergeWhenClause);
n->cols = $3;
- n->selectStmt = $5;
-
- $$ = (Node *)n;
+ n->values = $5;
+ $$ = n;
}
- | INSERT '(' insert_column_list ')' OVERRIDING override_kind VALUE_P values_clause
+ | INSERT '(' insert_column_list ')' OVERRIDING override_kind VALUE_P merge_values_clause
{
- InsertStmt *n = makeNode(InsertStmt);
+ MergeWhenClause *n = makeNode(MergeWhenClause);
n->cols = $3;
n->override = $6;
- n->selectStmt = $8;
-
- $$ = (Node *)n;
+ n->values = $8;
+ $$ = n;
}
| INSERT DEFAULT VALUES
{
- InsertStmt *n = makeNode(InsertStmt);
+ MergeWhenClause *n = makeNode(MergeWhenClause);
n->cols = NIL;
- n->selectStmt = NULL;
+ n->values = NIL;
+ $$ = n;
+ }
+ ;
- $$ = (Node *)n;
+merge_values_clause:
+ VALUES '(' expr_list ')'
+ {
+ $$ = $3;
}
;
diff --git a/src/backend/parser/parse_merge.c b/src/backend/parser/parse_merge.c
index eb4c615ce1c..722cb23b86c 100644
--- a/src/backend/parser/parse_merge.c
+++ b/src/backend/parser/parse_merge.c
@@ -33,8 +33,8 @@
static int transformMergeJoinClause(ParseState *pstate, Node *merge,
List **mergeSourceTargetList);
-static void setNamespaceForMergeAction(ParseState *pstate,
- MergeAction *action);
+static void setNamespaceForMergeWhen(ParseState *pstate,
+ MergeWhenClause *mergeWhenClause);
static void setNamespaceVisibilityForRTE(List *namespace, RangeTblEntry *rte,
bool rel_visible,
bool cols_visible);
@@ -138,7 +138,7 @@ transformMergeJoinClause(ParseState *pstate, Node *merge,
* that columns can be referenced unqualified from these relations.
*/
static void
-setNamespaceForMergeAction(ParseState *pstate, MergeAction *action)
+setNamespaceForMergeWhen(ParseState *pstate, MergeWhenClause *mergeWhenClause)
{
RangeTblEntry *targetRelRTE,
*sourceRelRTE;
@@ -152,7 +152,7 @@ setNamespaceForMergeAction(ParseState *pstate, MergeAction *action)
*/
sourceRelRTE = rt_fetch(list_length(pstate->p_rtable) - 1, pstate->p_rtable);
- switch (action->commandType)
+ switch (mergeWhenClause->commandType)
{
case CMD_INSERT:
@@ -198,6 +198,7 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
bool is_terminal[2];
JoinExpr *joinexpr;
RangeTblEntry *resultRelRTE, *mergeRelRTE;
+ List *mergeActionList;
/* There can't be any outer WITH to worry about */
Assert(pstate->p_ctenamespace == NIL);
@@ -222,43 +223,18 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
*/
is_terminal[0] = false;
is_terminal[1] = false;
- foreach(l, stmt->mergeActionList)
+ foreach(l, stmt->mergeWhenClauses)
{
- MergeAction *action = (MergeAction *) lfirst(l);
- int when_type = (action->matched ? 0 : 1);
+ MergeWhenClause *mergeWhenClause = (MergeWhenClause *) lfirst(l);
+ int when_type = (mergeWhenClause->matched ? 0 : 1);
/*
* Collect action types so we can check Target permissions
*/
- switch (action->commandType)
+ switch (mergeWhenClause->commandType)
{
case CMD_INSERT:
- {
- InsertStmt *istmt = (InsertStmt *) action->stmt;
- SelectStmt *selectStmt = (SelectStmt *) istmt->selectStmt;
-
- /*
- * The grammar allows attaching ORDER BY, LIMIT, FOR
- * UPDATE, or WITH to a VALUES clause and also multiple
- * VALUES clauses. If we have any of those, ERROR.
- */
- if (selectStmt && (selectStmt->valuesLists == NIL ||
- selectStmt->sortClause != NIL ||
- selectStmt->limitOffset != NULL ||
- selectStmt->limitCount != NULL ||
- selectStmt->lockingClause != NIL ||
- selectStmt->withClause != NULL))
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("SELECT not allowed in MERGE INSERT statement")));
-
- if (selectStmt && list_length(selectStmt->valuesLists) > 1)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("Multiple VALUES clauses not allowed in MERGE INSERT statement")));
-
- targetPerms |= ACL_INSERT;
- }
+ targetPerms |= ACL_INSERT;
break;
case CMD_UPDATE:
targetPerms |= ACL_UPDATE;
@@ -275,7 +251,7 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
/*
* Check for unreachable WHEN clauses
*/
- if (action->condition == NULL)
+ if (mergeWhenClause->condition == NULL)
is_terminal[when_type] = true;
else if (is_terminal[when_type])
ereport(ERROR,
@@ -461,15 +437,20 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
* both of those already have RTEs. There is nothing like the EXCLUDED
* pseudo-relation for INSERT ON CONFLICT.
*/
- foreach(l, stmt->mergeActionList)
+ mergeActionList = NIL;
+ foreach(l, stmt->mergeWhenClauses)
{
- MergeAction *action = (MergeAction *) lfirst(l);
+ MergeWhenClause *mergeWhenClause = (MergeWhenClause *) lfirst(l);
+ MergeAction *action = makeNode(MergeAction);
+
+ action->commandType = mergeWhenClause->commandType;
+ action->matched = mergeWhenClause->matched;
/*
* Set namespace for the specific action. This must be done before
* analyzing the WHEN quals and the action targetlisst.
*/
- setNamespaceForMergeAction(pstate, action);
+ setNamespaceForMergeWhen(pstate, mergeWhenClause);
/*
* Transform the when condition.
@@ -478,7 +459,7 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
* are evaluated separately during execution to decide which of the
* WHEN MATCHED or WHEN NOT MATCHED actions to execute.
*/
- action->qual = transformWhereClause(pstate, action->condition,
+ action->qual = transformWhereClause(pstate, mergeWhenClause->condition,
EXPR_KIND_MERGE_WHEN_AND, "WHEN");
/*
@@ -488,8 +469,6 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
{
case CMD_INSERT:
{
- InsertStmt *istmt = (InsertStmt *) action->stmt;
- SelectStmt *selectStmt = (SelectStmt *) istmt->selectStmt;
List *exprList = NIL;
ListCell *lc;
RangeTblEntry *rte;
@@ -500,13 +479,17 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
pstate->p_is_insert = true;
- icolumns = checkInsertTargets(pstate, istmt->cols, &attrnos);
+ icolumns = checkInsertTargets(pstate,
+ mergeWhenClause->cols,
+ &attrnos);
Assert(list_length(icolumns) == list_length(attrnos));
+ action->override = mergeWhenClause->override;
+
/*
* Handle INSERT much like in transformInsertStmt
*/
- if (selectStmt == NULL)
+ if (mergeWhenClause->values == NIL)
{
/*
* We have INSERT ... DEFAULT VALUES. We can handle
@@ -525,23 +508,19 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
* as the Query's targetlist, with no VALUES RTE. So
* it works just like a SELECT without any FROM.
*/
- List *valuesLists = selectStmt->valuesLists;
-
- Assert(list_length(valuesLists) == 1);
- Assert(selectStmt->intoClause == NULL);
/*
* Do basic expression transformation (same as a ROW()
* expr, but allow SetToDefault at top level)
*/
exprList = transformExpressionList(pstate,
- (List *) linitial(valuesLists),
+ mergeWhenClause->values,
EXPR_KIND_VALUES_SINGLE,
true);
/* Prepare row for assignment to target table */
exprList = transformInsertRow(pstate, exprList,
- istmt->cols,
+ mergeWhenClause->cols,
icolumns, attrnos,
false);
}
@@ -580,10 +559,9 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
break;
case CMD_UPDATE:
{
- UpdateStmt *ustmt = (UpdateStmt *) action->stmt;
-
pstate->p_is_insert = false;
- action->targetList = transformUpdateTargetList(pstate, ustmt->targetList);
+ action->targetList = transformUpdateTargetList(pstate,
+ mergeWhenClause->targetList);
}
break;
case CMD_DELETE:
@@ -595,9 +573,11 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
default:
elog(ERROR, "unknown action in MERGE WHEN clause");
}
+
+ mergeActionList = lappend(mergeActionList, action);
}
- qry->mergeActionList = stmt->mergeActionList;
+ qry->mergeActionList = mergeActionList;
/* XXX maybe later */
qry->returningList = NULL;