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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * xfunc.c
  4.  *   Utility routines to handle expensive function optimization.
  5.  *   Includes xfunc_trypullup(), which attempts early pullup of predicates
  6.  *   to allow for maximal pruning.
  7.  *
  8.  * Copyright (c) 1994, Regents of the University of California
  9.  *
  10.  *
  11.  * IDENTIFICATION
  12.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/path/_deadcode/xfunc.c,v 1.5 1999/07/03 00:32:42 momjian Exp $
  13.  *
  14.  *-------------------------------------------------------------------------
  15.  */
  16. #include <math.h> /* for MAXFLOAT on most systems */
  17. #include <values.h> /* for MAXFLOAT on SunOS */
  18. #include <string.h>
  19. #include "postgres.h"
  20. #include "access/htup.h"
  21. #include "access/heapam.h"
  22. #include "catalog/pg_language.h"
  23. #include "catalog/pg_proc.h"
  24. #include "catalog/pg_type.h"
  25. #include "lib/lispsort.h"
  26. #include "nodes/nodes.h"
  27. #include "nodes/pg_list.h"
  28. #include "nodes/primnodes.h"
  29. #include "nodes/relation.h"
  30. #include "optimizer/clauses.h"
  31. #include "optimizer/cost.h"
  32. #include "optimizer/internal.h"
  33. #include "optimizer/keys.h"
  34. #include "optimizer/pathnode.h"
  35. #include "optimizer/tlist.h" /* for get_expr */
  36. #include "optimizer/xfunc.h"
  37. #include "storage/buf_internals.h" /* for NBuffers */
  38. #include "tcop/dest.h"
  39. #include "utils/syscache.h"
  40. #define ever ; 1 ;
  41. /* local funcs */
  42. static int xfunc_card_unreferenced(Query *queryInfo,
  43. Expr *clause, Relids referenced);
  44. */
  45. /*
  46. ** xfunc_trypullup
  47. **   Preliminary pullup of predicates, to allow for maximal pruning.
  48. ** Given a relation, check each of its paths and see if you can
  49. ** pullup clauses from its inner and outer.
  50. */
  51. void
  52. xfunc_trypullup(RelOptInfo rel)
  53. {
  54. LispValue y; /* list ptr */
  55. RestrictInfo maxcinfo; /* The RestrictInfo to pull up, as
  56.  * calculated by xfunc_shouldpull() */
  57. JoinPath curpath; /* current path in list */
  58. int progress; /* has progress been made this time
  59.  * through? */
  60. int clausetype;
  61. do
  62. {
  63. progress = false; /* no progress yet in this iteration */
  64. foreach(y, get_pathlist(rel))
  65. {
  66. curpath = (JoinPath) lfirst(y);
  67. /*
  68.  * * for each operand, attempt to pullup predicates until
  69.  * first * failure.
  70.  */
  71. for (ever)
  72. {
  73. /* No, the following should NOT be '=='  !! */
  74. if (clausetype = xfunc_shouldpull((Path) get_innerjoinpath(curpath),
  75.   curpath, INNER, &maxcinfo))
  76. {
  77. xfunc_pullup((Path) get_innerjoinpath(curpath),
  78.  curpath, maxcinfo, INNER, clausetype);
  79. progress = true;
  80. }
  81. else
  82. break;
  83. }
  84. for (ever)
  85. {
  86. /* No, the following should NOT be '=='  !! */
  87. if (clausetype = xfunc_shouldpull((Path) get_outerjoinpath(curpath),
  88.   curpath, OUTER, &maxcinfo))
  89. {
  90. xfunc_pullup((Path) get_outerjoinpath(curpath),
  91.  curpath, maxcinfo, OUTER, clausetype);
  92. progress = true;
  93. }
  94. else
  95. break;
  96. }
  97. /*
  98.  * * make sure the unpruneable flag bubbles up, i.e. * if
  99.  * anywhere below us in the path pruneable is false, * then
  100.  * pruneable should be false here
  101.  */
  102. if (get_pruneable(get_parent(curpath)) &&
  103. (!get_pruneable(get_parent
  104. ((Path) get_innerjoinpath(curpath))) ||
  105.  !get_pruneable(get_parent((Path)
  106.    get_outerjoinpath(curpath)))))
  107. {
  108. set_pruneable(get_parent(curpath), false);
  109. progress = true;
  110. }
  111. }
  112. } while (progress);
  113. }
  114. /*
  115.  ** xfunc_shouldpull
  116.  **    find clause with highest rank, and decide whether to pull it up
  117.  ** from child to parent.  Currently we only pullup secondary join clauses
  118.  ** that are in the pathrestrictinfo.  Secondary hash and sort clauses are
  119.  ** left where they are.
  120.  **    If we find an expensive function but decide *not* to pull it up,
  121.  ** we'd better set the unpruneable flag.  -- JMH, 11/11/92
  122.  **
  123.  ** Returns:  0 if nothing left to pullup
  124.  **   XFUNC_LOCPRD if a local predicate is to be pulled up
  125.  **   XFUNC_JOINPRD if a secondary join predicate is to be pulled up
  126.  */
  127. int
  128. xfunc_shouldpull(Query *queryInfo,
  129.  Path childpath,
  130.  JoinPath parentpath,
  131.  int whichchild,
  132.  RestrictInfo *maxcinfopt) /* Out: pointer to clause
  133.  * to pullup */
  134. {
  135. LispValue clauselist,
  136. tmplist; /* lists of clauses */
  137. RestrictInfo maxcinfo; /* clause to pullup */
  138. LispValue primjoinclause /* primary join clause */
  139. = xfunc_primary_join(parentpath);
  140. Cost tmprank,
  141. maxrank = (-1 * MAXFLOAT); /* ranks of clauses */
  142. Cost joinselec = 0; /* selectivity of the join predicate */
  143. Cost joincost = 0; /* join cost + primjoinclause cost */
  144. int retval = XFUNC_LOCPRD;
  145. clauselist = get_loc_restrictinfo(childpath);
  146. if (clauselist != LispNil)
  147. {
  148. /* find local predicate with maximum rank */
  149. for (tmplist = clauselist,
  150.  maxcinfo = (RestrictInfo) lfirst(tmplist),
  151.  maxrank = xfunc_rank(get_clause(maxcinfo));
  152.  tmplist != LispNil;
  153.  tmplist = lnext(tmplist))
  154. {
  155. if ((tmprank = xfunc_rank(get_clause((RestrictInfo) lfirst(tmplist))))
  156. > maxrank)
  157. {
  158. maxcinfo = (RestrictInfo) lfirst(tmplist);
  159. maxrank = tmprank;
  160. }
  161. }
  162. }
  163. /*
  164.  * * If child is a join path, and there are multiple join clauses, *
  165.  * see if any join clause has even higher rank than the highest *
  166.  * local predicate
  167.  */
  168. if (is_join(childpath) && xfunc_num_join_clauses((JoinPath) childpath) > 1)
  169. for (tmplist = get_pathrestrictinfo((JoinPath) childpath);
  170.  tmplist != LispNil;
  171.  tmplist = lnext(tmplist))
  172. {
  173. if (tmplist != LispNil &&
  174. (tmprank = xfunc_rank(get_clause((RestrictInfo) lfirst(tmplist))))
  175. > maxrank)
  176. {
  177. maxcinfo = (RestrictInfo) lfirst(tmplist);
  178. maxrank = tmprank;
  179. retval = XFUNC_JOINPRD;
  180. }
  181. }
  182. if (maxrank == (-1 * MAXFLOAT)) /* no expensive clauses */
  183. return 0;
  184. /*
  185.  * * Pullup over join if clause is higher rank than join, or if * join
  186.  * is nested loop and current path is inner child (note that *
  187.  * restrictions on the inner of a nested loop don't buy you anything
  188.  * -- * you still have to scan the entire inner relation each time). *
  189.  * Note that the cost of a secondary join clause is only what's *
  190.  * calculated by xfunc_expense(), since the actual joining * (i.e. the
  191.  * usual path_cost) is paid for by the primary join clause.
  192.  */
  193. if (primjoinclause != LispNil)
  194. {
  195. joinselec = compute_clause_selec(queryInfo, primjoinclause, LispNil);
  196. joincost = xfunc_join_expense(parentpath, whichchild);
  197. if (XfuncMode == XFUNC_PULLALL ||
  198. (XfuncMode != XFUNC_WAIT &&
  199.  ((joincost != 0 &&
  200.    (maxrank = xfunc_rank(get_clause(maxcinfo))) >
  201.    ((joinselec - 1.0) / joincost))
  202.   || (joincost == 0 && joinselec < 1)
  203.   || (!is_join(childpath)
  204.   && (whichchild == INNER)
  205.   && IsA(parentpath, NestPath)
  206.   &&!IsA(parentpath, HashPath)
  207.   &&!IsA(parentpath, MergePath)))))
  208. {
  209. *maxcinfopt = maxcinfo;
  210. return retval;
  211. }
  212. else if (maxrank != -(MAXFLOAT))
  213. {
  214. /*
  215.  * * we've left an expensive restriction below a join.  Since *
  216.  * we may pullup this restriction in predmig.c, we'd best *
  217.  * set the RelOptInfo of this join to be unpruneable
  218.  */
  219. set_pruneable(get_parent(parentpath), false);
  220. /* and fall through */
  221. }
  222. }
  223. return 0;
  224. }
  225. /*
  226.  ** xfunc_pullup
  227.  **    move clause from child pathnode to parent pathnode.  This operation
  228.  ** makes the child pathnode produce a larger relation than it used to.
  229.  ** This means that we must construct a new RelOptInfo just for the childpath,
  230.  ** although this RelOptInfo will not be added to the list of Rels to be joined up
  231.  ** in the query; it's merely a parent for the new childpath.
  232.  **    We also have to fix up the path costs of the child and parent.
  233.  **
  234.  ** Now returns a pointer to the new pulled-up RestrictInfo. -- JMH, 11/18/92
  235.  */
  236. RestrictInfo
  237. xfunc_pullup(Query *queryInfo,
  238.  Path childpath,
  239.  JoinPath parentpath,
  240.  RestrictInfo cinfo,/* clause to pull up */
  241.  int whichchild, /* whether child is INNER or OUTER of join */
  242.  int clausetype) /* whether clause to pull is join or local */
  243. {
  244. Path newkid;
  245. RelOptInfo newrel;
  246. Cost pulled_selec;
  247. Cost cost;
  248. RestrictInfo newinfo;
  249. /* remove clause from childpath */
  250. newkid = (Path) copyObject((Node) childpath);
  251. if (clausetype == XFUNC_LOCPRD)
  252. {
  253. set_locrestrictinfo(newkid,
  254. xfunc_LispRemove((LispValue) cinfo,
  255.    (List) get_loc_restrictinfo(newkid)));
  256. }
  257. else
  258. {
  259. set_pathrestrictinfo
  260. ((JoinPath) newkid,
  261.  xfunc_LispRemove((LispValue) cinfo,
  262. (List) get_pathrestrictinfo((JoinPath) newkid)));
  263. }
  264. /*
  265.  * * give the new child path its own RelOptInfo node that reflects the *
  266.  * lack of the pulled-up predicate
  267.  */
  268. pulled_selec = compute_clause_selec(queryInfo,
  269. get_clause(cinfo), LispNil);
  270. xfunc_copyrel(get_parent(newkid), &newrel);
  271. set_parent(newkid, newrel);
  272. set_pathlist(newrel, lcons(newkid, NIL));
  273. set_unorderedpath(newrel, (PathPtr) newkid);
  274. set_cheapestpath(newrel, (PathPtr) newkid);
  275. set_size(newrel,
  276. (Count) ((Cost) get_size(get_parent(childpath)) / pulled_selec));
  277. /*
  278.  * * fix up path cost of newkid.  To do this we subtract away all the *
  279.  * xfunc_costs of childpath, then recompute the xfunc_costs of newkid
  280.  */
  281. cost = get_path_cost(newkid) - xfunc_get_path_cost(childpath);
  282. Assert(cost >= 0);
  283. set_path_cost(newkid, cost);
  284. cost = get_path_cost(newkid) + xfunc_get_path_cost(newkid);
  285. set_path_cost(newkid, cost);
  286. /*
  287.  * * We copy the cinfo, since it may appear in other plans, and we're
  288.  * going * to munge it.  -- JMH, 7/22/92
  289.  */
  290. newinfo = (RestrictInfo) copyObject((Node) cinfo);
  291. /*
  292.  * * Fix all vars in the clause * to point to the right varno and
  293.  * varattno in parentpath
  294.  */
  295. xfunc_fixvars(get_clause(newinfo), newrel, whichchild);
  296. /* add clause to parentpath, and fix up its cost. */
  297. set_locrestrictinfo(parentpath,
  298. lispCons((LispValue) newinfo,
  299.   (LispValue) get_loc_restrictinfo(parentpath)));
  300. /* put new childpath into the path tree */
  301. if (whichchild == INNER)
  302. set_innerjoinpath(parentpath, (pathPtr) newkid);
  303. else
  304. set_outerjoinpath(parentpath, (pathPtr) newkid);
  305. /*
  306.  * * recompute parentpath cost from scratch -- the cost * of the join
  307.  * method has changed
  308.  */
  309. cost = xfunc_total_path_cost(parentpath);
  310. set_path_cost(parentpath, cost);
  311. return newinfo;
  312. }
  313. /*
  314.  ** calculate (selectivity-1)/cost.
  315.  */
  316. Cost
  317. xfunc_rank(Query *queryInfo, LispValue clause)
  318. {
  319. Cost selec = compute_clause_selec(queryInfo, clause, LispNil);
  320. Cost cost = xfunc_expense(queryInfo, clause);
  321. if (cost == 0)
  322. if (selec > 1)
  323. return MAXFLOAT;
  324. else
  325. return -(MAXFLOAT);
  326. return (selec - 1) / cost;
  327. }
  328. /*
  329.  ** Find the "global" expense of a clause; i.e. the local expense divided
  330.  ** by the cardinalities of all the base relations of the query that are *not*
  331.  ** referenced in the clause.
  332.  */
  333. Cost
  334. xfunc_expense(Query *queryInfo, clause)
  335. LispValue clause;
  336. {
  337. Cost cost = xfunc_local_expense(clause);
  338. if (cost)
  339. {
  340. Count card = xfunc_card_unreferenced(queryInfo, clause, LispNil);
  341. if (card)
  342. cost /= card;
  343. }
  344. return cost;
  345. }
  346. /*
  347.  ** xfunc_join_expense
  348.  **    Find global expense of a join clause
  349.  */
  350. Cost
  351. xfunc_join_expense(Query *queryInfo, JoinPath path, int whichchild)
  352. {
  353. LispValue primjoinclause = xfunc_primary_join(path);
  354. /*
  355.  * * the second argument to xfunc_card_unreferenced reflects all the *
  356.  * relations involved in the join clause, i.e. all the relids in the
  357.  * RelOptInfo * of the join clause
  358.  */
  359. Count card = 0;
  360. Cost cost = xfunc_expense_per_tuple(path, whichchild);
  361. card = xfunc_card_unreferenced(queryInfo,
  362.    primjoinclause,
  363.    get_relids(get_parent(path)));
  364. if (primjoinclause)
  365. cost += xfunc_local_expense(primjoinclause);
  366. if (card)
  367. cost /= card;
  368. return cost;
  369. }
  370. /*
  371.  ** Recursively find the per-tuple expense of a clause.  See
  372.  ** xfunc_func_expense for more discussion.
  373.  */
  374. Cost
  375. xfunc_local_expense(LispValue clause)
  376. {
  377. Cost cost = 0; /* running expense */
  378. LispValue tmpclause;
  379. /* First handle the base case */
  380. if (IsA(clause, Const) ||IsA(clause, Var) ||IsA(clause, Param))
  381. return 0;
  382. /* now other stuff */
  383. else if (IsA(clause, Iter))
  384. /* Too low. Should multiply by the expected number of iterations. */
  385. return xfunc_local_expense(get_iterexpr((Iter) clause));
  386. else if (IsA(clause, ArrayRef))
  387. return xfunc_local_expense(get_refexpr((ArrayRef) clause));
  388. else if (fast_is_clause(clause))
  389. return (xfunc_func_expense((LispValue) get_op(clause),
  390.    (LispValue) get_opargs(clause)));
  391. else if (fast_is_funcclause(clause))
  392. return (xfunc_func_expense((LispValue) get_function(clause),
  393.    (LispValue) get_funcargs(clause)));
  394. else if (fast_not_clause(clause))
  395. return xfunc_local_expense(lsecond(clause));
  396. else if (fast_or_clause(clause) || fast_and_clause(clause))
  397. {
  398. /* find cost of evaluating each disjunct */
  399. for (tmpclause = lnext(clause); tmpclause != LispNil;
  400.  tmpclause = lnext(tmpclause))
  401. cost += xfunc_local_expense(lfirst(tmpclause));
  402. return cost;
  403. }
  404. else
  405. {
  406. elog(ERROR, "Clause node of undetermined type");
  407. return -1;
  408. }
  409. }
  410. /*
  411.  ** xfunc_func_expense
  412.  **    given a Func or Oper and its args, find its expense.
  413.  ** Note: in Stonebraker's SIGMOD '91 paper, he uses a more complicated metric
  414.  ** than the one here. We can ignore the expected number of tuples for
  415.  ** our calculations; we just need the per-tuple expense.  But he also
  416.  ** proposes components to take into account the costs of accessing disk and
  417.  ** archive.  We didn't adopt that scheme here; eventually the vacuum
  418.  ** cleaner should be able to tell us what percentage of bytes to find on
  419.  ** which storage level, and that should be multiplied in appropriately
  420.  ** in the cost function below.  Right now we don't model the cost of
  421.  ** accessing secondary or tertiary storage, since we don't have sufficient
  422.  ** stats to do it right.
  423.  */
  424. Cost
  425. xfunc_func_expense(LispValue node, LispValue args)
  426. {
  427. HeapTuple tupl; /* the pg_proc tuple for each function */
  428. Form_pg_proc proc; /* a data structure to hold the pg_proc
  429.  * tuple */
  430. int width = 0; /* byte width of the field referenced by
  431.  * each clause */
  432. RegProcedure funcid; /* ID of function associate with node */
  433. Cost cost = 0; /* running expense */
  434. LispValue tmpclause;
  435. LispValue operand; /* one operand of an operator */
  436. if (IsA(node, Oper))
  437. {
  438. /* don't trust the opid in the Oper node.  Use the opno. */
  439. if (!(funcid = get_opcode(get_opno((Oper) node))))
  440. elog(ERROR, "Oper's function is undefined");
  441. }
  442. else
  443. funcid = get_funcid((Func) node);
  444. /* look up tuple in cache */
  445. tupl = SearchSysCacheTuple(PROOID,
  446.    ObjectIdGetDatum(funcid),
  447.    0, 0, 0);
  448. if (!HeapTupleIsValid(tupl))
  449. elog(ERROR, "Cache lookup failed for procedure %u", funcid);
  450. proc = (Form_pg_proc) GETSTRUCT(tupl);
  451. /*
  452.  * * if it's a Postquel function, its cost is stored in the *
  453.  * associated plan.
  454.  */
  455. if (proc->prolang == SQLlanguageId)
  456. {
  457. LispValue tmpplan;
  458. List planlist;
  459. if (IsA(node, Oper) ||get_func_planlist((Func) node) == LispNil)
  460. {
  461. Oid    *argOidVect; /* vector of argtypes */
  462. char    *pq_src; /* text of PQ function */
  463. int nargs; /* num args to PQ function */
  464. QueryTreeList *queryTree_list; /* dummy variable */
  465. /*
  466.  * * plan the function, storing it in the Func node for later *
  467.  * use by the executor.
  468.  */
  469. pq_src = (char *) textout(&(proc->prosrc));
  470. nargs = proc->pronargs;
  471. if (nargs > 0)
  472. argOidVect = proc->proargtypes;
  473. planlist = (List) pg_parse_and_plan(pq_src, argOidVect, nargs,
  474.    &parseTree_list, None, FALSE);
  475. if (IsA(node, Func))
  476. set_func_planlist((Func) node, planlist);
  477. }
  478. else
  479. { /* plan has been cached inside the Func
  480.  * node already */
  481. planlist = get_func_planlist((Func) node);
  482. }
  483. /*
  484.  * * Return the sum of the costs of the plans (the PQ function *
  485.  * may have many queries in its body).
  486.  */
  487. foreach(tmpplan, planlist)
  488. cost += get_cost((Plan) lfirst(tmpplan));
  489. return cost;
  490. }
  491. else
  492. { /* it's a C function */
  493. /*
  494.  * *  find the cost of evaluating the function's arguments *  and
  495.  * the width of the operands
  496.  */
  497. for (tmpclause = args; tmpclause != LispNil;
  498.  tmpclause = lnext(tmpclause))
  499. {
  500. if ((operand = lfirst(tmpclause)) != LispNil)
  501. {
  502. cost += xfunc_local_expense(operand);
  503. width += xfunc_width(operand);
  504. }
  505. }
  506. /*
  507.  * * when stats become available, add in cost of accessing
  508.  * secondary * and tertiary storage here.
  509.  */
  510. return (cost +
  511. (Cost) proc->propercall_cpu +
  512. (Cost) proc->properbyte_cpu * (Cost) proc->probyte_pct / 100.00 *
  513. (Cost) width
  514. /*
  515.  * Pct_of_obj_in_mem DISK_COST * proc->probyte_pct/100.00 * width
  516.  * Pct_of_obj_on_disk + ARCH_COST * proc->probyte_pct/100.00 *
  517.  * width Pct_of_obj_on_arch
  518.  */
  519. );
  520. }
  521. }
  522. /*
  523.  ** xfunc_width
  524.  **    recursively find the width of a expression
  525.  */
  526. int
  527. xfunc_width(LispValue clause)
  528. {
  529. Relation rd; /* Relation Descriptor */
  530. HeapTuple tupl; /* structure to hold a cached tuple */
  531. Form_pg_type type; /* structure to hold a type tuple */
  532. int retval = 0;
  533. if (IsA(clause, Const))
  534. {
  535. /* base case: width is the width of this constant */
  536. retval = get_constlen((Const) clause);
  537. goto exit;
  538. }
  539. else if (IsA(clause, ArrayRef))
  540. {
  541. /* base case: width is width of the refelem within the array */
  542. retval = get_refelemlength((ArrayRef) clause);
  543. goto exit;
  544. }
  545. else if (IsA(clause, Var))
  546. {
  547. /* base case: width is width of this attribute */
  548. tupl = SearchSysCacheTuple(TYPOID,
  549.  ObjectIdGetDatum(get_vartype((Var) clause)),
  550.    0, 0, 0);
  551. if (!HeapTupleIsValid(tupl))
  552. elog(ERROR, "Cache lookup failed for type %u",
  553.  get_vartype((Var) clause));
  554. type = (Form_pg_type) GETSTRUCT(tupl);
  555. if (get_varattno((Var) clause) == 0)
  556. {
  557. /* clause is a tuple.  Get its width */
  558. rd = heap_open(type->typrelid);
  559. retval = xfunc_tuple_width(rd);
  560. heap_close(rd);
  561. }
  562. else
  563. {
  564. /* attribute is a base type */
  565. retval = type->typlen;
  566. }
  567. goto exit;
  568. }
  569. else if (IsA(clause, Param))
  570. {
  571. if (typeidTypeRelids(get_paramtype((Param) clause)))
  572. {
  573. /* Param node returns a tuple. Find its width */
  574. rd = heap_open(typeidTypeRelids(get_paramtype((Param) clause)));
  575. retval = xfunc_tuple_width(rd);
  576. heap_close(rd);
  577. }
  578. else if (get_param_tlist((Param) clause) != LispNil)
  579. {
  580. /* Param node projects a complex type */
  581. Assert(length(get_param_tlist((Param) clause)) == 1); /* sanity */
  582. retval = xfunc_width((LispValue)
  583.   get_expr(lfirst(get_param_tlist((Param) clause))));
  584. }
  585. else
  586. {
  587. /* Param node returns a base type */
  588. retval = typeLen(typeidType(get_paramtype((Param) clause)));
  589. }
  590. goto exit;
  591. }
  592. else if (IsA(clause, Iter))
  593. {
  594. /*
  595.  * * An Iter returns a setof things, so return the width of a
  596.  * single * thing. * Note: THIS MAY NOT WORK RIGHT WHEN AGGS GET
  597.  * FIXED, * SINCE AGG FUNCTIONS CHEW ON THE WHOLE SETOF THINGS!!!! *
  598.  * This whole Iter business is bogus, anyway.
  599.  */
  600. retval = xfunc_width(get_iterexpr((Iter) clause));
  601. goto exit;
  602. }
  603. else if (fast_is_clause(clause))
  604. {
  605. /*
  606.  * * get function associated with this Oper, and treat this as * a
  607.  * Func
  608.  */
  609. tupl = SearchSysCacheTuple(OPROID,
  610.    ObjectIdGetDatum(get_opno((Oper) get_op(clause))),
  611.    0, 0, 0);
  612. if (!HeapTupleIsValid(tupl))
  613. elog(ERROR, "Cache lookup failed for procedure %u",
  614.  get_opno((Oper) get_op(clause)));
  615. return (xfunc_func_width
  616. ((RegProcedure) (((Form_pg_operator) (GETSTRUCT(tupl)))->oprcode),
  617.  (LispValue) get_opargs(clause)));
  618. }
  619. else if (fast_is_funcclause(clause))
  620. {
  621. Func func = (Func) get_function(clause);
  622. if (get_func_tlist(func) != LispNil)
  623. {
  624. /*
  625.  * this function has a projection on it.  Get the length of
  626.  * the projected attribute
  627.  */
  628. Assert(length(get_func_tlist(func)) == 1); /* sanity */
  629. retval = xfunc_width((LispValue)
  630.  get_expr(lfirst(get_func_tlist(func))));
  631. goto exit;
  632. }
  633. else
  634. {
  635. return (xfunc_func_width((RegProcedure) get_funcid(func),
  636.  (LispValue) get_funcargs(clause)));
  637. }
  638. }
  639. else
  640. {
  641. elog(ERROR, "Clause node of undetermined type");
  642. return -1;
  643. }
  644. exit:
  645. if (retval == -1)
  646. retval = VARLEN_DEFAULT;
  647. return retval;
  648. }
  649. /*
  650.  ** xfunc_card_unreferenced:
  651.  **   find all relations not referenced in clause, and multiply their
  652.  ** cardinalities. Ignore relation of cardinality 0.
  653.  ** User may pass in referenced list, if they know it (useful
  654.  ** for joins).
  655.  */
  656. static Count
  657. xfunc_card_unreferenced(Query *queryInfo,
  658. LispValue clause, Relids referenced)
  659. {
  660. Relids unreferenced,
  661. allrelids = LispNil;
  662. LispValue temp;
  663. /* find all relids of base relations referenced in query */
  664. foreach(temp, queryInfo->base_rel_list)
  665. {
  666. Assert(lnext(get_relids((RelOptInfo) lfirst(temp))) == LispNil);
  667. allrelids = lappend(allrelids,
  668.   lfirst(get_relids((RelOptInfo) lfirst(temp))));
  669. }
  670. /* find all relids referenced in query but not in clause */
  671. if (!referenced)
  672. referenced = xfunc_find_references(clause);
  673. unreferenced = set_difference(allrelids, referenced);
  674. return xfunc_card_product(unreferenced);
  675. }
  676. /*
  677.  ** xfunc_card_product
  678.  **   multiple together cardinalities of a list relations.
  679.  */
  680. Count
  681. xfunc_card_product(Query *queryInfo, Relids relids)
  682. {
  683. LispValue cinfonode;
  684. LispValue temp;
  685. RelOptInfo currel;
  686. Cost tuples;
  687. Count retval = 0;
  688. foreach(temp, relids)
  689. {
  690. currel = get_rel(lfirst(temp));
  691. tuples = get_tuples(currel);
  692. if (tuples)
  693. { /* not of cardinality 0 */
  694. /* factor in the selectivity of all zero-cost clauses */
  695. foreach(cinfonode, get_restrictinfo(currel))
  696. {
  697. if (!xfunc_expense(queryInfo, get_clause((RestrictInfo) lfirst(cinfonode))))
  698. tuples *= compute_clause_selec(queryInfo,
  699. get_clause((RestrictInfo) lfirst(cinfonode)),
  700.    LispNil);
  701. }
  702. if (retval == 0)
  703. retval = tuples;
  704. else
  705. retval *= tuples;
  706. }
  707. }
  708. if (retval == 0)
  709. retval = 1; /* saves caller from dividing by zero */
  710. return retval;
  711. }
  712. /*
  713.  ** xfunc_find_references:
  714.  **   Traverse a clause and find all relids referenced in the clause.
  715.  */
  716. List
  717. xfunc_find_references(LispValue clause)
  718. {
  719. List retval = (List) LispNil;
  720. LispValue tmpclause;
  721. /* Base cases */
  722. if (IsA(clause, Var))
  723. return lispCons(lfirst(get_varid((Var) clause)), LispNil);
  724. else if (IsA(clause, Const) ||IsA(clause, Param))
  725. return (List) LispNil;
  726. /* recursion */
  727. else if (IsA(clause, Iter))
  728. /*
  729.  * Too low. Should multiply by the expected number of iterations.
  730.  * maybe
  731.  */
  732. return xfunc_find_references(get_iterexpr((Iter) clause));
  733. else if (IsA(clause, ArrayRef))
  734. return xfunc_find_references(get_refexpr((ArrayRef) clause));
  735. else if (fast_is_clause(clause))
  736. {
  737. /* string together result of all operands of Oper */
  738. for (tmpclause = (LispValue) get_opargs(clause); tmpclause != LispNil;
  739.  tmpclause = lnext(tmpclause))
  740. retval = nconc(retval, xfunc_find_references(lfirst(tmpclause)));
  741. return retval;
  742. }
  743. else if (fast_is_funcclause(clause))
  744. {
  745. /* string together result of all args of Func */
  746. for (tmpclause = (LispValue) get_funcargs(clause);
  747.  tmpclause != LispNil;
  748.  tmpclause = lnext(tmpclause))
  749. retval = nconc(retval, xfunc_find_references(lfirst(tmpclause)));
  750. return retval;
  751. }
  752. else if (fast_not_clause(clause))
  753. return xfunc_find_references(lsecond(clause));
  754. else if (fast_or_clause(clause) || fast_and_clause(clause))
  755. {
  756. /* string together result of all operands of OR */
  757. for (tmpclause = lnext(clause); tmpclause != LispNil;
  758.  tmpclause = lnext(tmpclause))
  759. retval = nconc(retval, xfunc_find_references(lfirst(tmpclause)));
  760. return retval;
  761. }
  762. else
  763. {
  764. elog(ERROR, "Clause node of undetermined type");
  765. return (List) LispNil;
  766. }
  767. }
  768. /*
  769.  ** xfunc_primary_join:
  770.  **   Find the primary join clause: for Hash and Merge Joins, this is the
  771.  ** min rank Hash or Merge clause, while for Nested Loop it's the
  772.  ** min rank pathclause
  773.  */
  774. LispValue
  775. xfunc_primary_join(JoinPath pathnode)
  776. {
  777. LispValue joinclauselist = get_pathrestrictinfo(pathnode);
  778. RestrictInfo mincinfo;
  779. LispValue tmplist;
  780. LispValue minclause = LispNil;
  781. Cost minrank,
  782. tmprank;
  783. if (IsA(pathnode, MergePath))
  784. {
  785. for (tmplist = get_path_mergeclauses((MergePath) pathnode),
  786.  minclause = lfirst(tmplist),
  787.  minrank = xfunc_rank(minclause);
  788.  tmplist != LispNil;
  789.  tmplist = lnext(tmplist))
  790. if ((tmprank = xfunc_rank(lfirst(tmplist)))
  791. < minrank)
  792. {
  793. minrank = tmprank;
  794. minclause = lfirst(tmplist);
  795. }
  796. return minclause;
  797. }
  798. else if (IsA(pathnode, HashPath))
  799. {
  800. for (tmplist = get_path_hashclauses((HashPath) pathnode),
  801.  minclause = lfirst(tmplist),
  802.  minrank = xfunc_rank(minclause);
  803.  tmplist != LispNil;
  804.  tmplist = lnext(tmplist))
  805. if ((tmprank = xfunc_rank(lfirst(tmplist)))
  806. < minrank)
  807. {
  808. minrank = tmprank;
  809. minclause = lfirst(tmplist);
  810. }
  811. return minclause;
  812. }
  813. /* if we drop through, it's nested loop join */
  814. if (joinclauselist == LispNil)
  815. return LispNil;
  816. for (tmplist = joinclauselist, mincinfo = (RestrictInfo) lfirst(joinclauselist),
  817.  minrank = xfunc_rank(get_clause((RestrictInfo) lfirst(tmplist)));
  818.  tmplist != LispNil;
  819.  tmplist = lnext(tmplist))
  820. if ((tmprank = xfunc_rank(get_clause((RestrictInfo) lfirst(tmplist))))
  821. < minrank)
  822. {
  823. minrank = tmprank;
  824. mincinfo = (RestrictInfo) lfirst(tmplist);
  825. }
  826. return (LispValue) get_clause(mincinfo);
  827. }
  828. /*
  829.  ** xfunc_get_path_cost
  830.  **   get the expensive function costs of the path
  831.  */
  832. Cost
  833. xfunc_get_path_cost(Query *queryInfo, Path pathnode)
  834. {
  835. Cost cost = 0;
  836. LispValue tmplist;
  837. Cost selec = 1.0;
  838. /*
  839.  * * first add in the expensive local function costs. * We ensure that
  840.  * the clauses are sorted by rank, so that we * know (via
  841.  * selectivities) the number of tuples that will be checked * by each
  842.  * function.  If we're not doing any optimization of expensive *
  843.  * functions, we don't sort.
  844.  */
  845. if (XfuncMode != XFUNC_OFF)
  846. set_locrestrictinfo(pathnode, lisp_qsort(get_loc_restrictinfo(pathnode),
  847.  xfunc_cinfo_compare));
  848. for (tmplist = get_loc_restrictinfo(pathnode), selec = 1.0;
  849.  tmplist != LispNil;
  850.  tmplist = lnext(tmplist))
  851. {
  852. cost += (Cost) (xfunc_local_expense(get_clause((RestrictInfo) lfirst(tmplist)))
  853.   * (Cost) get_tuples(get_parent(pathnode)) * selec);
  854. selec *= compute_clause_selec(queryInfo,
  855.   get_clause((RestrictInfo) lfirst(tmplist)),
  856.   LispNil);
  857. }
  858. /*
  859.  * * Now add in any node-specific expensive function costs. * Again,
  860.  * we must ensure that the clauses are sorted by rank.
  861.  */
  862. if (IsA(pathnode, JoinPath))
  863. {
  864. if (XfuncMode != XFUNC_OFF)
  865. set_pathrestrictinfo((JoinPath) pathnode, lisp_qsort
  866.   (get_pathrestrictinfo((JoinPath) pathnode),
  867.    xfunc_cinfo_compare));
  868. for (tmplist = get_pathrestrictinfo((JoinPath) pathnode), selec = 1.0;
  869.  tmplist != LispNil;
  870.  tmplist = lnext(tmplist))
  871. {
  872. cost += (Cost) (xfunc_local_expense(get_clause((RestrictInfo) lfirst(tmplist)))
  873.   * (Cost) get_tuples(get_parent(pathnode)) * selec);
  874. selec *= compute_clause_selec(queryInfo,
  875.   get_clause((RestrictInfo) lfirst(tmplist)),
  876.   LispNil);
  877. }
  878. }
  879. if (IsA(pathnode, HashPath))
  880. {
  881. if (XfuncMode != XFUNC_OFF)
  882. set_path_hashclauses
  883. ((HashPath) pathnode,
  884.  lisp_qsort(get_path_hashclauses((HashPath) pathnode),
  885. xfunc_clause_compare));
  886. for (tmplist = get_path_hashclauses((HashPath) pathnode), selec = 1.0;
  887.  tmplist != LispNil;
  888.  tmplist = lnext(tmplist))
  889. {
  890. cost += (Cost) (xfunc_local_expense(lfirst(tmplist))
  891.   * (Cost) get_tuples(get_parent(pathnode)) * selec);
  892. selec *= compute_clause_selec(queryInfo,
  893.   lfirst(tmplist), LispNil);
  894. }
  895. }
  896. if (IsA(pathnode, MergePath))
  897. {
  898. if (XfuncMode != XFUNC_OFF)
  899. set_path_mergeclauses
  900. ((MergePath) pathnode,
  901.  lisp_qsort(get_path_mergeclauses((MergePath) pathnode),
  902. xfunc_clause_compare));
  903. for (tmplist = get_path_mergeclauses((MergePath) pathnode), selec = 1.0;
  904.  tmplist != LispNil;
  905.  tmplist = lnext(tmplist))
  906. {
  907. cost += (Cost) (xfunc_local_expense(lfirst(tmplist))
  908.   * (Cost) get_tuples(get_parent(pathnode)) * selec);
  909. selec *= compute_clause_selec(queryInfo,
  910.   lfirst(tmplist), LispNil);
  911. }
  912. }
  913. Assert(cost >= 0);
  914. return cost;
  915. }
  916. /*
  917.  ** Recalculate the cost of a path node.  This includes the basic cost of the
  918.  ** node, as well as the cost of its expensive functions.
  919.  ** We need to do this to the parent after pulling a clause from a child into a
  920.  ** parent.  Thus we should only be calling this function on JoinPaths.
  921.  */
  922. Cost
  923. xfunc_total_path_cost(JoinPath pathnode)
  924. {
  925. Cost cost = xfunc_get_path_cost((Path) pathnode);
  926. Assert(IsA(pathnode, JoinPath));
  927. if (IsA(pathnode, MergePath))
  928. {
  929. MergePath mrgnode = (MergePath) pathnode;
  930. cost += cost_mergejoin(get_path_cost((Path) get_outerjoinpath(mrgnode)),
  931. get_path_cost((Path) get_innerjoinpath(mrgnode)),
  932.    get_outersortkeys(mrgnode),
  933.    get_innersortkeys(mrgnode),
  934.    get_tuples(get_parent((Path) get_outerjoinpath
  935.  (mrgnode))),
  936.    get_tuples(get_parent((Path) get_innerjoinpath
  937.  (mrgnode))),
  938. get_width(get_parent((Path) get_outerjoinpath
  939.  (mrgnode))),
  940. get_width(get_parent((Path) get_innerjoinpath
  941.  (mrgnode))));
  942. Assert(cost >= 0);
  943. return cost;
  944. }
  945. else if (IsA(pathnode, HashPath))
  946. {
  947. HashPath hashnode = (HashPath) pathnode;
  948. cost += cost_hashjoin(get_path_cost((Path) get_outerjoinpath(hashnode)),
  949.    get_path_cost((Path) get_innerjoinpath(hashnode)),
  950.   get_outerhashkeys(hashnode),
  951.   get_innerhashkeys(hashnode),
  952.    get_tuples(get_parent((Path) get_outerjoinpath
  953.  (hashnode))),
  954.    get_tuples(get_parent((Path) get_innerjoinpath
  955.  (hashnode))),
  956. get_width(get_parent((Path) get_outerjoinpath
  957.  (hashnode))),
  958. get_width(get_parent((Path) get_innerjoinpath
  959.  (hashnode))));
  960. Assert(cost >= 0);
  961. return cost;
  962. }
  963. else
  964. /* Nested Loop Join */
  965. {
  966. cost += cost_nestloop(get_path_cost((Path) get_outerjoinpath(pathnode)),
  967.    get_path_cost((Path) get_innerjoinpath(pathnode)),
  968.    get_tuples(get_parent((Path) get_outerjoinpath
  969.  (pathnode))),
  970.    get_tuples(get_parent((Path) get_innerjoinpath
  971.  (pathnode))),
  972. get_pages(get_parent((Path) get_outerjoinpath
  973.  (pathnode))),
  974. IsA(get_innerjoinpath(pathnode), IndexPath));
  975. Assert(cost >= 0);
  976. return cost;
  977. }
  978. }
  979. /*
  980.  ** xfunc_expense_per_tuple
  981.  **    return the expense of the join *per-tuple* of the input relation.
  982.  ** The cost model here is that a join costs
  983.  ** k*card(outer)*card(inner) + l*card(outer) + m*card(inner) + n
  984.  **
  985.  ** We treat the l and m terms by considering them to be like restrictions
  986.  ** constrained to be right under the join.  Thus the cost per inner and
  987.  ** cost per outer of the join is different, reflecting these virtual nodes.
  988.  **
  989.  ** The cost per tuple of outer is k + l/referenced(inner).  Cost per tuple
  990.  ** of inner is k + m/referenced(outer).
  991.  ** The constants k, l, m and n depend on the join method. Measures here are
  992.  ** based on the costs in costsize.c, with fudging for HashJoin and Sorts to
  993.  ** make it fit our model (the 'q' in HashJoin results in a
  994.  ** card(outer)/card(inner) term, and sorting results in a log term.
  995.  */
  996. Cost
  997. xfunc_expense_per_tuple(JoinPath joinnode, int whichchild)
  998. {
  999. RelOptInfo outerrel = get_parent((Path) get_outerjoinpath(joinnode));
  1000. RelOptInfo innerrel = get_parent((Path) get_innerjoinpath(joinnode));
  1001. Count outerwidth = get_width(outerrel);
  1002. Count outers_per_page = ceil(BLCKSZ / (outerwidth + MinTupleSize));
  1003. if (IsA(joinnode, HashPath))
  1004. {
  1005. if (whichchild == INNER)
  1006. return (1 + _CPU_PAGE_WEIGHT_) * outers_per_page / NBuffers;
  1007. else
  1008. return (((1 + _CPU_PAGE_WEIGHT_) * outers_per_page / NBuffers)
  1009. + _CPU_PAGE_WEIGHT_
  1010. / xfunc_card_product(get_relids(innerrel)));
  1011. }
  1012. else if (IsA(joinnode, MergePath))
  1013. {
  1014. /* assumes sort exists, and costs one (I/O + CPU) per tuple */
  1015. if (whichchild == INNER)
  1016. return ((2 * _CPU_PAGE_WEIGHT_ + 1)
  1017. / xfunc_card_product(get_relids(outerrel)));
  1018. else
  1019. return ((2 * _CPU_PAGE_WEIGHT_ + 1)
  1020. / xfunc_card_product(get_relids(innerrel)));
  1021. }
  1022. else
  1023. /* nestloop */
  1024. {
  1025. Assert(IsA(joinnode, JoinPath));
  1026. return _CPU_PAGE_WEIGHT_;
  1027. }
  1028. }
  1029. /*
  1030.  ** xfunc_fixvars
  1031.  ** After pulling up a clause, we must walk its expression tree, fixing Var
  1032.  ** nodes to point to the correct varno (either INNER or OUTER, depending
  1033.  ** on which child the clause was pulled from), and the right varattno in the
  1034.  ** target list of the child's former relation.  If the target list of the
  1035.  ** child RelOptInfo does not contain the attribute we need, we add it.
  1036.  */
  1037. void
  1038. xfunc_fixvars(LispValue clause, /* clause being pulled up */
  1039.   RelOptInfo rel, /* rel it's being pulled from */
  1040.   int varno) /* whether rel is INNER or OUTER of join */
  1041. {
  1042. LispValue tmpclause; /* temporary variable */
  1043. TargetEntry *tle; /* tlist member corresponding to var */
  1044. if (IsA(clause, Const) ||IsA(clause, Param))
  1045. return;
  1046. else if (IsA(clause, Var))
  1047. {
  1048. /* here's the meat */
  1049. tle = tlistentry_member((Var) clause, get_targetlist(rel));
  1050. if (tle == LispNil)
  1051. {
  1052. /*
  1053.  * * The attribute we need is not in the target list, * so we
  1054.  * have to add it. *
  1055.  *
  1056.  */
  1057. add_var_to_tlist(rel, (Var) clause);
  1058. tle = tlistentry_member((Var) clause, get_targetlist(rel));
  1059. }
  1060. set_varno(((Var) clause), varno);
  1061. set_varattno(((Var) clause), get_resno(get_resdom(get_entry(tle))));
  1062. }
  1063. else if (IsA(clause, Iter))
  1064. xfunc_fixvars(get_iterexpr((Iter) clause), rel, varno);
  1065. else if (fast_is_clause(clause))
  1066. {
  1067. xfunc_fixvars(lfirst(lnext(clause)), rel, varno);
  1068. xfunc_fixvars(lfirst(lnext(lnext(clause))), rel, varno);
  1069. }
  1070. else if (fast_is_funcclause(clause))
  1071. for (tmpclause = lnext(clause); tmpclause != LispNil;
  1072.  tmpclause = lnext(tmpclause))
  1073. xfunc_fixvars(lfirst(tmpclause), rel, varno);
  1074. else if (fast_not_clause(clause))
  1075. xfunc_fixvars(lsecond(clause), rel, varno);
  1076. else if (fast_or_clause(clause) || fast_and_clause(clause))
  1077. for (tmpclause = lnext(clause); tmpclause != LispNil;
  1078.  tmpclause = lnext(tmpclause))
  1079. xfunc_fixvars(lfirst(tmpclause), rel, varno);
  1080. else
  1081. elog(ERROR, "Clause node of undetermined type");
  1082. }
  1083. /*
  1084.  ** Comparison function for lisp_qsort() on a list of RestrictInfo's.
  1085.  ** arg1 and arg2 should really be of type (RestrictInfo *).
  1086.  */
  1087. int
  1088. xfunc_cinfo_compare(void *arg1, void *arg2)
  1089. {
  1090. RestrictInfo info1 = *(RestrictInfo *) arg1;
  1091. RestrictInfo info2 = *(RestrictInfo *) arg2;
  1092. LispValue clause1 = (LispValue) get_clause(info1),
  1093. clause2 = (LispValue) get_clause(info2);
  1094. return xfunc_clause_compare((void *) &clause1, (void *) &clause2);
  1095. }
  1096. /*
  1097.  ** xfunc_clause_compare: comparison function for lisp_qsort() that compares two
  1098.  ** clauses based on expense/(1 - selectivity)
  1099.  ** arg1 and arg2 are really pointers to clauses.
  1100.  */
  1101. int
  1102. xfunc_clause_compare(void *arg1, void *arg2)
  1103. {
  1104. LispValue clause1 = *(LispValue *) arg1;
  1105. LispValue clause2 = *(LispValue *) arg2;
  1106. Cost rank1, /* total xfunc rank of clause1 */
  1107. rank2; /* total xfunc rank of clause2 */
  1108. rank1 = xfunc_rank(clause1);
  1109. rank2 = xfunc_rank(clause2);
  1110. if (rank1 < rank2)
  1111. return -1;
  1112. else if (rank1 == rank2)
  1113. return 0;
  1114. else
  1115. return 1;
  1116. }
  1117. /*
  1118.  ** xfunc_disjunct_sort
  1119.  **   given a list of clauses, for each clause sort the disjuncts by cost
  1120.  **   (this assumes the predicates have been converted to Conjunctive NF)
  1121.  **   Modifies the clause list!
  1122.  */
  1123. void
  1124. xfunc_disjunct_sort(LispValue clause_list)
  1125. {
  1126. LispValue temp;
  1127. foreach(temp, clause_list)
  1128. if (or_clause(lfirst(temp)))
  1129. lnext(lfirst(temp)) = lisp_qsort(lnext(lfirst(temp)), xfunc_disjunct_compare);
  1130. }
  1131. /*
  1132.  ** xfunc_disjunct_compare: comparison function for qsort() that compares two
  1133.  ** disjuncts based on cost/selec.
  1134.  ** arg1 and arg2 are really pointers to disjuncts
  1135.  */
  1136. int
  1137. xfunc_disjunct_compare(Query *queryInfo, void *arg1, void *arg2)
  1138. {
  1139. LispValue disjunct1 = *(LispValue *) arg1;
  1140. LispValue disjunct2 = *(LispValue *) arg2;
  1141. Cost cost1, /* total cost of disjunct1 */
  1142. cost2, /* total cost of disjunct2 */
  1143. selec1,
  1144. selec2;
  1145. Cost rank1,
  1146. rank2;
  1147. cost1 = xfunc_expense(queryInfo, disjunct1);
  1148. cost2 = xfunc_expense(queryInfo, disjunct2);
  1149. selec1 = compute_clause_selec(queryInfo,
  1150.   disjunct1, LispNil);
  1151. selec2 = compute_clause_selec(queryInfo,
  1152.   disjunct2, LispNil);
  1153. if (selec1 == 0)
  1154. rank1 = MAXFLOAT;
  1155. else if (cost1 == 0)
  1156. rank1 = 0;
  1157. else
  1158. rank1 = cost1 / selec1;
  1159. if (selec2 == 0)
  1160. rank2 = MAXFLOAT;
  1161. else if (cost2 == 0)
  1162. rank2 = 0;
  1163. else
  1164. rank2 = cost2 / selec2;
  1165. if (rank1 < rank2)
  1166. return -1;
  1167. else if (rank1 == rank2)
  1168. return 0;
  1169. else
  1170. return 1;
  1171. }
  1172. /* ------------------------ UTILITY FUNCTIONS ------------------------------- */
  1173. /*
  1174.  ** xfunc_func_width
  1175.  **    Given a function OID and operands, find the width of the return value.
  1176.  */
  1177. int
  1178. xfunc_func_width(RegProcedure funcid, LispValue args)
  1179. {
  1180. Relation rd; /* Relation Descriptor */
  1181. HeapTuple tupl; /* structure to hold a cached tuple */
  1182. Form_pg_proc proc; /* structure to hold the pg_proc tuple */
  1183. Form_pg_type type; /* structure to hold the pg_type tuple */
  1184. LispValue tmpclause;
  1185. int retval;
  1186. /* lookup function and find its return type */
  1187. Assert(RegProcedureIsValid(funcid));
  1188. tupl = SearchSysCacheTuple(PROOID,
  1189.    ObjectIdGetDatum(funcid),
  1190.    0, 0, 0);
  1191. if (!HeapTupleIsValid(tupl))
  1192. elog(ERROR, "Cache lookup failed for procedure %u", funcid);
  1193. proc = (Form_pg_proc) GETSTRUCT(tupl);
  1194. /* if function returns a tuple, get the width of that */
  1195. if (typeidTypeRelids(proc->prorettype))
  1196. {
  1197. rd = heap_open(typeidTypeRelids(proc->prorettype));
  1198. retval = xfunc_tuple_width(rd);
  1199. heap_close(rd);
  1200. goto exit;
  1201. }
  1202. else
  1203. /* function returns a base type */
  1204. {
  1205. tupl = SearchSysCacheTuple(TYPOID,
  1206.    ObjectIdGetDatum(proc->prorettype),
  1207.    0, 0, 0);
  1208. if (!HeapTupleIsValid(tupl))
  1209. elog(ERROR, "Cache lookup failed for type %u", proc->prorettype);
  1210. type = (Form_pg_type) GETSTRUCT(tupl);
  1211. /* if the type length is known, return that */
  1212. if (type->typlen != -1)
  1213. {
  1214. retval = type->typlen;
  1215. goto exit;
  1216. }
  1217. else
  1218. /* estimate the return size */
  1219. {
  1220. /* find width of the function's arguments */
  1221. for (tmpclause = args; tmpclause != LispNil;
  1222.  tmpclause = lnext(tmpclause))
  1223. retval += xfunc_width(lfirst(tmpclause));
  1224. /* multiply by outin_ratio */
  1225. retval = (int) (proc->prooutin_ratio / 100.0 * retval);
  1226. goto exit;
  1227. }
  1228. }
  1229. exit:
  1230. return retval;
  1231. }
  1232. /*
  1233.  ** xfunc_tuple_width
  1234.  ** Return the sum of the lengths of all the attributes of a given relation
  1235.  */
  1236. int
  1237. xfunc_tuple_width(Relation rd)
  1238. {
  1239. int i;
  1240. int retval = 0;
  1241. TupleDesc tdesc = RelationGetDescr(rd);
  1242. for (i = 0; i < tdesc->natts; i++)
  1243. {
  1244. if (tdesc->attrs[i]->attlen != -1)
  1245. retval += tdesc->attrs[i]->attlen;
  1246. else
  1247. retval += VARLEN_DEFAULT;
  1248. }
  1249. return retval;
  1250. }
  1251. /*
  1252.  ** xfunc_num_join_clauses
  1253.  **   Find the number of join clauses associated with this join path
  1254.  */
  1255. int
  1256. xfunc_num_join_clauses(JoinPath path)
  1257. {
  1258. int num = length(get_pathrestrictinfo(path));
  1259. if (IsA(path, MergePath))
  1260. return num + length(get_path_mergeclauses((MergePath) path));
  1261. else if (IsA(path, HashPath))
  1262. return num + length(get_path_hashclauses((HashPath) path));
  1263. else
  1264. return num;
  1265. }
  1266. /*
  1267.  ** xfunc_LispRemove
  1268.  **   Just like LispRemove, but it whines if the item to be removed ain't there
  1269.  */
  1270. LispValue
  1271. xfunc_LispRemove(LispValue foo, List bar)
  1272. {
  1273. LispValue temp = LispNil;
  1274. LispValue result = LispNil;
  1275. int sanity = false;
  1276. for (temp = bar; !null(temp); temp = lnext(temp))
  1277. if (!equal((Node) (foo), (Node) (lfirst(temp))))
  1278. result = lappend(result, lfirst(temp));
  1279. else
  1280. sanity = true; /* found a matching item to remove! */
  1281. if (!sanity)
  1282. elog(ERROR, "xfunc_LispRemove: didn't find a match!");
  1283. return result;
  1284. }
  1285. #define Node_Copy(a, b, c, d) 
  1286. do { 
  1287. if (NodeCopy((Node)((a)->d), (Node*)&((b)->d), c) != true) 
  1288. return false; 
  1289. } while(0)
  1290. /*
  1291.  ** xfunc_copyrel
  1292.  **   Just like _copyRel, but doesn't copy the paths
  1293.  */
  1294. bool
  1295. xfunc_copyrel(RelOptInfo from, RelOptInfo *to)
  1296. {
  1297. RelOptInfo newnode;
  1298. Pointer (*alloc) () = palloc;
  1299. /* COPY_CHECKARGS() */
  1300. if (to == NULL)
  1301. return false;
  1302. /* COPY_CHECKNULL() */
  1303. if (from == NULL)
  1304. {
  1305. (*to) = NULL;
  1306. return true;
  1307. }
  1308. /* COPY_NEW(c) */
  1309. newnode = (RelOptInfo) (*alloc) (classSize(RelOptInfo));
  1310. if (newnode == NULL)
  1311. return false;
  1312. /* ----------------
  1313.  * copy node superclass fields
  1314.  * ----------------
  1315.  */
  1316. CopyNodeFields((Node) from, (Node) newnode, alloc);
  1317. /* ----------------
  1318.  * copy remainder of node
  1319.  * ----------------
  1320.  */
  1321. Node_Copy(from, newnode, alloc, relids);
  1322. newnode->indexed = from->indexed;
  1323. newnode->pages = from->pages;
  1324. newnode->tuples = from->tuples;
  1325. newnode->size = from->size;
  1326. newnode->width = from->width;
  1327. Node_Copy(from, newnode, alloc, targetlist);
  1328. /*
  1329.  * No!!!!  Node_Copy(from, newnode, alloc, pathlist);
  1330.  * Node_Copy(from, newnode, alloc, unorderedpath); Node_Copy(from,
  1331.  * newnode, alloc, cheapestpath);
  1332.  */
  1333. #if 0 /* can't use Node_copy now. 2/95 -ay */
  1334. Node_Copy(from, newnode, alloc, classlist);
  1335. Node_Copy(from, newnode, alloc, indexkeys);
  1336. Node_Copy(from, newnode, alloc, ordering);
  1337. #endif
  1338. Node_Copy(from, newnode, alloc, restrictinfo);
  1339. Node_Copy(from, newnode, alloc, joininfo);
  1340. Node_Copy(from, newnode, alloc, innerjoin);
  1341. (*to) = newnode;
  1342. return true;
  1343. }