setrefs.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:27k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * setrefs.c
  4.  *   Routines to change varno/attno entries to contain references
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.50.2.1 1999/08/02 06:27:03 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include <sys/types.h>
  15. #include "postgres.h"
  16. #include "nodes/makefuncs.h"
  17. #include "nodes/nodeFuncs.h"
  18. #include "optimizer/clauses.h"
  19. #include "optimizer/planmain.h"
  20. #include "optimizer/tlist.h"
  21. #include "optimizer/var.h"
  22. static void set_join_tlist_references(Join *join);
  23. static void set_nonamescan_tlist_references(SeqScan *nonamescan);
  24. static void set_noname_tlist_references(Noname *noname);
  25. static Node *replace_clause_joinvar_refs(Node *clause,
  26. List *outer_tlist,
  27. List *inner_tlist);
  28. static Var *replace_joinvar_refs(Var *var,
  29.  List *outer_tlist,
  30.  List *inner_tlist);
  31. static List *tlist_noname_references(Oid nonameid, List *tlist);
  32. static bool OperandIsInner(Node *opnd, int inner_relid);
  33. static List *pull_agg_clause(Node *clause);
  34. static void set_result_tlist_references(Result *resultNode);
  35. static void replace_vars_with_subplan_refs(Node *clause,
  36.    Index subvarno,
  37.    List *subplanTargetList);
  38. /*****************************************************************************
  39.  *
  40.  * SUBPLAN REFERENCES
  41.  *
  42.  *****************************************************************************/
  43. /*
  44.  * set_tlist_references
  45.  *   Modifies the target list of nodes in a plan to reference target lists
  46.  *   at lower levels.
  47.  *
  48.  * 'plan' is the plan whose target list and children's target lists will
  49.  * be modified
  50.  *
  51.  * Returns nothing of interest, but modifies internal fields of nodes.
  52.  *
  53.  */
  54. void
  55. set_tlist_references(Plan *plan)
  56. {
  57. if (plan == NULL)
  58. return;
  59. if (IsA_Join(plan))
  60. set_join_tlist_references((Join *) plan);
  61. else if (IsA(plan, SeqScan) &&plan->lefttree &&
  62.  IsA_Noname(plan->lefttree))
  63. set_nonamescan_tlist_references((SeqScan *) plan);
  64. else if (IsA(plan, Sort))
  65. set_noname_tlist_references((Noname *) plan);
  66. else if (IsA(plan, Result))
  67. set_result_tlist_references((Result *) plan);
  68. else if (IsA(plan, Hash))
  69. set_tlist_references(plan->lefttree);
  70. }
  71. /*
  72.  * set_join_tlist_references
  73.  *   Modifies the target list of a join node by setting the varnos and
  74.  *   varattnos to reference the target list of the outer and inner join
  75.  *   relations.
  76.  *
  77.  *   Creates a target list for a join node to contain references by setting
  78.  *   varno values to OUTER or INNER and setting attno values to the
  79.  *   result domain number of either the corresponding outer or inner join
  80.  *   tuple.
  81.  *
  82.  * 'join' is a join plan node
  83.  *
  84.  * Returns nothing of interest, but modifies internal fields of nodes.
  85.  *
  86.  */
  87. static void
  88. set_join_tlist_references(Join *join)
  89. {
  90. Plan    *outer = ((Plan *) join)->lefttree;
  91. Plan    *inner = ((Plan *) join)->righttree;
  92. List    *outer_tlist = ((outer == NULL) ? NIL : outer->targetlist);
  93. List    *inner_tlist = ((inner == NULL) ? NIL : inner->targetlist);
  94. List    *new_join_targetlist = NIL;
  95. List    *qptlist = ((Plan *) join)->targetlist;
  96. List    *entry;
  97. foreach(entry, qptlist)
  98. {
  99. TargetEntry *xtl = (TargetEntry *) lfirst(entry);
  100. Node    *joinvar = replace_clause_joinvar_refs(xtl->expr,
  101.   outer_tlist,
  102.   inner_tlist);
  103. new_join_targetlist = lappend(new_join_targetlist,
  104.   makeTargetEntry(xtl->resdom, joinvar));
  105. }
  106. ((Plan *) join)->targetlist = new_join_targetlist;
  107. if (outer != NULL)
  108. set_tlist_references(outer);
  109. if (inner != NULL)
  110. set_tlist_references(inner);
  111. }
  112. /*
  113.  * set_nonamescan_tlist_references
  114.  *   Modifies the target list of a node that scans a noname relation (i.e., a
  115.  *   sort or hash node) so that the varnos refer to the child noname.
  116.  *
  117.  * 'nonamescan' is a seqscan node
  118.  *
  119.  * Returns nothing of interest, but modifies internal fields of nodes.
  120.  *
  121.  */
  122. static void
  123. set_nonamescan_tlist_references(SeqScan *nonamescan)
  124. {
  125. Noname    *noname = (Noname *) ((Plan *) nonamescan)->lefttree;
  126. ((Plan *) nonamescan)->targetlist = tlist_noname_references(noname->nonameid,
  127.   ((Plan *) nonamescan)->targetlist);
  128. set_noname_tlist_references(noname);
  129. }
  130. /*
  131.  * set_noname_tlist_references
  132.  *   The noname's vars are made consistent with (actually, identical to) the
  133.  *   modified version of the target list of the node from which noname node
  134.  *   receives its tuples.
  135.  *
  136.  * 'noname' is a noname (e.g., sort, hash) plan node
  137.  *
  138.  * Returns nothing of interest, but modifies internal fields of nodes.
  139.  *
  140.  */
  141. static void
  142. set_noname_tlist_references(Noname *noname)
  143. {
  144. Plan    *source = ((Plan *) noname)->lefttree;
  145. if (source != NULL)
  146. {
  147. set_tlist_references(source);
  148. ((Plan *) noname)->targetlist = copy_vars(((Plan *) noname)->targetlist,
  149.   (source)->targetlist);
  150. }
  151. else
  152. elog(ERROR, "calling set_noname_tlist_references with empty lefttree");
  153. }
  154. /*
  155.  * join_references
  156.  *    Creates a new set of join clauses by changing the varno/varattno
  157.  *    values of variables in the clauses to reference target list values
  158.  *    from the outer and inner join relation target lists.
  159.  *    This is just an external interface for replace_clause_joinvar_refs.
  160.  *
  161.  * 'clauses' is the list of join clauses
  162.  * 'outer_tlist' is the target list of the outer join relation
  163.  * 'inner_tlist' is the target list of the inner join relation
  164.  *
  165.  * Returns the new join clauses.  The original clause structure is
  166.  * not modified.
  167.  *
  168.  */
  169. List *
  170. join_references(List *clauses,
  171. List *outer_tlist,
  172. List *inner_tlist)
  173. {
  174. return (List *) replace_clause_joinvar_refs((Node *) clauses,
  175. outer_tlist,
  176. inner_tlist);
  177. }
  178. /*
  179.  * index_outerjoin_references
  180.  *   Given a list of join clauses, replace the operand corresponding to the
  181.  *   outer relation in the join with references to the corresponding target
  182.  *   list element in 'outer_tlist' (the outer is rather obscurely
  183.  *   identified as the side that doesn't contain a var whose varno equals
  184.  *   'inner_relid').
  185.  *
  186.  *   As a side effect, the operator is replaced by the regproc id.
  187.  *
  188.  * 'inner_indxqual' is the list of join clauses (so-called because they
  189.  * are used as qualifications for the inner (inbex) scan of a nestloop)
  190.  *
  191.  * Returns the new list of clauses.
  192.  *
  193.  */
  194. List *
  195. index_outerjoin_references(List *inner_indxqual,
  196.    List *outer_tlist,
  197.    Index inner_relid)
  198. {
  199. List    *t_list = NIL;
  200. Expr    *temp = NULL;
  201. List    *t_clause = NIL;
  202. Expr    *clause = NULL;
  203. foreach(t_clause, inner_indxqual)
  204. {
  205. clause = lfirst(t_clause);
  206. /*
  207.  * if inner scan on the right.
  208.  */
  209. if (OperandIsInner((Node *) get_rightop(clause), inner_relid))
  210. {
  211. Var    *joinvar = (Var *)
  212. replace_clause_joinvar_refs((Node *) get_leftop(clause),
  213. outer_tlist,
  214. NIL);
  215. temp = make_opclause(replace_opid((Oper *) ((Expr *) clause)->oper),
  216.  joinvar,
  217.  get_rightop(clause));
  218. t_list = lappend(t_list, temp);
  219. }
  220. else
  221. {
  222. /* inner scan on left */
  223. Var    *joinvar = (Var *)
  224. replace_clause_joinvar_refs((Node *) get_rightop(clause),
  225. outer_tlist,
  226. NIL);
  227. temp = make_opclause(replace_opid((Oper *) ((Expr *) clause)->oper),
  228.  get_leftop(clause),
  229.  joinvar);
  230. t_list = lappend(t_list, temp);
  231. }
  232. }
  233. return t_list;
  234. }
  235. /*
  236.  * replace_clause_joinvar_refs
  237.  * replace_joinvar_refs
  238.  *
  239.  *   Replaces all variables within a join clause with a new var node
  240.  *   whose varno/varattno fields contain a reference to a target list
  241.  *   element from either the outer or inner join relation.
  242.  *
  243.  * 'clause' is the join clause
  244.  * 'outer_tlist' is the target list of the outer join relation
  245.  * 'inner_tlist' is the target list of the inner join relation
  246.  *
  247.  * Returns the new join clause.
  248.  * NB: it is critical that the original clause structure not be modified!
  249.  * The changes must be applied to a copy.
  250.  *
  251.  * XXX the current implementation does not copy unchanged primitive
  252.  * nodes; they remain shared with the original.  Is this safe?
  253.  */
  254. static Node *
  255. replace_clause_joinvar_refs(Node *clause,
  256. List *outer_tlist,
  257. List *inner_tlist)
  258. {
  259. if (clause == NULL)
  260. return NULL;
  261. if (IsA(clause, Var))
  262. {
  263. Var    *temp = replace_joinvar_refs((Var *) clause,
  264. outer_tlist, inner_tlist);
  265. if (temp != NULL)
  266. return (Node *) temp;
  267. else
  268. return clause;
  269. }
  270. else if (single_node(clause))
  271. return clause;
  272. else if (and_clause(clause))
  273. {
  274. return (Node *) make_andclause((List *)
  275. replace_clause_joinvar_refs((Node *) ((Expr *) clause)->args,
  276. outer_tlist,
  277. inner_tlist));
  278. }
  279. else if (or_clause(clause))
  280. {
  281. return (Node *) make_orclause((List *)
  282. replace_clause_joinvar_refs((Node *) ((Expr *) clause)->args,
  283. outer_tlist,
  284. inner_tlist));
  285. }
  286. else if (IsA(clause, ArrayRef))
  287. {
  288. ArrayRef   *oldnode = (ArrayRef *) clause;
  289. ArrayRef   *newnode = makeNode(ArrayRef);
  290. newnode->refattrlength = oldnode->refattrlength;
  291. newnode->refelemlength = oldnode->refelemlength;
  292. newnode->refelemtype = oldnode->refelemtype;
  293. newnode->refelembyval = oldnode->refelembyval;
  294. newnode->refupperindexpr = (List *)
  295. replace_clause_joinvar_refs((Node *) oldnode->refupperindexpr,
  296. outer_tlist,
  297. inner_tlist);
  298. newnode->reflowerindexpr = (List *)
  299. replace_clause_joinvar_refs((Node *) oldnode->reflowerindexpr,
  300. outer_tlist,
  301. inner_tlist);
  302. newnode->refexpr =
  303. replace_clause_joinvar_refs(oldnode->refexpr,
  304. outer_tlist,
  305. inner_tlist);
  306. newnode->refassgnexpr =
  307. replace_clause_joinvar_refs(oldnode->refassgnexpr,
  308. outer_tlist,
  309. inner_tlist);
  310. return (Node *) newnode;
  311. }
  312. else if (is_funcclause(clause))
  313. {
  314. return (Node *) make_funcclause(
  315. (Func *) ((Expr *) clause)->oper,
  316. (List *) replace_clause_joinvar_refs(
  317. (Node *) ((Expr *) clause)->args,
  318.  outer_tlist,
  319.    inner_tlist));
  320. }
  321. else if (not_clause(clause))
  322. {
  323. return (Node *) make_notclause((Expr *)
  324.    replace_clause_joinvar_refs(
  325.   (Node *) get_notclausearg((Expr *) clause),
  326.  outer_tlist,
  327.    inner_tlist));
  328. }
  329. else if (is_opclause(clause))
  330. {
  331. return (Node *) make_opclause(
  332.   replace_opid((Oper *) ((Expr *) clause)->oper),
  333.   (Var *) replace_clause_joinvar_refs(
  334. (Node *) get_leftop((Expr *) clause),
  335.  outer_tlist,
  336. inner_tlist),
  337.   (Var *) replace_clause_joinvar_refs(
  338.    (Node *) get_rightop((Expr *) clause),
  339.  outer_tlist,
  340.    inner_tlist));
  341. }
  342. else if (IsA(clause, List))
  343. {
  344. List    *t_list = NIL;
  345. List    *subclause;
  346. foreach(subclause, (List *) clause)
  347. {
  348. t_list = lappend(t_list,
  349.    replace_clause_joinvar_refs(lfirst(subclause),
  350.    outer_tlist,
  351.    inner_tlist));
  352. }
  353. return (Node *) t_list;
  354. }
  355. else if (is_subplan(clause))
  356. {
  357. /* This is a tad wasteful of space, but it works... */
  358. Expr    *newclause = (Expr *) copyObject(clause);
  359. newclause->args = (List *)
  360. replace_clause_joinvar_refs((Node *) newclause->args,
  361. outer_tlist,
  362. inner_tlist);
  363. ((SubPlan *) newclause->oper)->sublink->oper = (List *)
  364. replace_clause_joinvar_refs(
  365.    (Node *) ((SubPlan *) newclause->oper)->sublink->oper,
  366. outer_tlist,
  367. inner_tlist);
  368. return (Node *) newclause;
  369. }
  370. else if (IsA(clause, CaseExpr))
  371. {
  372. CaseExpr   *oldnode = (CaseExpr *) clause;
  373. CaseExpr   *newnode = makeNode(CaseExpr);
  374. newnode->casetype = oldnode->casetype;
  375. newnode->arg = oldnode->arg; /* XXX should always be null
  376.  * anyway ... */
  377. newnode->args = (List *)
  378. replace_clause_joinvar_refs((Node *) oldnode->args,
  379. outer_tlist,
  380. inner_tlist);
  381. newnode->defresult =
  382. replace_clause_joinvar_refs(oldnode->defresult,
  383. outer_tlist,
  384. inner_tlist);
  385. return (Node *) newnode;
  386. }
  387. else if (IsA(clause, CaseWhen))
  388. {
  389. CaseWhen   *oldnode = (CaseWhen *) clause;
  390. CaseWhen   *newnode = makeNode(CaseWhen);
  391. newnode->expr =
  392. replace_clause_joinvar_refs(oldnode->expr,
  393. outer_tlist,
  394. inner_tlist);
  395. newnode->result =
  396. replace_clause_joinvar_refs(oldnode->result,
  397. outer_tlist,
  398. inner_tlist);
  399. return (Node *) newnode;
  400. }
  401. else
  402. {
  403. elog(ERROR, "replace_clause_joinvar_refs: unsupported clause %d",
  404.  nodeTag(clause));
  405. return NULL;
  406. }
  407. }
  408. static Var *
  409. replace_joinvar_refs(Var *var, List *outer_tlist, List *inner_tlist)
  410. {
  411. Resdom    *outer_resdom;
  412. outer_resdom = tlist_member(var, outer_tlist);
  413. if (outer_resdom != NULL && IsA(outer_resdom, Resdom))
  414. {
  415. return (makeVar(OUTER,
  416. outer_resdom->resno,
  417. var->vartype,
  418. var->vartypmod,
  419. 0,
  420. var->varnoold,
  421. var->varoattno));
  422. }
  423. else
  424. {
  425. Resdom    *inner_resdom;
  426. inner_resdom = tlist_member(var, inner_tlist);
  427. if (inner_resdom != NULL && IsA(inner_resdom, Resdom))
  428. {
  429. return (makeVar(INNER,
  430. inner_resdom->resno,
  431. var->vartype,
  432. var->vartypmod,
  433. 0,
  434. var->varnoold,
  435. var->varoattno));
  436. }
  437. }
  438. return (Var *) NULL;
  439. }
  440. /*
  441.  * tlist_noname_references
  442.  *   Creates a new target list for a node that scans a noname relation,
  443.  *   setting the varnos to the id of the noname relation and setting varids
  444.  *   if necessary (varids are only needed if this is a targetlist internal
  445.  *   to the tree, in which case the targetlist entry always contains a var
  446.  *   node, so we can just copy it from the noname).
  447.  *
  448.  * 'nonameid' is the id of the noname relation
  449.  * 'tlist' is the target list to be modified
  450.  *
  451.  * Returns new target list
  452.  *
  453.  */
  454. static List *
  455. tlist_noname_references(Oid nonameid,
  456. List *tlist)
  457. {
  458. List    *t_list = NIL;
  459. TargetEntry *noname = (TargetEntry *) NULL;
  460. TargetEntry *xtl = NULL;
  461. List    *entry;
  462. foreach(entry, tlist)
  463. {
  464. AttrNumber oattno;
  465. xtl = lfirst(entry);
  466. if (IsA(get_expr(xtl), Var))
  467. oattno = ((Var *) xtl->expr)->varoattno;
  468. else
  469. oattno = 0;
  470. noname = makeTargetEntry(xtl->resdom,
  471.  (Node *) makeVar(nonameid,
  472.   xtl->resdom->resno,
  473.   xtl->resdom->restype,
  474.   xtl->resdom->restypmod,
  475.   0,
  476.   nonameid,
  477.   oattno));
  478. t_list = lappend(t_list, noname);
  479. }
  480. return t_list;
  481. }
  482. /*---------------------------------------------------------
  483.  *
  484.  * set_result_tlist_references
  485.  *
  486.  * Change the target list of a Result node, so that it correctly
  487.  * addresses the tuples returned by its left tree subplan.
  488.  *
  489.  * NOTE:
  490.  * 1) we ignore the right tree! (in the current implementation
  491.  *    it is always nil
  492.  * 2) this routine will probably *NOT* work with nested dot
  493.  *    fields....
  494.  */
  495. static void
  496. set_result_tlist_references(Result *resultNode)
  497. {
  498. Plan    *subplan;
  499. List    *resultTargetList;
  500. List    *subplanTargetList;
  501. resultTargetList = ((Plan *) resultNode)->targetlist;
  502. /*
  503.  * NOTE: we only consider the left tree subplan. This is usually a seq
  504.  * scan.
  505.  */
  506. subplan = ((Plan *) resultNode)->lefttree;
  507. if (subplan != NULL)
  508. subplanTargetList = subplan->targetlist;
  509. else
  510. subplanTargetList = NIL;
  511. replace_tlist_with_subplan_refs(resultTargetList,
  512. (Index) OUTER,
  513. subplanTargetList);
  514. }
  515. /*---------------------------------------------------------
  516.  *
  517.  * replace_tlist_with_subplan_refs
  518.  *
  519.  * Applies replace_vars_with_subplan_refs() to each entry of a targetlist.
  520.  */
  521. void
  522. replace_tlist_with_subplan_refs(List *tlist,
  523. Index subvarno,
  524. List *subplanTargetList)
  525. {
  526. List    *t;
  527. foreach(t, tlist)
  528. {
  529. TargetEntry *entry = (TargetEntry *) lfirst(t);
  530. replace_vars_with_subplan_refs((Node *) get_expr(entry),
  531.    subvarno, subplanTargetList);
  532. }
  533. }
  534. /*---------------------------------------------------------
  535.  *
  536.  * replace_vars_with_subplan_refs
  537.  *
  538.  * This routine modifies (destructively!) an expression tree so that all
  539.  * Var nodes reference target nodes of a subplan.  It is used to fix up
  540.  * target expressions of upper-level plan nodes.
  541.  *
  542.  * 'clause': the tree to be fixed
  543.  * 'subvarno': varno to be assigned to all Vars
  544.  * 'subplanTargetList': target list for subplan
  545.  *
  546.  * Afterwards, all Var nodes have varno = subvarno, varattno = resno
  547.  * of corresponding subplan target.
  548.  */
  549. static void
  550. replace_vars_with_subplan_refs(Node *clause,
  551.    Index subvarno,
  552.    List *subplanTargetList)
  553. {
  554. List    *t;
  555. if (clause == NULL)
  556. return;
  557. if (IsA(clause, Var))
  558. {
  559. /*
  560.  * Ha! A Var node!
  561.  *
  562.  * It could be that this varnode has been created by make_groupplan
  563.  * and is already set up to reference the subplan target list. We
  564.  * recognize that case by varno = 1, varnoold = -1, varattno =
  565.  * varoattno, and varlevelsup = 0. (Probably ought to have an
  566.  * explicit flag, but this should do for now.)
  567.  */
  568. Var    *var = (Var *) clause;
  569. TargetEntry *subplanVar;
  570. if (var->varno == (Index) 1 &&
  571. var->varnoold == ((Index) -1) &&
  572. var->varattno == var->varoattno &&
  573. var->varlevelsup == 0)
  574. return; /* OK to leave it alone */
  575. /* Otherwise it had better be in the subplan list. */
  576. subplanVar = match_varid(var, subplanTargetList);
  577. if (!subplanVar)
  578. elog(ERROR, "replace_vars_with_subplan_refs: variable not in target list");
  579. /*
  580.  * Change the varno & varattno fields of the var node.
  581.  */
  582. var->varno = subvarno;
  583. var->varattno = subplanVar->resdom->resno;
  584. }
  585. else if (single_node(clause))
  586. {
  587. /* do nothing! */
  588. }
  589. else if (IsA(clause, Iter))
  590. replace_vars_with_subplan_refs(((Iter *) clause)->iterexpr,
  591.    subvarno, subplanTargetList);
  592. else if (is_subplan(clause))
  593. {
  594. foreach(t, ((Expr *) clause)->args)
  595. replace_vars_with_subplan_refs(lfirst(t),
  596.    subvarno, subplanTargetList);
  597. foreach(t, ((SubPlan *) ((Expr *) clause)->oper)->sublink->oper)
  598. replace_vars_with_subplan_refs(lfirst(((Expr *) lfirst(t))->args),
  599.    subvarno, subplanTargetList);
  600. }
  601. else if (IsA(clause, Expr))
  602. {
  603. /*
  604.  * Recursively scan the arguments of an expression. NOTE: this
  605.  * must come after is_subplan() case since subplan is a kind of
  606.  * Expr node.
  607.  */
  608. foreach(t, ((Expr *) clause)->args)
  609. replace_vars_with_subplan_refs(lfirst(t),
  610.    subvarno, subplanTargetList);
  611. }
  612. else if (IsA(clause, Aggref))
  613. replace_vars_with_subplan_refs(((Aggref *) clause)->target,
  614.    subvarno, subplanTargetList);
  615. else if (IsA(clause, ArrayRef))
  616. {
  617. ArrayRef   *aref = (ArrayRef *) clause;
  618. foreach(t, aref->refupperindexpr)
  619. replace_vars_with_subplan_refs(lfirst(t),
  620.    subvarno, subplanTargetList);
  621. foreach(t, aref->reflowerindexpr)
  622. replace_vars_with_subplan_refs(lfirst(t),
  623.    subvarno, subplanTargetList);
  624. replace_vars_with_subplan_refs(aref->refexpr,
  625.    subvarno, subplanTargetList);
  626. replace_vars_with_subplan_refs(aref->refassgnexpr,
  627.    subvarno, subplanTargetList);
  628. }
  629. else if (case_clause(clause))
  630. {
  631. foreach(t, ((CaseExpr *) clause)->args)
  632. {
  633. CaseWhen   *when = (CaseWhen *) lfirst(t);
  634. replace_vars_with_subplan_refs(when->expr,
  635.    subvarno, subplanTargetList);
  636. replace_vars_with_subplan_refs(when->result,
  637.    subvarno, subplanTargetList);
  638. }
  639. replace_vars_with_subplan_refs(((CaseExpr *) clause)->defresult,
  640.    subvarno, subplanTargetList);
  641. }
  642. else
  643. {
  644. elog(ERROR, "replace_vars_with_subplan_refs: Cannot handle node type %d",
  645.  nodeTag(clause));
  646. }
  647. }
  648. static bool
  649. OperandIsInner(Node *opnd, int inner_relid)
  650. {
  651. /*
  652.  * Can be the inner scan if its a varnode or a function and the
  653.  * inner_relid is equal to the varnode's var number or in the case of
  654.  * a function the first argument's var number (all args in a
  655.  * functional index are from the same relation).
  656.  */
  657. if (IsA(opnd, Var) &&
  658. (inner_relid == ((Var *) opnd)->varno))
  659. return true;
  660. if (is_funcclause(opnd))
  661. {
  662. List    *firstArg = lfirst(((Expr *) opnd)->args);
  663. if (IsA(firstArg, Var) &&
  664. (inner_relid == ((Var *) firstArg)->varno))
  665. return true;
  666. }
  667. return false;
  668. }
  669. /*****************************************************************************
  670.  *
  671.  *****************************************************************************/
  672. /*---------------------------------------------------------
  673.  *
  674.  * set_agg_tlist_references -
  675.  *   This routine has several responsibilities:
  676.  * * Update the target list of an Agg node so that it points to
  677.  *   the tuples returned by its left tree subplan.
  678.  * * If there is a qual list (from a HAVING clause), similarly update
  679.  *   vars in it to point to the subplan target list.
  680.  * * Generate the aggNode->aggs list of Aggref nodes contained in the Agg.
  681.  *
  682.  * The return value is TRUE if all qual clauses include Aggrefs, or FALSE
  683.  * if any do not (caller may choose to raise an error condition).
  684.  */
  685. bool
  686. set_agg_tlist_references(Agg *aggNode)
  687. {
  688. List    *subplanTargetList;
  689. List    *tl;
  690. List    *ql;
  691. bool all_quals_ok;
  692. subplanTargetList = aggNode->plan.lefttree->targetlist;
  693. aggNode->aggs = NIL;
  694. foreach(tl, aggNode->plan.targetlist)
  695. {
  696. TargetEntry *tle = lfirst(tl);
  697. replace_vars_with_subplan_refs(tle->expr,
  698.    (Index) 0,
  699.    subplanTargetList);
  700. aggNode->aggs = nconc(pull_agg_clause(tle->expr), aggNode->aggs);
  701. }
  702. all_quals_ok = true;
  703. foreach(ql, aggNode->plan.qual)
  704. {
  705. Node    *qual = lfirst(ql);
  706. List    *qualaggs;
  707. replace_vars_with_subplan_refs(qual,
  708.    (Index) 0,
  709.    subplanTargetList);
  710. qualaggs = pull_agg_clause(qual);
  711. if (qualaggs == NIL)
  712. all_quals_ok = false; /* this qual clause has no agg
  713.  * functions! */
  714. else
  715. aggNode->aggs = nconc(qualaggs, aggNode->aggs);
  716. }
  717. return all_quals_ok;
  718. }
  719. /*
  720.  * Make a list of all Aggref nodes contained in the given expression.
  721.  */
  722. static List *
  723. pull_agg_clause(Node *clause)
  724. {
  725. List    *agg_list = NIL;
  726. List    *t;
  727. if (clause == NULL)
  728. return NIL;
  729. else if (single_node(clause))
  730. return NIL;
  731. else if (IsA(clause, Iter))
  732. return pull_agg_clause(((Iter *) clause)->iterexpr);
  733. else if (is_subplan(clause))
  734. {
  735. SubLink    *sublink = ((SubPlan *) ((Expr *) clause)->oper)->sublink;
  736. /*
  737.  * Only the lefthand side of the sublink should be checked for
  738.  * aggregates to be attached to the aggs list
  739.  */
  740. foreach(t, sublink->lefthand)
  741. agg_list = nconc(pull_agg_clause(lfirst(t)), agg_list);
  742. /* The first argument of ...->oper has also to be checked */
  743. foreach(t, sublink->oper)
  744. agg_list = nconc(pull_agg_clause(lfirst(t)), agg_list);
  745. }
  746. else if (IsA(clause, Expr))
  747. {
  748. /*
  749.  * Recursively scan the arguments of an expression. NOTE: this
  750.  * must come after is_subplan() case since subplan is a kind of
  751.  * Expr node.
  752.  */
  753. foreach(t, ((Expr *) clause)->args)
  754. agg_list = nconc(pull_agg_clause(lfirst(t)), agg_list);
  755. }
  756. else if (IsA(clause, Aggref))
  757. {
  758. return lcons(clause,
  759.  pull_agg_clause(((Aggref *) clause)->target));
  760. }
  761. else if (IsA(clause, ArrayRef))
  762. {
  763. ArrayRef   *aref = (ArrayRef *) clause;
  764. foreach(t, aref->refupperindexpr)
  765. agg_list = nconc(pull_agg_clause(lfirst(t)), agg_list);
  766. foreach(t, aref->reflowerindexpr)
  767. agg_list = nconc(pull_agg_clause(lfirst(t)), agg_list);
  768. agg_list = nconc(pull_agg_clause(aref->refexpr), agg_list);
  769. agg_list = nconc(pull_agg_clause(aref->refassgnexpr), agg_list);
  770. }
  771. else if (case_clause(clause))
  772. {
  773. foreach(t, ((CaseExpr *) clause)->args)
  774. {
  775. CaseWhen   *when = (CaseWhen *) lfirst(t);
  776. agg_list = nconc(agg_list, pull_agg_clause(when->expr));
  777. agg_list = nconc(agg_list, pull_agg_clause(when->result));
  778. }
  779. agg_list = nconc(pull_agg_clause(((CaseExpr *) clause)->defresult),
  780.  agg_list);
  781. }
  782. else
  783. {
  784. elog(ERROR, "pull_agg_clause: Cannot handle node type %d",
  785.  nodeTag(clause));
  786. }
  787. return agg_list;
  788. }
  789. /*
  790.  * check_having_for_ungrouped_vars takes the havingQual and the list of
  791.  * GROUP BY clauses and checks for subplans in the havingQual that are being
  792.  * passed ungrouped variables as parameters.  In other contexts, ungrouped
  793.  * vars in the havingQual will be detected by the parser (see parse_agg.c,
  794.  * exprIsAggOrGroupCol()). But that routine currently does not check subplans,
  795.  * because the necessary info is not computed until the planner runs.
  796.  * This ought to be cleaned up someday.
  797.  *
  798.  * NOTE: the havingClause has been cnf-ified, so AND subclauses have been
  799.  * turned into a plain List.  Thus, this routine has to cope with List nodes
  800.  * where the routine above does not...
  801.  */
  802. void
  803. check_having_for_ungrouped_vars(Node *clause, List *groupClause,
  804. List *targetList)
  805. {
  806. List    *t;
  807. if (clause == NULL)
  808. return;
  809. if (IsA(clause, Var))
  810. {
  811. /*
  812.  * Ignore vars elsewhere in the having clause, since the parser
  813.  * already checked 'em.
  814.  */
  815. }
  816. else if (single_node(clause))
  817. {
  818. /* ignore */
  819. }
  820. else if (IsA(clause, Iter))
  821. {
  822. check_having_for_ungrouped_vars(((Iter *) clause)->iterexpr,
  823. groupClause, targetList);
  824. }
  825. else if (is_subplan(clause))
  826. {
  827. /*
  828.  * The args list of the subplan node represents attributes from
  829.  * outside passed into the sublink.
  830.  */
  831. foreach(t, ((Expr *) clause)->args)
  832. {
  833. bool contained_in_group_clause = false;
  834. List    *gl;
  835. foreach(gl, groupClause)
  836. {
  837. if (var_equal(lfirst(t),
  838.   get_groupclause_expr((GroupClause *)
  839. lfirst(gl), targetList)))
  840. {
  841. contained_in_group_clause = true;
  842. break;
  843. }
  844. }
  845. if (!contained_in_group_clause)
  846. elog(ERROR, "Sub-SELECT in HAVING clause must use only GROUPed attributes from outer SELECT");
  847. }
  848. }
  849. else if (IsA(clause, Expr))
  850. {
  851. /*
  852.  * Recursively scan the arguments of an expression. NOTE: this
  853.  * must come after is_subplan() case since subplan is a kind of
  854.  * Expr node.
  855.  */
  856. foreach(t, ((Expr *) clause)->args)
  857. check_having_for_ungrouped_vars(lfirst(t), groupClause,
  858. targetList);
  859. }
  860. else if (IsA(clause, List))
  861. {
  862. /*
  863.  * Recursively scan AND subclauses (see NOTE above).
  864.  */
  865. foreach(t, ((List *) clause))
  866. check_having_for_ungrouped_vars(lfirst(t), groupClause,
  867. targetList);
  868. }
  869. else if (IsA(clause, Aggref))
  870. {
  871. check_having_for_ungrouped_vars(((Aggref *) clause)->target,
  872. groupClause, targetList);
  873. }
  874. else if (IsA(clause, ArrayRef))
  875. {
  876. ArrayRef   *aref = (ArrayRef *) clause;
  877. /*
  878.  * This is an arrayref. Recursively call this routine for its
  879.  * expression and its index expression...
  880.  */
  881. foreach(t, aref->refupperindexpr)
  882. check_having_for_ungrouped_vars(lfirst(t), groupClause,
  883. targetList);
  884. foreach(t, aref->reflowerindexpr)
  885. check_having_for_ungrouped_vars(lfirst(t), groupClause,
  886. targetList);
  887. check_having_for_ungrouped_vars(aref->refexpr, groupClause,
  888. targetList);
  889. check_having_for_ungrouped_vars(aref->refassgnexpr, groupClause,
  890. targetList);
  891. }
  892. else if (case_clause(clause))
  893. {
  894. foreach(t, ((CaseExpr *) clause)->args)
  895. {
  896. CaseWhen   *when = (CaseWhen *) lfirst(t);
  897. check_having_for_ungrouped_vars(when->expr, groupClause,
  898. targetList);
  899. check_having_for_ungrouped_vars(when->result, groupClause,
  900. targetList);
  901. }
  902. check_having_for_ungrouped_vars(((CaseExpr *) clause)->defresult,
  903. groupClause, targetList);
  904. }
  905. else
  906. {
  907. elog(ERROR, "check_having_for_ungrouped_vars: Cannot handle node type %d",
  908.  nodeTag(clause));
  909. }
  910. }