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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * preptlist.c
  4.  *   Routines to preprocess the parse tree target list
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.22.2.1 1999/08/02 06:27:05 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include "postgres.h"
  15. #include "catalog/pg_type.h"
  16. #include "nodes/makefuncs.h"
  17. #include "optimizer/clauses.h"
  18. #include "optimizer/prep.h"
  19. #include "parser/parsetree.h"
  20. #include "utils/lsyscache.h"
  21. #include "utils/syscache.h"
  22. static List *expand_targetlist(List *tlist, Oid relid, int command_type,
  23.   Index result_relation);
  24. static List *replace_matching_resname(List *new_tlist,
  25.  List *old_tlist);
  26. static List *new_relation_targetlist(Oid relid, Index rt_index,
  27. NodeTag node_type);
  28. /*
  29.  * preprocess_targetlist
  30.  *   Driver for preprocessing the parse tree targetlist.
  31.  *
  32.  *   1. Deal with appends and replaces by filling missing attributes
  33.  *  in the target list.
  34.  *   2. Reset operator OIDs to the appropriate regproc ids.
  35.  *
  36.  *   Returns the new targetlist.
  37.  */
  38. List *
  39. preprocess_targetlist(List *tlist,
  40.   int command_type,
  41.   Index result_relation,
  42.   List *range_table)
  43. {
  44. List    *expanded_tlist = NIL;
  45. Oid relid = InvalidOid;
  46. List    *t_list = NIL;
  47. List    *temp = NIL;
  48. if (result_relation >= 1 && command_type != CMD_SELECT)
  49. relid = getrelid(result_relation, range_table);
  50. /*
  51.  * for heap_formtuple to work, the targetlist must match the exact
  52.  * order of the attributes. We also need to fill in the missing
  53.  * attributes here. -ay 10/94
  54.  */
  55. expanded_tlist = expand_targetlist(tlist, relid, command_type, result_relation);
  56. /* XXX should the fix-opids be this early?? */
  57. /* was mapCAR  */
  58. foreach(temp, expanded_tlist)
  59. {
  60. TargetEntry *tle = lfirst(temp);
  61. if (tle->expr)
  62. fix_opid(tle->expr);
  63. }
  64. t_list = copyObject(expanded_tlist);
  65. /* ------------------
  66.  * for "replace" or "delete" queries, add ctid of the result
  67.  * relation into the target list so that the ctid can get
  68.  * propogate through the execution and in the end ExecReplace()
  69.  * will find the right tuple to replace or delete.  This
  70.  * extra field will be removed in ExecReplace().
  71.  * For convinient, we append this extra field to the end of
  72.  * the target list.
  73.  * ------------------
  74.  */
  75. if (command_type == CMD_UPDATE || command_type == CMD_DELETE)
  76. {
  77. TargetEntry *ctid;
  78. Resdom    *resdom;
  79. Var    *var;
  80. resdom = makeResdom(length(t_list) + 1,
  81. TIDOID,
  82. -1,
  83. "ctid",
  84. 0,
  85. 0,
  86. true);
  87. var = makeVar(result_relation, -1, TIDOID, -1, 0, result_relation, -1);
  88. ctid = makeTargetEntry(resdom, (Node *) var);
  89. t_list = lappend(t_list, ctid);
  90. }
  91. return t_list;
  92. }
  93. /*****************************************************************************
  94.  *
  95.  * TARGETLIST EXPANSION
  96.  *
  97.  *****************************************************************************/
  98. /*
  99.  * expand_targetlist
  100.  *   Given a target list as generated by the parser and a result relation,
  101.  *   add targetlist entries for the attributes which have not been used.
  102.  *
  103.  *   XXX This code is only supposed to work with unnested relations.
  104.  *
  105.  *   'tlist' is the original target list
  106.  *   'relid' is the relid of the result relation
  107.  *   'command' is the update command
  108.  *
  109.  * Returns the expanded target list, sorted in resno order.
  110.  */
  111. static List *
  112. expand_targetlist(List *tlist,
  113.   Oid relid,
  114.   int command_type,
  115.   Index result_relation)
  116. {
  117. NodeTag node_type = T_Invalid;
  118. switch (command_type)
  119. {
  120. case CMD_INSERT:
  121. node_type = (NodeTag) T_Const;
  122. break;
  123. case CMD_UPDATE:
  124. node_type = (NodeTag) T_Var;
  125. break;
  126. }
  127. if (node_type != T_Invalid)
  128. {
  129. List    *ntlist = new_relation_targetlist(relid,
  130.  result_relation,
  131.  node_type);
  132. return replace_matching_resname(ntlist, tlist);
  133. }
  134. else
  135. return tlist;
  136. }
  137. static List *
  138. replace_matching_resname(List *new_tlist, List *old_tlist)
  139. {
  140. List    *temp,
  141.    *i;
  142. List    *t_list = NIL;
  143. foreach(i, new_tlist)
  144. {
  145. TargetEntry *new_tle = (TargetEntry *) lfirst(i);
  146. TargetEntry *matching_old_tl = NULL;
  147. foreach(temp, old_tlist)
  148. {
  149. TargetEntry *old_tle = (TargetEntry *) lfirst(temp);
  150. old_tle = lfirst(temp);
  151. if (!strcmp(old_tle->resdom->resname,
  152. new_tle->resdom->resname))
  153. {
  154. matching_old_tl = old_tle;
  155. break;
  156. }
  157. }
  158. if (matching_old_tl)
  159. {
  160. matching_old_tl->resdom->resno = new_tle->resdom->resno;
  161. t_list = lappend(t_list, matching_old_tl);
  162. }
  163. else
  164. t_list = lappend(t_list, new_tle);
  165. }
  166. /*
  167.  * It is possible that 'old_tlist' has some negative attributes (i.e.
  168.  * negative resnos). This only happens if this is a replace/append
  169.  * command and we explicitly specify a system attribute. Of course
  170.  * this is not a very good idea if this is a user query, but on the
  171.  * other hand the rule manager uses this mechanism to replace rule
  172.  * locks.
  173.  *
  174.  * So, copy all these entries to the end of the target list and set their
  175.  * 'resjunk' value to true to show that these are special attributes
  176.  * and have to be treated specially by the executor!
  177.  */
  178. foreach(temp, old_tlist)
  179. {
  180. TargetEntry *old_tle,
  181.    *new_tl;
  182. Resdom    *newresno;
  183. old_tle = lfirst(temp);
  184. if (old_tle->resdom->resno < 0)
  185. {
  186. newresno = (Resdom *) copyObject((Node *) old_tle->resdom);
  187. newresno->resno = length(t_list) + 1;
  188. newresno->resjunk = true;
  189. new_tl = makeTargetEntry(newresno, old_tle->expr);
  190. t_list = lappend(t_list, new_tl);
  191. }
  192. /*
  193.  * Also it is possible that the parser or rewriter added some junk
  194.  * attributes to hold GROUP BY expressions which are not part of
  195.  * the result attributes. We can simply identify them by looking
  196.  * at the resgroupref in the TLE's resdom, which is a unique
  197.  * number telling which TLE belongs to which GroupClause.
  198.  */
  199. if (old_tle->resdom->resgroupref > 0)
  200. {
  201. bool already_there = FALSE;
  202. TargetEntry *new_tle;
  203. Resdom    *newresno;
  204. /*
  205.  * Check if the tle is already in the new list
  206.  */
  207. foreach(i, t_list)
  208. {
  209. new_tle = (TargetEntry *) lfirst(i);
  210. if (new_tle->resdom->resgroupref ==
  211. old_tle->resdom->resgroupref)
  212. {
  213. already_there = TRUE;
  214. break;
  215. }
  216. }
  217. /*
  218.  * If not, add it and make sure it is now a junk attribute
  219.  */
  220. if (!already_there)
  221. {
  222. newresno = (Resdom *) copyObject((Node *) old_tle->resdom);
  223. newresno->resno = length(t_list) + 1;
  224. newresno->resjunk = true;
  225. new_tl = makeTargetEntry(newresno, old_tle->expr);
  226. t_list = lappend(t_list, new_tl);
  227. }
  228. }
  229. }
  230. return t_list;
  231. }
  232. /*
  233.  * new_relation_targetlist
  234.  *   Generate a targetlist for the relation with relation OID 'relid'
  235.  *   and rangetable index 'rt_index'.
  236.  *
  237.  *   Returns the new targetlist.
  238.  */
  239. static List *
  240. new_relation_targetlist(Oid relid, Index rt_index, NodeTag node_type)
  241. {
  242. List    *t_list = NIL;
  243. int natts = get_relnatts(relid);
  244. AttrNumber attno;
  245. for (attno = 1; attno <= natts; attno++)
  246. {
  247. HeapTuple tp;
  248. Form_pg_attribute att_tup;
  249. char    *attname;
  250. Oid atttype;
  251. int32 atttypmod;
  252. bool attisset;
  253. tp = SearchSysCacheTuple(ATTNUM,
  254.  ObjectIdGetDatum(relid),
  255.  UInt16GetDatum(attno),
  256.  0, 0);
  257. if (! HeapTupleIsValid(tp))
  258. {
  259. elog(ERROR, "new_relation_targetlist: no attribute tuple %u %d",
  260.  relid, attno);
  261. }
  262. att_tup = (Form_pg_attribute) GETSTRUCT(tp);
  263. attname = pstrdup(att_tup->attname.data);
  264. atttype = att_tup->atttypid;
  265. atttypmod = att_tup->atttypmod;
  266. attisset = att_tup->attisset;
  267. switch (node_type)
  268. {
  269. case T_Const: /* INSERT command */
  270. {
  271. struct varlena *typedefault = get_typdefault(atttype);
  272. int typlen;
  273. Const    *temp_const;
  274. TargetEntry *temp_tle;
  275. if (typedefault == NULL)
  276. typlen = 0;
  277. else
  278. {
  279. /*
  280.  * Since this is an append or replace, the size of
  281.  * any set attribute is the size of the OID used to
  282.  * represent it.
  283.  */
  284. if (attisset)
  285. typlen = get_typlen(OIDOID);
  286. else
  287. typlen = get_typlen(atttype);
  288. }
  289. temp_const = makeConst(atttype,
  290.    typlen,
  291.    (Datum) typedefault,
  292.    (typedefault == NULL),
  293.    /* XXX ? */
  294.    false,
  295.    false, /* not a set */
  296.    false);
  297. temp_tle = makeTargetEntry(makeResdom(attno,
  298.   atttype,
  299.   -1,
  300.   attname,
  301.   0,
  302.   (Oid) 0,
  303.   false),
  304.    (Node *) temp_const);
  305. t_list = lappend(t_list, temp_tle);
  306. break;
  307. }
  308. case T_Var: /* UPDATE command */
  309. {
  310. Var    *temp_var;
  311. TargetEntry *temp_tle;
  312. temp_var = makeVar(rt_index, attno, atttype, atttypmod,
  313.    0, rt_index, attno);
  314. temp_tle = makeTargetEntry(makeResdom(attno,
  315.   atttype,
  316.   atttypmod,
  317.   attname,
  318.   0,
  319.   (Oid) 0,
  320.   false),
  321.    (Node *) temp_var);
  322. t_list = lappend(t_list, temp_tle);
  323. break;
  324. }
  325. default: /* do nothing */
  326. break;
  327. }
  328. }
  329. return t_list;
  330. }