Skip to content

Commit a44174c

Browse files
committed
Fix subselect.c to avoid assuming that a SubLink's testexpr references each
subquery output column exactly once left-to-right. Although this is the case in the original parser output, it might not be so after rewriting and constant-folding, as illustrated by bug #3882 from Jan Mate. Instead scan the subquery's target list to obtain needed per-column information; this is duplicative of what the parser did, but only a couple dozen lines need be copied, and we can clean up a couple of notational uglinesses. Bug was introduced in 8.2 as part of revision of SubLink representation.
1 parent 0df7717 commit a44174c

File tree

1 file changed

+107
-70
lines changed

1 file changed

+107
-70
lines changed

src/backend/optimizer/plan/subselect.c

Lines changed: 107 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.128 2008/01/01 19:45:50 momjian Exp $
10+
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.129 2008/01/17 20:35:27 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -35,8 +35,7 @@
3535
typedef struct convert_testexpr_context
3636
{
3737
PlannerInfo *root;
38-
int rtindex; /* RT index for Vars, or 0 for Params */
39-
List *righthandIds; /* accumulated list of Vars or Param IDs */
38+
List *subst_nodes; /* Nodes to substitute for Params */
4039
} convert_testexpr_context;
4140

4241
typedef struct process_sublinks_context
@@ -53,10 +52,13 @@ typedef struct finalize_primnode_context
5352
} finalize_primnode_context;
5453

5554

55+
static List *generate_subquery_params(PlannerInfo *root, List *tlist,
56+
List **paramIds);
57+
static List *generate_subquery_vars(PlannerInfo *root, List *tlist,
58+
Index varno);
5659
static Node *convert_testexpr(PlannerInfo *root,
5760
Node *testexpr,
58-
int rtindex,
59-
List **righthandIds);
61+
List *subst_nodes);
6062
static Node *convert_testexpr_mutator(Node *node,
6163
convert_testexpr_context *context);
6264
static bool subplan_is_hashable(SubLink *slink, SubPlan *node, Plan *plan);
@@ -374,10 +376,14 @@ make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
374376
else if (splan->parParam == NIL && slink->subLinkType == ROWCOMPARE_SUBLINK)
375377
{
376378
/* Adjust the Params */
379+
List *params;
380+
381+
params = generate_subquery_params(root,
382+
plan->targetlist,
383+
&splan->paramIds);
377384
result = convert_testexpr(root,
378385
testexpr,
379-
0,
380-
&splan->paramIds);
386+
params);
381387
splan->setParam = list_copy(splan->paramIds);
382388
isInitPlan = true;
383389

@@ -388,14 +394,17 @@ make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
388394
}
389395
else
390396
{
397+
List *params;
391398
List *args;
392399
ListCell *l;
393400

394401
/* Adjust the Params */
402+
params = generate_subquery_params(root,
403+
plan->targetlist,
404+
&splan->paramIds);
395405
splan->testexpr = convert_testexpr(root,
396406
testexpr,
397-
0,
398-
&splan->paramIds);
407+
params);
399408

400409
/*
401410
* We can't convert subplans of ALL_SUBLINK or ANY_SUBLINK types to
@@ -482,17 +491,76 @@ make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
482491
return result;
483492
}
484493

494+
/*
495+
* generate_subquery_params: build a list of Params representing the output
496+
* columns of a sublink's sub-select, given the sub-select's targetlist.
497+
*
498+
* We also return an integer list of the paramids of the Params.
499+
*/
500+
static List *
501+
generate_subquery_params(PlannerInfo *root, List *tlist, List **paramIds)
502+
{
503+
List *result;
504+
List *ids;
505+
ListCell *lc;
506+
507+
result = ids = NIL;
508+
foreach(lc, tlist)
509+
{
510+
TargetEntry *tent = (TargetEntry *) lfirst(lc);
511+
Param *param;
512+
513+
if (tent->resjunk)
514+
continue;
515+
516+
param = generate_new_param(root,
517+
exprType((Node *) tent->expr),
518+
exprTypmod((Node *) tent->expr));
519+
result = lappend(result, param);
520+
ids = lappend_int(ids, param->paramid);
521+
}
522+
523+
*paramIds = ids;
524+
return result;
525+
}
526+
527+
/*
528+
* generate_subquery_vars: build a list of Vars representing the output
529+
* columns of a sublink's sub-select, given the sub-select's targetlist.
530+
* The Vars have the specified varno (RTE index).
531+
*/
532+
static List *
533+
generate_subquery_vars(PlannerInfo *root, List *tlist, Index varno)
534+
{
535+
List *result;
536+
ListCell *lc;
537+
538+
result = NIL;
539+
foreach(lc, tlist)
540+
{
541+
TargetEntry *tent = (TargetEntry *) lfirst(lc);
542+
Var *var;
543+
544+
if (tent->resjunk)
545+
continue;
546+
547+
var = makeVar(varno,
548+
tent->resno,
549+
exprType((Node *) tent->expr),
550+
exprTypmod((Node *) tent->expr),
551+
0);
552+
result = lappend(result, var);
553+
}
554+
555+
return result;
556+
}
557+
485558
/*
486559
* convert_testexpr: convert the testexpr given by the parser into
487560
* actually executable form. This entails replacing PARAM_SUBLINK Params
488-
* with Params or Vars representing the results of the sub-select:
489-
*
490-
* If rtindex is 0, we build Params to represent the sub-select outputs.
491-
* The paramids of the Params created are returned in the *righthandIds list.
492-
*
493-
* If rtindex is not 0, we build Vars using that rtindex as varno. Copies
494-
* of the Var nodes are returned in *righthandIds (this is a bit of a type
495-
* cheat, but we can get away with it).
561+
* with Params or Vars representing the results of the sub-select. The
562+
* nodes to be substituted are passed in as the List result from
563+
* generate_subquery_params or generate_subquery_vars.
496564
*
497565
* The given testexpr has already been recursively processed by
498566
* process_sublinks_mutator. Hence it can no longer contain any
@@ -502,18 +570,13 @@ make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
502570
static Node *
503571
convert_testexpr(PlannerInfo *root,
504572
Node *testexpr,
505-
int rtindex,
506-
List **righthandIds)
573+
List *subst_nodes)
507574
{
508-
Node *result;
509575
convert_testexpr_context context;
510576

511577
context.root = root;
512-
context.rtindex = rtindex;
513-
context.righthandIds = NIL;
514-
result = convert_testexpr_mutator(testexpr, &context);
515-
*righthandIds = context.righthandIds;
516-
return result;
578+
context.subst_nodes = subst_nodes;
579+
return convert_testexpr_mutator(testexpr, &context);
517580
}
518581

519582
static Node *
@@ -528,47 +591,17 @@ convert_testexpr_mutator(Node *node,
528591

529592
if (param->paramkind == PARAM_SUBLINK)
530593
{
531-
/*
532-
* We expect to encounter the Params in column-number sequence. We
533-
* could handle non-sequential order if necessary, but for now
534-
* there's no need. (This is also a useful cross-check that we
535-
* aren't finding any unexpected Params.)
536-
*/
537-
if (param->paramid != list_length(context->righthandIds) + 1)
594+
if (param->paramid <= 0 ||
595+
param->paramid > list_length(context->subst_nodes))
538596
elog(ERROR, "unexpected PARAM_SUBLINK ID: %d", param->paramid);
539597

540-
if (context->rtindex)
541-
{
542-
/* Make the Var node representing the subplan's result */
543-
Var *newvar;
544-
545-
newvar = makeVar(context->rtindex,
546-
param->paramid,
547-
param->paramtype,
548-
param->paramtypmod,
549-
0);
550-
551-
/*
552-
* Copy it for caller. NB: we need a copy to avoid having
553-
* doubly-linked substructure in the modified parse tree.
554-
*/
555-
context->righthandIds = lappend(context->righthandIds,
556-
copyObject(newvar));
557-
return (Node *) newvar;
558-
}
559-
else
560-
{
561-
/* Make the Param node representing the subplan's result */
562-
Param *newparam;
563-
564-
newparam = generate_new_param(context->root,
565-
param->paramtype,
566-
param->paramtypmod);
567-
/* Record its ID */
568-
context->righthandIds = lappend_int(context->righthandIds,
569-
newparam->paramid);
570-
return (Node *) newparam;
571-
}
598+
/*
599+
* We copy the list item to avoid having doubly-linked
600+
* substructure in the modified parse tree. This is probably
601+
* unnecessary when it's a Param, but be safe.
602+
*/
603+
return (Node *) copyObject(list_nth(context->subst_nodes,
604+
param->paramid - 1));
572605
}
573606
}
574607
return expression_tree_mutator(node,
@@ -786,20 +819,24 @@ convert_IN_to_join(PlannerInfo *root, SubLink *sublink)
786819
ininfo->in_operators = in_operators;
787820

788821
/*
789-
* Build the result qual expression. As a side effect,
790822
* ininfo->sub_targetlist is filled with a list of Vars representing the
791823
* subselect outputs.
792824
*/
793-
result = convert_testexpr(root,
794-
sublink->testexpr,
795-
rtindex,
796-
&ininfo->sub_targetlist);
797-
825+
ininfo->sub_targetlist = generate_subquery_vars(root,
826+
subselect->targetList,
827+
rtindex);
798828
Assert(list_length(in_operators) == list_length(ininfo->sub_targetlist));
799829

800830
/* Add the completed node to the query's list */
801831
root->in_info_list = lappend(root->in_info_list, ininfo);
802832

833+
/*
834+
* Build the result qual expression.
835+
*/
836+
result = convert_testexpr(root,
837+
sublink->testexpr,
838+
ininfo->sub_targetlist);
839+
803840
return result;
804841
}
805842

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy