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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * prepqual.c
  4.  *   Routines for preprocessing the parse tree qualification
  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/prepqual.c,v 1.15.2.1 1999/08/02 06:27:04 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include <sys/types.h>
  15. #include "postgres.h"
  16. #include "nodes/makefuncs.h"
  17. #include "optimizer/clauses.h"
  18. #include "optimizer/prep.h"
  19. #include "utils/lsyscache.h"
  20. static Expr *pull_args(Expr *qual);
  21. static List *pull_ors(List *orlist);
  22. static List *pull_ands(List *andlist);
  23. static Expr *find_nots(Expr *qual);
  24. static Expr *push_nots(Expr *qual);
  25. static Expr *normalize(Expr *qual);
  26. static List *or_normalize(List *orlist);
  27. static List *distribute_args(List *item, List *args);
  28. static List *qual_cleanup(Expr *qual);
  29. static List *remove_ands(Expr *qual);
  30. static List *remove_duplicates(List *list);
  31. /*****************************************************************************
  32.  *
  33.  * CNF CONVERSION ROUTINES
  34.  *
  35.  * NOTES:
  36.  * The basic algorithms for normalizing the qualification are taken
  37.  * from ingres/source/qrymod/norml.c
  38.  *
  39.  * Remember that the initial qualification may consist of ARBITRARY
  40.  * combinations of clauses.  In addition, before this routine is called,
  41.  * the qualification will contain explicit "AND"s.
  42.  *
  43.  *****************************************************************************/
  44. /*
  45.  * cnfify
  46.  *   Convert a qualification to conjunctive normal form by applying
  47.  *   successive normalizations.
  48.  *
  49.  * Returns the modified qualification with an extra level of nesting.
  50.  *
  51.  * If 'removeAndFlag' is true then it removes the explicit ANDs.
  52.  *
  53.  * NOTE: this routine is called by the planner (removeAndFlag = true)
  54.  * and from the rule manager (removeAndFlag = false).
  55.  *
  56.  */
  57. List *
  58. cnfify(Expr *qual, bool removeAndFlag)
  59. {
  60. Expr    *newqual = NULL;
  61. if (qual != NULL)
  62. {
  63. newqual = find_nots(pull_args(qual));
  64. newqual = normalize(pull_args(newqual));
  65. newqual = (Expr *) qual_cleanup(pull_args(newqual));
  66. newqual = pull_args(newqual);;
  67. if (removeAndFlag)
  68. {
  69. if (and_clause((Node *) newqual))
  70. newqual = (Expr *) remove_ands(newqual);
  71. else
  72. newqual = (Expr *) remove_ands(make_andclause(lcons(newqual, NIL)));
  73. }
  74. }
  75. return (List *) (newqual);
  76. }
  77. /*
  78.  * find_nots
  79.  *   Traverse the qualification, looking for 'not's to take care of.
  80.  *   For 'not' clauses, remove the 'not' and push it down to the clauses'
  81.  *   descendants.
  82.  *   For all other clause types, simply recurse.
  83.  *
  84.  * Returns the modified qualification.
  85.  *
  86.  */
  87. static Expr *
  88. find_nots(Expr *qual)
  89. {
  90. if (qual == NULL)
  91. return NULL;
  92. if (is_opclause((Node *) qual))
  93. {
  94. Expr    *left = (Expr *) get_leftop(qual);
  95. Expr    *right = (Expr *) get_rightop(qual);
  96. if (right)
  97. return make_clause(qual->opType, qual->oper,
  98.    lcons(find_nots(left),
  99.  lcons(find_nots(right),
  100.    NIL)));
  101. else
  102. return make_clause(qual->opType, qual->oper,
  103.    lcons(find_nots(left),
  104.  NIL));
  105. }
  106. else if (and_clause((Node *) qual))
  107. {
  108. List    *temp = NIL;
  109. List    *t_list = NIL;
  110. foreach(temp, qual->args)
  111. t_list = lappend(t_list, find_nots(lfirst(temp)));
  112. return make_andclause(t_list);
  113. }
  114. else if (or_clause((Node *) qual))
  115. {
  116. List    *temp = NIL;
  117. List    *t_list = NIL;
  118. foreach(temp, qual->args)
  119. t_list = lappend(t_list, find_nots(lfirst(temp)));
  120. return make_orclause(t_list);
  121. }
  122. else if (not_clause((Node *) qual))
  123. return push_nots(get_notclausearg(qual));
  124. else
  125. return qual;
  126. }
  127. /*
  128.  * normalize
  129.  *   Given a qualification tree with the 'not's pushed down, convert it
  130.  *   to a tree in CNF by repeatedly applying the rule:
  131.  * ("OR" A ("AND" B C))  => ("AND" ("OR" A B) ("OR" A C))
  132.  *   bottom-up.
  133.  *   Note that 'or' clauses will always be turned into 'and' clauses.
  134.  *
  135.  * Returns the modified qualification.
  136.  *
  137.  */
  138. static Expr *
  139. normalize(Expr *qual)
  140. {
  141. if (qual == NULL)
  142. return NULL;
  143. if (is_opclause((Node *) qual))
  144. {
  145. Expr    *left = (Expr *) get_leftop(qual);
  146. Expr    *right = (Expr *) get_rightop(qual);
  147. if (right)
  148. return make_clause(qual->opType, qual->oper,
  149.    lcons(normalize(left),
  150.  lcons(normalize(right),
  151.    NIL)));
  152. else
  153. return make_clause(qual->opType, qual->oper,
  154.    lcons(normalize(left),
  155.  NIL));
  156. }
  157. else if (and_clause((Node *) qual))
  158. {
  159. List    *temp = NIL;
  160. List    *t_list = NIL;
  161. foreach(temp, qual->args)
  162. t_list = lappend(t_list, normalize(lfirst(temp)));
  163. return make_andclause(t_list);
  164. }
  165. else if (or_clause((Node *) qual))
  166. {
  167. /* XXX - let form, maybe incorrect */
  168. List    *orlist = NIL;
  169. List    *temp = NIL;
  170. bool has_andclause = FALSE;
  171. foreach(temp, qual->args)
  172. orlist = lappend(orlist, normalize(lfirst(temp)));
  173. foreach(temp, orlist)
  174. {
  175. if (and_clause(lfirst(temp)))
  176. {
  177. has_andclause = TRUE;
  178. break;
  179. }
  180. }
  181. if (has_andclause == TRUE)
  182. return make_andclause(or_normalize(orlist));
  183. else
  184. return make_orclause(orlist);
  185. }
  186. else if (not_clause((Node *) qual))
  187. return make_notclause(normalize(get_notclausearg(qual)));
  188. else
  189. return qual;
  190. }
  191. /*
  192.  * qual_cleanup
  193.  *   Fix up a qualification by removing duplicate entries (left over from
  194.  *   normalization), and by removing 'and' and 'or' clauses which have only
  195.  *   one valid expr (e.g., ("AND" A) => A).
  196.  *
  197.  * Returns the modified qualfication.
  198.  *
  199.  */
  200. static List *
  201. qual_cleanup(Expr *qual)
  202. {
  203. if (qual == NULL)
  204. return NIL;
  205. if (is_opclause((Node *) qual))
  206. {
  207. Expr    *left = (Expr *) get_leftop(qual);
  208. Expr    *right = (Expr *) get_rightop(qual);
  209. if (right)
  210. return (List *) make_clause(qual->opType, qual->oper,
  211. lcons(qual_cleanup(left),
  212.   lcons(qual_cleanup(right),
  213. NIL)));
  214. else
  215. return (List *) make_clause(qual->opType, qual->oper,
  216. lcons(qual_cleanup(left),
  217.   NIL));
  218. }
  219. else if (and_clause((Node *) qual))
  220. {
  221. List    *temp = NIL;
  222. List    *t_list = NIL;
  223. List    *new_and_args = NIL;
  224. foreach(temp, qual->args)
  225. t_list = lappend(t_list, qual_cleanup(lfirst(temp)));
  226. new_and_args = remove_duplicates(t_list);
  227. if (length(new_and_args) > 1)
  228. return (List *) make_andclause(new_and_args);
  229. else
  230. return lfirst(new_and_args);
  231. }
  232. else if (or_clause((Node *) qual))
  233. {
  234. List    *temp = NIL;
  235. List    *t_list = NIL;
  236. List    *new_or_args = NIL;
  237. foreach(temp, qual->args)
  238. t_list = lappend(t_list, qual_cleanup(lfirst(temp)));
  239. new_or_args = remove_duplicates(t_list);
  240. if (length(new_or_args) > 1)
  241. return (List *) make_orclause(new_or_args);
  242. else
  243. return lfirst(new_or_args);
  244. }
  245. else if (not_clause((Node *) qual))
  246. return (List *) make_notclause((Expr *) qual_cleanup((Expr *) get_notclausearg(qual)));
  247. else
  248. return (List *) qual;
  249. }
  250. /*
  251.  * pull_args
  252.  *   Given a qualification, eliminate nested 'and' and 'or' clauses.
  253.  *
  254.  * Returns the modified qualification.
  255.  *
  256.  */
  257. static Expr *
  258. pull_args(Expr *qual)
  259. {
  260. if (qual == NULL)
  261. return NULL;
  262. if (is_opclause((Node *) qual))
  263. {
  264. Expr    *left = (Expr *) get_leftop(qual);
  265. Expr    *right = (Expr *) get_rightop(qual);
  266. if (right)
  267. return make_clause(qual->opType, qual->oper,
  268.    lcons(pull_args(left),
  269.  lcons(pull_args(right),
  270.    NIL)));
  271. else
  272. return make_clause(qual->opType, qual->oper,
  273.    lcons(pull_args(left),
  274.  NIL));
  275. }
  276. else if (and_clause((Node *) qual))
  277. {
  278. List    *temp = NIL;
  279. List    *t_list = NIL;
  280. foreach(temp, qual->args)
  281. t_list = lappend(t_list, pull_args(lfirst(temp)));
  282. return make_andclause(pull_ands(t_list));
  283. }
  284. else if (or_clause((Node *) qual))
  285. {
  286. List    *temp = NIL;
  287. List    *t_list = NIL;
  288. foreach(temp, qual->args)
  289. t_list = lappend(t_list, pull_args(lfirst(temp)));
  290. return make_orclause(pull_ors(t_list));
  291. }
  292. else if (not_clause((Node *) qual))
  293. return make_notclause(pull_args(get_notclausearg(qual)));
  294. else
  295. return qual;
  296. }
  297. /*
  298.  * pull_ors
  299.  *   Pull the arguments of an 'or' clause nested within another 'or'
  300.  *   clause up into the argument list of the parent.
  301.  *
  302.  * Returns the modified list.
  303.  */
  304. static List *
  305. pull_ors(List *orlist)
  306. {
  307. if (orlist == NIL)
  308. return NIL;
  309. if (or_clause(lfirst(orlist)))
  310. {
  311. List    *args = ((Expr *) lfirst(orlist))->args;
  312. return (pull_ors(nconc(copyObject((Node *) args),
  313.    copyObject((Node *) lnext(orlist)))));
  314. }
  315. else
  316. return lcons(lfirst(orlist), pull_ors(lnext(orlist)));
  317. }
  318. /*
  319.  * pull_ands
  320.  *   Pull the arguments of an 'and' clause nested within another 'and'
  321.  *   clause up into the argument list of the parent.
  322.  *
  323.  * Returns the modified list.
  324.  */
  325. static List *
  326. pull_ands(List *andlist)
  327. {
  328. if (andlist == NIL)
  329. return NIL;
  330. if (and_clause(lfirst(andlist)))
  331. {
  332. List    *args = ((Expr *) lfirst(andlist))->args;
  333. return (pull_ands(nconc(copyObject((Node *) args),
  334. copyObject((Node *) lnext(andlist)))));
  335. }
  336. else
  337. return lcons(lfirst(andlist), pull_ands(lnext(andlist)));
  338. }
  339. /*
  340.  * push_nots
  341.  *   Negate the descendants of a 'not' clause.
  342.  *
  343.  * Returns the modified qualification.
  344.  *
  345.  */
  346. static Expr *
  347. push_nots(Expr *qual)
  348. {
  349. if (qual == NULL)
  350. return NULL;
  351. /*
  352.  * Negate an operator clause if possible: ("NOT" (< A B)) => (> A B)
  353.  * Otherwise, retain the clause as it is (the 'not' can't be pushed
  354.  * down any farther).
  355.  */
  356. if (is_opclause((Node *) qual))
  357. {
  358. Oper    *oper = (Oper *) ((Expr *) qual)->oper;
  359. Oid negator = get_negator(oper->opno);
  360. if (negator)
  361. {
  362. Oper    *op = (Oper *) makeOper(negator,
  363.    InvalidOid,
  364.    oper->opresulttype,
  365.    0, NULL);
  366. op->op_fcache = (FunctionCache *) NULL;
  367. return make_opclause(op, get_leftop(qual), get_rightop(qual));
  368. }
  369. else
  370. return make_notclause(qual);
  371. }
  372. else if (and_clause((Node *) qual))
  373. {
  374. /*
  375.  * Apply DeMorgan's Laws: ("NOT" ("AND" A B)) => ("OR" ("NOT" A)
  376.  * ("NOT" B)) ("NOT" ("OR" A B)) => ("AND" ("NOT" A) ("NOT" B))
  377.  * i.e., continue negating down through the clause's descendants.
  378.  */
  379. List    *temp = NIL;
  380. List    *t_list = NIL;
  381. foreach(temp, qual->args)
  382. t_list = lappend(t_list, push_nots(lfirst(temp)));
  383. return make_orclause(t_list);
  384. }
  385. else if (or_clause((Node *) qual))
  386. {
  387. List    *temp = NIL;
  388. List    *t_list = NIL;
  389. foreach(temp, qual->args)
  390. t_list = lappend(t_list, push_nots(lfirst(temp)));
  391. return make_andclause(t_list);
  392. }
  393. else if (not_clause((Node *) qual))
  394. /*
  395.  * Another 'not' cancels this 'not', so eliminate the 'not' and
  396.  * stop negating this branch.
  397.  */
  398. return find_nots(get_notclausearg(qual));
  399. else
  400. /*
  401.  * We don't know how to negate anything else, place a 'not' at
  402.  * this level.
  403.  */
  404. return make_notclause(qual);
  405. }
  406. /*
  407.  * or_normalize
  408.  *   Given a list of exprs which are 'or'ed together, distribute any
  409.  *   'and' clauses.
  410.  *
  411.  * Returns the modified list.
  412.  *
  413.  */
  414. static List *
  415. or_normalize(List *orlist)
  416. {
  417. List    *distributable = NIL;
  418. List    *new_orlist = NIL;
  419. List    *temp = NIL;
  420. if (orlist == NIL)
  421. return NIL;
  422. foreach(temp, orlist)
  423. {
  424. if (and_clause(lfirst(temp)))
  425. distributable = lfirst(temp);
  426. }
  427. if (distributable)
  428. new_orlist = LispRemove(distributable, orlist);
  429. if (new_orlist)
  430. {
  431. return (or_normalize(lcons(distribute_args(lfirst(new_orlist),
  432.  ((Expr *) distributable)->args),
  433.    lnext(new_orlist))));
  434. }
  435. else
  436. return orlist;
  437. }
  438. /*
  439.  * distribute_args
  440.  *   Create new 'or' clauses by or'ing 'item' with each element of 'args'.
  441.  *   E.g.: (distribute-args A ("AND" B C)) => ("AND" ("OR" A B) ("OR" A C))
  442.  *
  443.  * Returns an 'and' clause.
  444.  *
  445.  */
  446. static List *
  447. distribute_args(List *item, List *args)
  448. {
  449. List    *or_list = NIL;
  450. List    *n_list = NIL;
  451. List    *temp = NIL;
  452. List    *t_list = NIL;
  453. if (args == NULL)
  454. return item;
  455. foreach(temp, args)
  456. {
  457. n_list = or_normalize(pull_ors(lcons(item,
  458.  lcons(lfirst(temp), NIL))));
  459. or_list = (List *) make_orclause(n_list);
  460. t_list = lappend(t_list, or_list);
  461. }
  462. return (List *) make_andclause(t_list);
  463. }
  464. /*
  465.  * remove_ands
  466.  *   Remove the explicit "AND"s from the qualification:
  467.  * ("AND" A B) => (A B)
  468.  *
  469.  * RETURNS : qual
  470.  * MODIFIES: qual
  471.  */
  472. static List *
  473. remove_ands(Expr *qual)
  474. {
  475. List    *t_list = NIL;
  476. if (qual == NULL)
  477. return NIL;
  478. if (is_opclause((Node *) qual))
  479. {
  480. Expr    *left = (Expr *) get_leftop(qual);
  481. Expr    *right = (Expr *) get_rightop(qual);
  482. if (right)
  483. return (List *) make_clause(qual->opType, qual->oper,
  484. lcons(remove_ands(left),
  485.   lcons(remove_ands(right),
  486. NIL)));
  487. else
  488. return (List *) make_clause(qual->opType, qual->oper,
  489. lcons(remove_ands(left),
  490.   NIL));
  491. }
  492. else if (and_clause((Node *) qual))
  493. {
  494. List    *temp = NIL;
  495. foreach(temp, qual->args)
  496. t_list = lappend(t_list, remove_ands(lfirst(temp)));
  497. return t_list;
  498. }
  499. else if (or_clause((Node *) qual))
  500. {
  501. List    *temp = NIL;
  502. foreach(temp, qual->args)
  503. t_list = lappend(t_list, remove_ands(lfirst(temp)));
  504. return (List *) make_orclause((List *) t_list);
  505. }
  506. else if (not_clause((Node *) qual))
  507. return (List *) make_notclause((Expr *) remove_ands((Expr *) get_notclausearg(qual)));
  508. else
  509. return (List *) qual;
  510. }
  511. /*
  512.  * remove_duplicates
  513.  */
  514. static List *
  515. remove_duplicates(List *list)
  516. {
  517. List    *i;
  518. List    *j;
  519. List    *result = NIL;
  520. bool there_exists_duplicate = false;
  521. if (length(list) == 1)
  522. return list;
  523. foreach(i, list)
  524. {
  525. if (i != NIL)
  526. {
  527. foreach(j, lnext(i))
  528. {
  529. if (equal(lfirst(i), lfirst(j)))
  530. there_exists_duplicate = true;
  531. }
  532. if (!there_exists_duplicate)
  533. result = lappend(result, lfirst(i));
  534. there_exists_duplicate = false;
  535. }
  536. }
  537. return result;
  538. }