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 */
3535typedef 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
4241typedef 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 );
5659static Node * convert_testexpr (PlannerInfo * root ,
5760 Node * testexpr ,
58- int rtindex ,
59- List * * righthandIds );
61+ List * subst_nodes );
6062static Node * convert_testexpr_mutator (Node * node ,
6163 convert_testexpr_context * context );
6264static 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)
502570static Node *
503571convert_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
519582static 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