1
0
mirror of https://github.com/postgres/postgres.git synced 2025-05-12 16:21:30 +03:00

Support PlaceHolderVars in MERGE actions.

preprocess_targetlist thought PHVs couldn't appear here.
It was mistaken, as per report from Önder Kalacı.

Surveying other pull_var_clause calls, I noted no similar errors,
but I did notice that qual_is_pushdown_safe's assertion about
!contain_window_function was pointless, because the following
pull_var_clause call would complain about them anyway.  In HEAD
only, remove the redundant Assert and improve the commentary.

Discussion: https://postgr.es/m/CACawEhUuum-gC_2S3sXLTcsk7bUSPSHOD+g1ZpfKaDK-KKPPWA@mail.gmail.com
This commit is contained in:
Tom Lane 2023-03-15 11:59:18 -04:00
parent a0137388cb
commit e3ac85014e
4 changed files with 41 additions and 14 deletions

View File

@ -3839,18 +3839,16 @@ qual_is_pushdown_safe(Query *subquery, Index rti, RestrictInfo *rinfo,
contain_leaked_vars(qual)) contain_leaked_vars(qual))
return false; return false;
/*
* It would be unsafe to push down window function calls, but at least for
* the moment we could never see any in a qual anyhow. (The same applies
* to aggregates, which we check for in pull_var_clause below.)
*/
Assert(!contain_window_function(qual));
/* /*
* Examine all Vars used in clause. Since it's a restriction clause, all * Examine all Vars used in clause. Since it's a restriction clause, all
* such Vars must refer to subselect output columns ... unless this is * such Vars must refer to subselect output columns ... unless this is
* part of a LATERAL subquery, in which case there could be lateral * part of a LATERAL subquery, in which case there could be lateral
* references. * references.
*
* By omitting the relevant flags, this also gives us a cheap sanity check
* that no aggregates or window functions appear in the qual. Those would
* be unsafe to push down, but at least for the moment we could never see
* any in a qual anyhow.
*/ */
vars = pull_var_clause(qual, PVC_INCLUDE_PLACEHOLDERS); vars = pull_var_clause(qual, PVC_INCLUDE_PLACEHOLDERS);
foreach(vl, vars) foreach(vl, vars)

View File

@ -155,17 +155,15 @@ preprocess_targetlist(PlannerInfo *root)
extract_update_targetlist_colnos(action->targetList); extract_update_targetlist_colnos(action->targetList);
/* /*
* Add resjunk entries for any Vars used in each action's * Add resjunk entries for any Vars and PlaceHolderVars used in
* targetlist and WHEN condition that belong to relations other * each action's targetlist and WHEN condition that belong to
* than target. Note that aggregates, window functions and * relations other than the target. We don't expect to see any
* placeholder vars are not possible anywhere in MERGE's WHEN * aggregates or window functions here.
* clauses. (PHVs may be added later, but they don't concern us
* here.)
*/ */
vars = pull_var_clause((Node *) vars = pull_var_clause((Node *)
list_concat_copy((List *) action->qual, list_concat_copy((List *) action->qual,
action->targetList), action->targetList),
0); PVC_INCLUDE_PLACEHOLDERS);
foreach(l2, vars) foreach(l2, vars)
{ {
Var *var = (Var *) lfirst(l2); Var *var = (Var *) lfirst(l2);

View File

@ -1905,6 +1905,27 @@ SELECT * FROM cj_target;
2 | 320 | initial source2 300 2 | 320 | initial source2 300
(4 rows) (4 rows)
-- try it with an outer join and PlaceHolderVar
MERGE INTO cj_target t
USING (SELECT *, 'join input'::text AS phv FROM cj_source1) fj
FULL JOIN cj_source2 fj2 ON fj.scat = fj2.sid2 * 10
ON t.tid = fj.scat
WHEN NOT MATCHED THEN
INSERT (tid, balance, val) VALUES (fj.scat, fj.delta, fj.phv);
SELECT * FROM cj_target;
tid | balance | val
-----+---------+----------------------------------
3 | 400 | initial source2 updated by merge
1 | 220 | initial source2 200
1 | 110 | initial source2 200
2 | 320 | initial source2 300
10 | 100 | join input
10 | 400 | join input
20 | 200 | join input
20 | 300 | join input
| |
(9 rows)
ALTER TABLE cj_source1 RENAME COLUMN sid1 TO sid; ALTER TABLE cj_source1 RENAME COLUMN sid1 TO sid;
ALTER TABLE cj_source2 RENAME COLUMN sid2 TO sid; ALTER TABLE cj_source2 RENAME COLUMN sid2 TO sid;
TRUNCATE cj_target; TRUNCATE cj_target;

View File

@ -1225,6 +1225,16 @@ WHEN MATCHED THEN
SELECT * FROM cj_target; SELECT * FROM cj_target;
-- try it with an outer join and PlaceHolderVar
MERGE INTO cj_target t
USING (SELECT *, 'join input'::text AS phv FROM cj_source1) fj
FULL JOIN cj_source2 fj2 ON fj.scat = fj2.sid2 * 10
ON t.tid = fj.scat
WHEN NOT MATCHED THEN
INSERT (tid, balance, val) VALUES (fj.scat, fj.delta, fj.phv);
SELECT * FROM cj_target;
ALTER TABLE cj_source1 RENAME COLUMN sid1 TO sid; ALTER TABLE cj_source1 RENAME COLUMN sid1 TO sid;
ALTER TABLE cj_source2 RENAME COLUMN sid2 TO sid; ALTER TABLE cj_source2 RENAME COLUMN sid2 TO sid;