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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * tlist.c
  4.  *   Target list manipulation routines
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.33.2.1 1999/08/02 06:27:08 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include "postgres.h"
  15. #include "nodes/makefuncs.h"
  16. #include "nodes/nodeFuncs.h"
  17. #include "optimizer/clauses.h"
  18. #include "optimizer/tlist.h"
  19. #include "optimizer/var.h"
  20. static Node *flatten_tlistentry(Node *tlistentry, List *flat_tlist);
  21. /*****************************************************************************
  22.  * ---------- RELATION node target list routines ----------
  23.  *****************************************************************************/
  24. /*
  25.  * tlistentry_member
  26.  *
  27.  * RETURNS:  the leftmost member of sequence "targetlist" that satisfies
  28.  *  the predicate "var_equal"
  29.  * MODIFIES: nothing
  30.  * REQUIRES: test = function which can operate on a lispval union
  31.  *  var = valid var_node
  32.  *  targetlist = valid sequence
  33.  */
  34. TargetEntry *
  35. tlistentry_member(Var *var, List *targetlist)
  36. {
  37. if (var)
  38. {
  39. List    *temp;
  40. foreach(temp, targetlist)
  41. {
  42. if (var_equal(var,
  43.   get_expr(lfirst(temp))))
  44. return (TargetEntry *) lfirst(temp);
  45. }
  46. }
  47. return NULL;
  48. }
  49. /*
  50.  * matching_tlist_var
  51.  *
  52.  * RETURNS:  var node in a target list which is var_equal to 'var',
  53.  *  if one exists.
  54.  * REQUIRES: "test" operates on lispval unions,
  55.  *
  56.  */
  57. Expr *
  58. matching_tlist_var(Var *var, List *targetlist)
  59. {
  60. TargetEntry *tlentry;
  61. tlentry = tlistentry_member(var, targetlist);
  62. if (tlentry)
  63. return (Expr *) get_expr(tlentry);
  64. return (Expr *) NULL;
  65. }
  66. /*
  67.  * add_var_to_tlist
  68.  *   Creates a targetlist entry corresponding to the supplied var node
  69.  *
  70.  * 'var' and adds the new targetlist entry to the targetlist field of
  71.  * 'rel'
  72.  *
  73.  * RETURNS: nothing
  74.  * MODIFIES: vartype and varid fields of leftmost varnode that matches
  75.  *  argument "var" (sometimes).
  76.  * CREATES:  new var_node iff no matching var_node exists in targetlist
  77.  */
  78. void
  79. add_var_to_tlist(RelOptInfo *rel, Var *var)
  80. {
  81. Expr    *oldvar;
  82. oldvar = matching_tlist_var(var, rel->targetlist);
  83. /*
  84.  * If 'var' is not already in 'rel's target list, add a new node.
  85.  */
  86. if (oldvar == NULL)
  87. {
  88. List    *tlist = rel->targetlist;
  89. Var    *newvar = makeVar(var->varno,
  90.  var->varattno,
  91.  var->vartype,
  92.  var->vartypmod,
  93.  var->varlevelsup,
  94.  var->varno,
  95.  var->varoattno);
  96. rel->targetlist = lappend(tlist,
  97.   create_tl_element(newvar,
  98. length(tlist) + 1));
  99. }
  100. }
  101. /*
  102.  * create_tl_element
  103.  *   Creates a target list entry node and its associated (resdom var) pair
  104.  *   with its resdom number equal to 'resdomno' and the joinlist field set
  105.  *   to 'joinlist'.
  106.  *
  107.  * RETURNS:  newly created tlist_entry
  108.  * CREATES:  new targetlist entry (always).
  109.  */
  110. TargetEntry *
  111. create_tl_element(Var *var, int resdomno)
  112. {
  113. return makeTargetEntry(makeResdom(resdomno,
  114.   var->vartype,
  115.   var->vartypmod,
  116.   NULL,
  117.   (Index) 0,
  118.   (Oid) 0,
  119.   false),
  120.    (Node *) var);
  121. }
  122. /*
  123.  * get_actual_tlist
  124.  *   Returns the targetlist elements from a relation tlist.
  125.  *
  126.  */
  127. List *
  128. get_actual_tlist(List *tlist)
  129. {
  130. /*
  131.  * this function is not making sense. - ay 10/94
  132.  */
  133. #ifdef NOT_USED
  134. List    *element = NIL;
  135. List    *result = NIL;
  136. if (tlist == NULL)
  137. {
  138. elog(DEBUG, "calling get_actual_tlist with empty tlist");
  139. return NIL;
  140. }
  141. /*
  142.  * XXX - it is unclear to me what exactly get_entry should be doing,
  143.  * as it is unclear to me the exact relationship between "TL" "TLE"
  144.  * and joinlists
  145.  */
  146. foreach(element, tlist)
  147. result = lappend(result, lfirst((List *) lfirst(element)));
  148. return result;
  149. #endif
  150. return tlist;
  151. }
  152. /*****************************************************************************
  153.  * ---------- GENERAL target list routines ----------
  154.  *****************************************************************************/
  155. /*
  156.  * tlist_member
  157.  *   Determines whether a var node is already contained within a
  158.  *   target list.
  159.  *
  160.  * 'var' is the var node
  161.  * 'tlist' is the target list
  162.  *
  163.  * Returns the resdom entry of the matching var node, or NULL if no match.
  164.  *
  165.  */
  166. Resdom *
  167. tlist_member(Var *var, List *tlist)
  168. {
  169. if (var)
  170. {
  171. List    *i;
  172. foreach(i, tlist)
  173. {
  174. TargetEntry *tle = (TargetEntry *) lfirst(i);
  175. if (var_equal(var, get_expr(tle)))
  176. return tle->resdom;
  177. }
  178. }
  179. return (Resdom *) NULL;
  180. }
  181. /*
  182.  *  Routine to get the resdom out of a targetlist.
  183.  */
  184. Resdom *
  185. tlist_resdom(List *tlist, Resdom *resnode)
  186. {
  187. List    *i;
  188. foreach(i, tlist)
  189. {
  190. TargetEntry *tle = (TargetEntry *) lfirst(i);
  191. Resdom    *resdom = tle->resdom;
  192. /* Since resnos are supposed to be unique */
  193. if (resnode->resno == resdom->resno)
  194. return resdom;
  195. }
  196. return (Resdom *) NULL;
  197. }
  198. /*
  199.  * match_varid
  200.  *   Searches a target list for an entry with some desired varid.
  201.  *
  202.  * 'varid' is the desired id
  203.  * 'tlist' is the target list that is searched
  204.  *
  205.  * Returns the target list entry (resdom var) of the matching var.
  206.  *
  207.  * Now checks to make sure array references (in addition to range
  208.  * table indices) are identical - retrieve (a.b[1],a.b[2]) should
  209.  * not be turned into retrieve (a.b[1],a.b[1]).
  210.  *
  211.  * [what used to be varid is now broken up into two fields varnoold and
  212.  * varoattno. Also, nested attnos are long gone. - ay 2/95]
  213.  */
  214. TargetEntry *
  215. match_varid(Var *test_var, List *tlist)
  216. {
  217. List    *tl;
  218. Oid type_var;
  219. type_var = (Oid) test_var->vartype;
  220. Assert(test_var->varlevelsup == 0);
  221. foreach(tl, tlist)
  222. {
  223. TargetEntry *entry;
  224. Var    *tlvar;
  225. entry = lfirst(tl);
  226. tlvar = get_expr(entry);
  227. if (!IsA(tlvar, Var))
  228. continue;
  229. /*
  230.  * we test the original varno (instead of varno which might be
  231.  * changed to INNER/OUTER.
  232.  */
  233. Assert(tlvar->varlevelsup == 0);
  234. if (tlvar->varnoold == test_var->varnoold &&
  235. tlvar->varoattno == test_var->varoattno)
  236. {
  237. if (tlvar->vartype == type_var)
  238. return entry;
  239. }
  240. }
  241. return NULL;
  242. }
  243. /*
  244.  * new_unsorted_tlist
  245.  *   Creates a copy of a target list by creating new resdom nodes
  246.  *   without sort information.
  247.  *
  248.  * 'targetlist' is the target list to be copied.
  249.  *
  250.  * Returns the resulting target list.
  251.  *
  252.  */
  253. List *
  254. new_unsorted_tlist(List *targetlist)
  255. {
  256. List    *new_targetlist = (List *) copyObject((Node *) targetlist);
  257. List    *x;
  258. foreach(x, new_targetlist)
  259. {
  260. TargetEntry *tle = (TargetEntry *) lfirst(x);
  261. tle->resdom->reskey = 0;
  262. tle->resdom->reskeyop = (Oid) 0;
  263. }
  264. return new_targetlist;
  265. }
  266. /*
  267.  * copy_vars
  268.  *   Replaces the var nodes in the first target list with those from
  269.  *   the second target list.  The two target lists are assumed to be
  270.  *   identical except their actual resdoms and vars are different.
  271.  *
  272.  * 'target' is the target list to be replaced
  273.  * 'source' is the target list to be copied
  274.  *
  275.  * Returns a new target list.
  276.  *
  277.  */
  278. List *
  279. copy_vars(List *target, List *source)
  280. {
  281. List    *result = NIL;
  282. List    *src = NIL;
  283. List    *dest = NIL;
  284. for (src = source, dest = target; src != NIL &&
  285.  dest != NIL; src = lnext(src), dest = lnext(dest))
  286. {
  287. TargetEntry *temp = makeTargetEntry(((TargetEntry *) lfirst(dest))->resdom,
  288.  (Node *) get_expr(lfirst(src)));
  289. result = lappend(result, temp);
  290. }
  291. return result;
  292. }
  293. /*
  294.  * flatten_tlist
  295.  *   Create a target list that only contains unique variables.
  296.  *
  297.  *
  298.  * 'tlist' is the current target list
  299.  *
  300.  * Returns the "flattened" new target list.
  301.  *
  302.  */
  303. List *
  304. flatten_tlist(List *tlist)
  305. {
  306. int last_resdomno = 1;
  307. List    *new_tlist = NIL;
  308. List    *tlist_vars = NIL;
  309. List    *temp;
  310. foreach(temp, tlist)
  311. {
  312. TargetEntry *temp_entry = (TargetEntry *) lfirst(temp);
  313. tlist_vars = nconc(tlist_vars,
  314.  pull_var_clause((Node *) get_expr(temp_entry)));
  315. }
  316. foreach(temp, tlist_vars)
  317. {
  318. Var    *var = lfirst(temp);
  319. if (!(tlist_member(var, new_tlist)))
  320. {
  321. Resdom    *r;
  322. r = makeResdom(last_resdomno,
  323.    var->vartype,
  324.    var->vartypmod,
  325.    NULL,
  326.    (Index) 0,
  327.    (Oid) 0,
  328.    false);
  329. last_resdomno++;
  330. new_tlist = lappend(new_tlist, makeTargetEntry(r, (Node *) var));
  331. }
  332. }
  333. return new_tlist;
  334. }
  335. /*
  336.  * flatten_tlist_vars
  337.  *   Redoes the target list of a query with no nested attributes by
  338.  *   replacing vars within computational expressions with vars from
  339.  *   the 'flattened' target list of the query.
  340.  *
  341.  * 'full_tlist' is the actual target list
  342.  * 'flat_tlist' is the flattened (var-only) target list
  343.  *
  344.  * Returns the modified actual target list.
  345.  *
  346.  */
  347. List *
  348. flatten_tlist_vars(List *full_tlist, List *flat_tlist)
  349. {
  350. List    *result = NIL;
  351. List    *x;
  352. foreach(x, full_tlist)
  353. {
  354. TargetEntry *tle = lfirst(x);
  355. result = lappend(result, makeTargetEntry(tle->resdom,
  356.    flatten_tlistentry((Node *) get_expr(tle),
  357.   flat_tlist)));
  358. }
  359. return result;
  360. }
  361. /*
  362.  * flatten_tlistentry
  363.  *   Replaces vars within a target list entry with vars from a flattened
  364.  *   target list.
  365.  *
  366.  * 'tlistentry' is the target list entry to be modified
  367.  * 'flat_tlist' is the flattened target list
  368.  *
  369.  * Returns the (modified) target_list entry from the target list.
  370.  *
  371.  */
  372. static Node *
  373. flatten_tlistentry(Node *tlistentry, List *flat_tlist)
  374. {
  375. List    *temp;
  376. if (tlistentry == NULL)
  377. return NULL;
  378. else if (IsA(tlistentry, Var))
  379. return (Node *) get_expr(match_varid((Var *) tlistentry,
  380.  flat_tlist));
  381. else if (single_node(tlistentry))
  382. return tlistentry;
  383. else if (IsA(tlistentry, Iter))
  384. {
  385. ((Iter *) tlistentry)->iterexpr =
  386. flatten_tlistentry((Node *) ((Iter *) tlistentry)->iterexpr,
  387.    flat_tlist);
  388. return tlistentry;
  389. }
  390. else if (is_subplan(tlistentry))
  391. {
  392. /* do we need to support this case? */
  393. elog(ERROR, "flatten_tlistentry: subplan case not implemented");
  394. return tlistentry;
  395. }
  396. else if (IsA(tlistentry, Expr))
  397. {
  398. /*
  399.  * Recursively scan the arguments of an expression. NOTE: this
  400.  * must come after is_subplan() case since subplan is a kind of
  401.  * Expr node.
  402.  */
  403. foreach(temp, ((Expr *) tlistentry)->args)
  404. lfirst(temp) = flatten_tlistentry(lfirst(temp), flat_tlist);
  405. return tlistentry;
  406. }
  407. else if (IsA(tlistentry, Aggref))
  408. {
  409. /*
  410.  * XXX shouldn't this be recursing into the agg's target? Seems to
  411.  * work though, so will leave it alone ... tgl 5/99
  412.  */
  413. return tlistentry;
  414. }
  415. else if (IsA(tlistentry, ArrayRef))
  416. {
  417. ArrayRef   *aref = (ArrayRef *) tlistentry;
  418. foreach(temp, aref->refupperindexpr)
  419. lfirst(temp) = flatten_tlistentry(lfirst(temp), flat_tlist);
  420. foreach(temp, aref->reflowerindexpr)
  421. lfirst(temp) = flatten_tlistentry(lfirst(temp), flat_tlist);
  422. aref->refexpr = flatten_tlistentry(aref->refexpr, flat_tlist);
  423. aref->refassgnexpr = flatten_tlistentry(aref->refassgnexpr, flat_tlist);
  424. return tlistentry;
  425. }
  426. else if (case_clause(tlistentry))
  427. {
  428. CaseExpr   *cexpr = (CaseExpr *) tlistentry;
  429. foreach(temp, cexpr->args)
  430. {
  431. CaseWhen   *cwhen = (CaseWhen *) lfirst(temp);
  432. cwhen->expr = flatten_tlistentry(cwhen->expr, flat_tlist);
  433. cwhen->result = flatten_tlistentry(cwhen->result, flat_tlist);
  434. }
  435. cexpr->defresult = flatten_tlistentry(cexpr->defresult, flat_tlist);
  436. return tlistentry;
  437. }
  438. else
  439. {
  440. elog(ERROR, "flatten_tlistentry: Cannot handle node type %d",
  441.  nodeTag(tlistentry));
  442. return tlistentry;
  443. }
  444. }
  445. Var *
  446. get_expr(TargetEntry *tle)
  447. {
  448. Assert(tle != NULL);
  449. Assert(tle->expr != NULL);
  450. return (Var *) tle->expr;
  451. }
  452. Var *
  453. get_groupclause_expr(GroupClause *groupClause, List *targetList)
  454. {
  455. List    *l;
  456. TargetEntry *tle;
  457. foreach(l, targetList)
  458. {
  459. tle = (TargetEntry *) lfirst(l);
  460. if (tle->resdom->resgroupref == groupClause->tleGroupref)
  461. return get_expr(tle);
  462. }
  463. elog(ERROR,
  464. "get_groupclause_expr: GROUP BY expression not found in targetlist");
  465. return NULL;
  466. }
  467. /*****************************************************************************
  468.  *
  469.  *****************************************************************************/
  470. /*
  471.  * AddGroupAttrToTlist -
  472.  *   append the group attribute to the target list if it's not already
  473.  *   in there.
  474.  */
  475. #ifdef NOT_USED
  476. /*
  477.  * WARNING!!! If this ever get's used again, the new reference
  478.  * mechanism from group clause to targetlist entry must be implemented
  479.  * here too. Jan
  480.  */
  481. void
  482. AddGroupAttrToTlist(List *tlist, List *grpCl)
  483. {
  484. List    *gl;
  485. int last_resdomno = length(tlist) + 1;
  486. foreach(gl, grpCl)
  487. {
  488. GroupClause *gc = (GroupClause *) lfirst(gl);
  489. Var    *var = gc->grpAttr;
  490. if (!(tlist_member(var, tlist)))
  491. {
  492. Resdom    *r;
  493. r = makeResdom(last_resdomno,
  494.    var->vartype,
  495.    var->vartypmod,
  496.    NULL,
  497.    (Index) 0,
  498.    (Oid) 0,
  499.    false);
  500. last_resdomno++;
  501. tlist = lappend(tlist, makeTargetEntry(r, (Node *) var));
  502. }
  503. }
  504. }
  505. #endif