Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * prepqual.c
4 : * Routines for preprocessing qualification expressions
5 : *
6 : *
7 : * While the parser will produce flattened (N-argument) AND/OR trees from
8 : * simple sequences of AND'ed or OR'ed clauses, there might be an AND clause
9 : * directly underneath another AND, or OR underneath OR, if the input was
10 : * oddly parenthesized. Also, rule expansion and subquery flattening could
11 : * produce such parsetrees. The planner wants to flatten all such cases
12 : * to ensure consistent optimization behavior.
13 : *
14 : * Formerly, this module was responsible for doing the initial flattening,
15 : * but now we leave it to eval_const_expressions to do that since it has to
16 : * make a complete pass over the expression tree anyway. Instead, we just
17 : * have to ensure that our manipulations preserve AND/OR flatness.
18 : * pull_ands() and pull_ors() are used to maintain flatness of the AND/OR
19 : * tree after local transformations that might introduce nested AND/ORs.
20 : *
21 : *
22 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
23 : * Portions Copyright (c) 1994, Regents of the University of California
24 : *
25 : *
26 : * IDENTIFICATION
27 : * src/backend/optimizer/prep/prepqual.c
28 : *
29 : *-------------------------------------------------------------------------
30 : */
31 :
32 : #include "postgres.h"
33 :
34 : #include "nodes/makefuncs.h"
35 : #include "nodes/nodeFuncs.h"
36 : #include "optimizer/optimizer.h"
37 : #include "optimizer/prep.h"
38 : #include "utils/lsyscache.h"
39 :
40 :
41 : static List *pull_ands(List *andlist);
42 : static List *pull_ors(List *orlist);
43 : static Expr *find_duplicate_ors(Expr *qual, bool is_check);
44 : static Expr *process_duplicate_ors(List *orlist);
45 :
46 :
47 : /*
48 : * negate_clause
49 : * Negate a Boolean expression.
50 : *
51 : * Input is a clause to be negated (e.g., the argument of a NOT clause).
52 : * Returns a new clause equivalent to the negation of the given clause.
53 : *
54 : * Although this can be invoked on its own, it's mainly intended as a helper
55 : * for eval_const_expressions(), and that context drives several design
56 : * decisions. In particular, if the input is already AND/OR flat, we must
57 : * preserve that property. We also don't bother to recurse in situations
58 : * where we can assume that lower-level executions of eval_const_expressions
59 : * would already have simplified sub-clauses of the input.
60 : *
61 : * The difference between this and a simple make_notclause() is that this
62 : * tries to get rid of the NOT node by logical simplification. It's clearly
63 : * always a win if the NOT node can be eliminated altogether. However, our
64 : * use of DeMorgan's laws could result in having more NOT nodes rather than
65 : * fewer. We do that unconditionally anyway, because in WHERE clauses it's
66 : * important to expose as much top-level AND/OR structure as possible.
67 : * Also, eliminating an intermediate NOT may allow us to flatten two levels
68 : * of AND or OR together that we couldn't have otherwise. Finally, one of
69 : * the motivations for doing this is to ensure that logically equivalent
70 : * expressions will be seen as physically equal(), so we should always apply
71 : * the same transformations.
72 : */
73 : Node *
4564 tgl 74 CBC 9913 : negate_clause(Node *node)
75 : {
76 9913 : if (node == NULL) /* should not happen */
4564 tgl 77 UBC 0 : elog(ERROR, "can't negate an empty subexpression");
4564 tgl 78 CBC 9913 : switch (nodeTag(node))
79 : {
80 45 : case T_Const:
81 : {
82 45 : Const *c = (Const *) node;
83 :
84 : /* NOT NULL is still NULL */
85 45 : if (c->constisnull)
4564 tgl 86 UBC 0 : return makeBoolConst(false, true);
87 : /* otherwise pretty easy */
4564 tgl 88 CBC 45 : return makeBoolConst(!DatumGetBool(c->constvalue), false);
89 : }
90 : break;
91 3060 : case T_OpExpr:
92 : {
93 : /*
94 : * Negate operator if possible: (NOT (< A B)) => (>= A B)
95 : */
96 3060 : OpExpr *opexpr = (OpExpr *) node;
97 3060 : Oid negator = get_negator(opexpr->opno);
98 :
99 3060 : if (negator)
100 : {
101 2961 : OpExpr *newopexpr = makeNode(OpExpr);
102 :
103 2961 : newopexpr->opno = negator;
104 2961 : newopexpr->opfuncid = InvalidOid;
105 2961 : newopexpr->opresulttype = opexpr->opresulttype;
106 2961 : newopexpr->opretset = opexpr->opretset;
4398 107 2961 : newopexpr->opcollid = opexpr->opcollid;
108 2961 : newopexpr->inputcollid = opexpr->inputcollid;
4564 109 2961 : newopexpr->args = opexpr->args;
110 2961 : newopexpr->location = opexpr->location;
111 2961 : return (Node *) newopexpr;
112 : }
113 : }
114 99 : break;
115 206 : case T_ScalarArrayOpExpr:
116 : {
117 : /*
118 : * Negate a ScalarArrayOpExpr if its operator has a negator;
119 : * for example x = ANY (list) becomes x <> ALL (list)
120 : */
121 206 : ScalarArrayOpExpr *saopexpr = (ScalarArrayOpExpr *) node;
122 206 : Oid negator = get_negator(saopexpr->opno);
123 :
124 206 : if (negator)
125 : {
126 206 : ScalarArrayOpExpr *newopexpr = makeNode(ScalarArrayOpExpr);
127 :
128 206 : newopexpr->opno = negator;
129 206 : newopexpr->opfuncid = InvalidOid;
731 drowley 130 206 : newopexpr->hashfuncid = InvalidOid;
641 131 206 : newopexpr->negfuncid = InvalidOid;
4564 tgl 132 206 : newopexpr->useOr = !saopexpr->useOr;
4398 133 206 : newopexpr->inputcollid = saopexpr->inputcollid;
4564 134 206 : newopexpr->args = saopexpr->args;
135 206 : newopexpr->location = saopexpr->location;
136 206 : return (Node *) newopexpr;
137 : }
138 : }
4564 tgl 139 UBC 0 : break;
4564 tgl 140 CBC 1878 : case T_BoolExpr:
141 : {
142 1878 : BoolExpr *expr = (BoolExpr *) node;
143 :
144 1878 : switch (expr->boolop)
145 : {
146 : /*--------------------
147 : * Apply DeMorgan's Laws:
148 : * (NOT (AND A B)) => (OR (NOT A) (NOT B))
149 : * (NOT (OR A B)) => (AND (NOT A) (NOT B))
150 : * i.e., swap AND for OR and negate each subclause.
151 : *
152 : * If the input is already AND/OR flat and has no NOT
153 : * directly above AND or OR, this transformation preserves
154 : * those properties. For example, if no direct child of
155 : * the given AND clause is an AND or a NOT-above-OR, then
156 : * the recursive calls of negate_clause() can't return any
157 : * OR clauses. So we needn't call pull_ors() before
158 : * building a new OR clause. Similarly for the OR case.
159 : *--------------------
160 : */
161 1539 : case AND_EXPR:
162 : {
163 1539 : List *nargs = NIL;
164 : ListCell *lc;
165 :
166 5426 : foreach(lc, expr->args)
167 : {
168 3887 : nargs = lappend(nargs,
169 3887 : negate_clause(lfirst(lc)));
170 : }
171 1539 : return (Node *) make_orclause(nargs);
172 : }
173 : break;
174 306 : case OR_EXPR:
175 : {
176 306 : List *nargs = NIL;
177 : ListCell *lc;
178 :
179 1298 : foreach(lc, expr->args)
180 : {
181 992 : nargs = lappend(nargs,
182 992 : negate_clause(lfirst(lc)));
183 : }
184 306 : return (Node *) make_andclause(nargs);
185 : }
186 : break;
187 33 : case NOT_EXPR:
188 :
189 : /*
190 : * NOT underneath NOT: they cancel. We assume the
191 : * input is already simplified, so no need to recurse.
192 : */
193 33 : return (Node *) linitial(expr->args);
4564 tgl 194 UBC 0 : default:
195 0 : elog(ERROR, "unrecognized boolop: %d",
196 : (int) expr->boolop);
197 : break;
198 : }
199 : }
200 : break;
4564 tgl 201 CBC 772 : case T_NullTest:
202 : {
203 772 : NullTest *expr = (NullTest *) node;
204 :
205 : /*
206 : * In the rowtype case, the two flavors of NullTest are *not*
207 : * logical inverses, so we can't simplify. But it does work
208 : * for scalar datatypes.
209 : */
210 772 : if (!expr->argisrow)
211 : {
212 772 : NullTest *newexpr = makeNode(NullTest);
213 :
214 772 : newexpr->arg = expr->arg;
215 772 : newexpr->nulltesttype = (expr->nulltesttype == IS_NULL ?
216 772 : IS_NOT_NULL : IS_NULL);
217 772 : newexpr->argisrow = expr->argisrow;
2968 218 772 : newexpr->location = expr->location;
4564 219 772 : return (Node *) newexpr;
220 : }
221 : }
4564 tgl 222 UBC 0 : break;
223 0 : case T_BooleanTest:
224 : {
4382 bruce 225 0 : BooleanTest *expr = (BooleanTest *) node;
226 0 : BooleanTest *newexpr = makeNode(BooleanTest);
227 :
4564 tgl 228 0 : newexpr->arg = expr->arg;
229 0 : switch (expr->booltesttype)
230 : {
231 0 : case IS_TRUE:
232 0 : newexpr->booltesttype = IS_NOT_TRUE;
233 0 : break;
234 0 : case IS_NOT_TRUE:
235 0 : newexpr->booltesttype = IS_TRUE;
236 0 : break;
237 0 : case IS_FALSE:
238 0 : newexpr->booltesttype = IS_NOT_FALSE;
239 0 : break;
240 0 : case IS_NOT_FALSE:
241 0 : newexpr->booltesttype = IS_FALSE;
242 0 : break;
243 0 : case IS_UNKNOWN:
244 0 : newexpr->booltesttype = IS_NOT_UNKNOWN;
245 0 : break;
246 0 : case IS_NOT_UNKNOWN:
247 0 : newexpr->booltesttype = IS_UNKNOWN;
248 0 : break;
249 0 : default:
250 0 : elog(ERROR, "unrecognized booltesttype: %d",
251 : (int) expr->booltesttype);
252 : break;
253 : }
2968 254 0 : newexpr->location = expr->location;
4564 255 0 : return (Node *) newexpr;
256 : }
257 : break;
4564 tgl 258 CBC 3952 : default:
259 : /* else fall through */
260 3952 : break;
261 : }
262 :
263 : /*
264 : * Otherwise we don't know how to simplify this, so just tack on an
265 : * explicit NOT node.
266 : */
267 4051 : return (Node *) make_notclause((Expr *) node);
268 : }
269 :
270 :
271 : /*
272 : * canonicalize_qual
273 : * Convert a qualification expression to the most useful form.
274 : *
275 : * This is primarily intended to be used on top-level WHERE (or JOIN/ON)
276 : * clauses. It can also be used on top-level CHECK constraints, for which
277 : * pass is_check = true. DO NOT call it on any expression that is not known
278 : * to be one or the other, as it might apply inappropriate simplifications.
279 : *
280 : * The name of this routine is a holdover from a time when it would try to
281 : * force the expression into canonical AND-of-ORs or OR-of-ANDs form.
282 : * Eventually, we recognized that that had more theoretical purity than
283 : * actual usefulness, and so now the transformation doesn't involve any
284 : * notion of reaching a canonical form.
285 : *
286 : * NOTE: we assume the input has already been through eval_const_expressions
287 : * and therefore possesses AND/OR flatness. Formerly this function included
288 : * its own flattening logic, but that requires a useless extra pass over the
289 : * tree.
290 : *
291 : * Returns the modified qualification.
292 : */
293 : Expr *
1855 294 127491 : canonicalize_qual(Expr *qual, bool is_check)
295 : {
296 : Expr *newqual;
297 :
298 : /* Quick exit for empty qual */
8609 299 127491 : if (qual == NULL)
7042 tgl 300 UBC 0 : return NULL;
301 :
302 : /* This should not be invoked on quals in implicit-AND format */
1855 tgl 303 CBC 127491 : Assert(!IsA(qual, List));
304 :
305 : /*
306 : * Pull up redundant subclauses in OR-of-AND trees. We do this only
307 : * within the top-level AND/OR structure; there's no point in looking
308 : * deeper. Also remove any NULL constants in the top-level structure.
309 : */
310 127491 : newqual = find_duplicate_ors(qual, is_check);
311 :
7042 312 127491 : return newqual;
313 : }
314 :
315 :
316 : /*
317 : * pull_ands
318 : * Recursively flatten nested AND clauses into a single and-clause list.
319 : *
320 : * Input is the arglist of an AND clause.
321 : * Returns the rebuilt arglist (note original list structure is not touched).
322 : */
323 : static List *
8610 324 43379 : pull_ands(List *andlist)
325 : {
6886 326 43379 : List *out_list = NIL;
327 : ListCell *arg;
328 :
8610 329 160779 : foreach(arg, andlist)
330 : {
7042 331 117400 : Node *subexpr = (Node *) lfirst(arg);
332 :
1531 333 117400 : if (is_andclause(subexpr))
6886 tgl 334 UBC 0 : out_list = list_concat(out_list,
6385 bruce 335 0 : pull_ands(((BoolExpr *) subexpr)->args));
336 : else
6886 tgl 337 CBC 117400 : out_list = lappend(out_list, subexpr);
338 : }
339 43379 : return out_list;
340 : }
341 :
342 : /*
343 : * pull_ors
344 : * Recursively flatten nested OR clauses into a single or-clause list.
345 : *
346 : * Input is the arglist of an OR clause.
347 : * Returns the rebuilt arglist (note original list structure is not touched).
348 : */
349 : static List *
7256 350 3404 : pull_ors(List *orlist)
351 : {
6886 352 3404 : List *out_list = NIL;
353 : ListCell *arg;
354 :
7256 355 11635 : foreach(arg, orlist)
356 : {
7042 357 8231 : Node *subexpr = (Node *) lfirst(arg);
358 :
1531 359 8231 : if (is_orclause(subexpr))
6886 tgl 360 UBC 0 : out_list = list_concat(out_list,
6385 bruce 361 0 : pull_ors(((BoolExpr *) subexpr)->args));
362 : else
6886 tgl 363 CBC 8231 : out_list = lappend(out_list, subexpr);
364 : }
365 3404 : return out_list;
366 : }
367 :
368 :
369 : /*--------------------
370 : * The following code attempts to apply the inverse OR distributive law:
371 : * ((A AND B) OR (A AND C)) => (A AND (B OR C))
372 : * That is, locate OR clauses in which every subclause contains an
373 : * identical term, and pull out the duplicated terms.
374 : *
375 : * This may seem like a fairly useless activity, but it turns out to be
376 : * applicable to many machine-generated queries, and there are also queries
377 : * in some of the TPC benchmarks that need it. This was in fact almost the
378 : * sole useful side-effect of the old prepqual code that tried to force
379 : * the query into canonical AND-of-ORs form: the canonical equivalent of
380 : * ((A AND B) OR (A AND C))
381 : * is
382 : * ((A OR A) AND (A OR C) AND (B OR A) AND (B OR C))
383 : * which the code was able to simplify to
384 : * (A AND (A OR C) AND (B OR A) AND (B OR C))
385 : * thus successfully extracting the common condition A --- but at the cost
386 : * of cluttering the qual with many redundant clauses.
387 : *--------------------
388 : */
389 :
390 : /*
391 : * find_duplicate_ors
392 : * Given a qualification tree with the NOTs pushed down, search for
393 : * OR clauses to which the inverse OR distributive law might apply.
394 : * Only the top-level AND/OR structure is searched.
395 : *
396 : * While at it, we remove any NULL constants within the top-level AND/OR
397 : * structure, eg in a WHERE clause, "x OR NULL::boolean" is reduced to "x".
398 : * In general that would change the result, so eval_const_expressions can't
399 : * do it; but at top level of WHERE, we don't need to distinguish between
400 : * FALSE and NULL results, so it's valid to treat NULL::boolean the same
401 : * as FALSE and then simplify AND/OR accordingly. Conversely, in a top-level
402 : * CHECK constraint, we may treat a NULL the same as TRUE.
403 : *
404 : * Returns the modified qualification. AND/OR flatness is preserved.
405 : */
406 : static Expr *
1855 407 253131 : find_duplicate_ors(Expr *qual, bool is_check)
408 : {
1531 409 253131 : if (is_orclause(qual))
410 : {
7040 411 3407 : List *orlist = NIL;
412 : ListCell *temp;
413 :
414 : /* Recurse */
7423 415 11644 : foreach(temp, ((BoolExpr *) qual)->args)
416 : {
3267 417 8240 : Expr *arg = (Expr *) lfirst(temp);
418 :
1855 419 8240 : arg = find_duplicate_ors(arg, is_check);
420 :
421 : /* Get rid of any constant inputs */
3267 422 8240 : if (arg && IsA(arg, Const))
423 : {
424 6 : Const *carg = (Const *) arg;
425 :
1855 426 6 : if (is_check)
427 : {
428 : /* Within OR in CHECK, drop constant FALSE */
429 3 : if (!carg->constisnull && !DatumGetBool(carg->constvalue))
1855 tgl 430 UBC 0 : continue;
431 : /* Constant TRUE or NULL, so OR reduces to TRUE */
1855 tgl 432 CBC 3 : return (Expr *) makeBoolConst(true, false);
433 : }
434 : else
435 : {
436 : /* Within OR in WHERE, drop constant FALSE or NULL */
437 3 : if (carg->constisnull || !DatumGetBool(carg->constvalue))
438 3 : continue;
439 : /* Constant TRUE, so OR reduces to TRUE */
1855 tgl 440 UBC 0 : return arg;
441 : }
442 : }
443 :
3267 tgl 444 CBC 8234 : orlist = lappend(orlist, arg);
445 : }
446 :
447 : /* Flatten any ORs pulled up to just below here */
448 3404 : orlist = pull_ors(orlist);
449 :
450 : /* Now we can look for duplicate ORs */
7040 451 3404 : return process_duplicate_ors(orlist);
452 : }
1531 453 249724 : else if (is_andclause(qual))
454 : {
7040 455 43379 : List *andlist = NIL;
456 : ListCell *temp;
457 :
458 : /* Recurse */
7423 459 160779 : foreach(temp, ((BoolExpr *) qual)->args)
460 : {
3267 461 117400 : Expr *arg = (Expr *) lfirst(temp);
462 :
1855 463 117400 : arg = find_duplicate_ors(arg, is_check);
464 :
465 : /* Get rid of any constant inputs */
3267 466 117400 : if (arg && IsA(arg, Const))
467 : {
3267 tgl 468 UBC 0 : Const *carg = (Const *) arg;
469 :
1855 470 0 : if (is_check)
471 : {
472 : /* Within AND in CHECK, drop constant TRUE or NULL */
473 0 : if (carg->constisnull || DatumGetBool(carg->constvalue))
474 0 : continue;
475 : /* Constant FALSE, so AND reduces to FALSE */
476 0 : return arg;
477 : }
478 : else
479 : {
480 : /* Within AND in WHERE, drop constant TRUE */
481 0 : if (!carg->constisnull && DatumGetBool(carg->constvalue))
482 0 : continue;
483 : /* Constant FALSE or NULL, so AND reduces to FALSE */
484 0 : return (Expr *) makeBoolConst(false, false);
485 : }
486 : }
487 :
3267 tgl 488 CBC 117400 : andlist = lappend(andlist, arg);
489 : }
490 :
491 : /* Flatten any ANDs introduced just below here */
7040 492 43379 : andlist = pull_ands(andlist);
493 :
494 : /* AND of no inputs reduces to TRUE */
3267 495 43379 : if (andlist == NIL)
3267 tgl 496 UBC 0 : return (Expr *) makeBoolConst(true, false);
497 :
498 : /* Single-expression AND just reduces to that expression */
3267 tgl 499 CBC 43379 : if (list_length(andlist) == 1)
3267 tgl 500 UBC 0 : return (Expr *) linitial(andlist);
501 :
502 : /* Else we still need an AND node */
7040 tgl 503 CBC 43379 : return make_andclause(andlist);
504 : }
505 : else
8953 bruce 506 206345 : return qual;
507 : }
508 :
509 : /*
510 : * process_duplicate_ors
511 : * Given a list of exprs which are ORed together, try to apply
512 : * the inverse OR distributive law.
513 : *
514 : * Returns the resulting expression (could be an AND clause, an OR
515 : * clause, or maybe even a single subexpression).
516 : */
517 : static Expr *
7040 tgl 518 3404 : process_duplicate_ors(List *orlist)
519 : {
520 3404 : List *reference = NIL;
521 3404 : int num_subclauses = 0;
522 : List *winners;
523 : List *neworlist;
524 : ListCell *temp;
525 :
526 : /* OR of no inputs reduces to FALSE */
8610 527 3404 : if (orlist == NIL)
3267 tgl 528 UBC 0 : return (Expr *) makeBoolConst(false, false);
529 :
530 : /* Single-expression OR just reduces to that expression */
3267 tgl 531 CBC 3404 : if (list_length(orlist) == 1)
532 3 : return (Expr *) linitial(orlist);
533 :
534 : /*
535 : * Choose the shortest AND clause as the reference list --- obviously, any
536 : * subclause not in this clause isn't in all the clauses. If we find a
537 : * clause that's not an AND, we can treat it as a one-element AND clause,
538 : * which necessarily wins as shortest.
539 : */
8610 540 3864 : foreach(temp, orlist)
541 : {
6892 neilc 542 3723 : Expr *clause = (Expr *) lfirst(temp);
543 :
1531 tgl 544 3723 : if (is_andclause(clause))
545 : {
7040 546 463 : List *subclauses = ((BoolExpr *) clause)->args;
6888 neilc 547 463 : int nclauses = list_length(subclauses);
548 :
7040 tgl 549 463 : if (reference == NIL || nclauses < num_subclauses)
550 : {
551 320 : reference = subclauses;
8610 552 320 : num_subclauses = nclauses;
553 : }
554 : }
555 : else
556 : {
6888 neilc 557 3260 : reference = list_make1(clause);
7040 tgl 558 3260 : break;
559 : }
560 : }
561 :
562 : /*
563 : * Just in case, eliminate any duplicates in the reference list.
564 : */
6888 neilc 565 3401 : reference = list_union(NIL, reference);
566 :
567 : /*
568 : * Check each element of the reference list to see if it's in all the OR
569 : * clauses. Build a new list of winning clauses.
570 : */
7040 tgl 571 3401 : winners = NIL;
572 6949 : foreach(temp, reference)
573 : {
6892 neilc 574 3548 : Expr *refclause = (Expr *) lfirst(temp);
7040 tgl 575 3548 : bool win = true;
576 : ListCell *temp2;
577 :
578 6904 : foreach(temp2, orlist)
579 : {
6892 neilc 580 6904 : Expr *clause = (Expr *) lfirst(temp2);
581 :
1531 tgl 582 6904 : if (is_andclause(clause))
583 : {
6888 neilc 584 833 : if (!list_member(((BoolExpr *) clause)->args, refclause))
585 : {
7040 tgl 586 589 : win = false;
587 589 : break;
588 : }
589 : }
590 : else
591 : {
592 6071 : if (!equal(refclause, clause))
593 : {
594 2959 : win = false;
595 2959 : break;
596 : }
597 : }
598 : }
599 :
600 3548 : if (win)
7040 tgl 601 UBC 0 : winners = lappend(winners, refclause);
602 : }
603 :
604 : /*
605 : * If no winners, we can't transform the OR
606 : */
7040 tgl 607 CBC 3401 : if (winners == NIL)
608 3401 : return make_orclause(orlist);
609 :
610 : /*
611 : * Generate new OR list consisting of the remaining sub-clauses.
612 : *
613 : * If any clause degenerates to empty, then we have a situation like (A
614 : * AND B) OR (A), which can be reduced to just A --- that is, the
615 : * additional conditions in other arms of the OR are irrelevant.
616 : *
617 : * Note that because we use list_difference, any multiple occurrences of a
618 : * winning clause in an AND sub-clause will be removed automatically.
619 : */
7040 tgl 620 UBC 0 : neworlist = NIL;
621 0 : foreach(temp, orlist)
622 : {
6892 neilc 623 0 : Expr *clause = (Expr *) lfirst(temp);
624 :
1531 tgl 625 0 : if (is_andclause(clause))
626 : {
7040 627 0 : List *subclauses = ((BoolExpr *) clause)->args;
628 :
6888 neilc 629 0 : subclauses = list_difference(subclauses, winners);
7040 tgl 630 0 : if (subclauses != NIL)
631 : {
6888 neilc 632 0 : if (list_length(subclauses) == 1)
6892 633 0 : neworlist = lappend(neworlist, linitial(subclauses));
634 : else
7040 tgl 635 0 : neworlist = lappend(neworlist, make_andclause(subclauses));
636 : }
637 : else
638 : {
6797 bruce 639 0 : neworlist = NIL; /* degenerate case, see above */
7040 tgl 640 0 : break;
641 : }
642 : }
643 : else
644 : {
6888 neilc 645 0 : if (!list_member(winners, clause))
7040 tgl 646 0 : neworlist = lappend(neworlist, clause);
647 : else
648 : {
6797 bruce 649 0 : neworlist = NIL; /* degenerate case, see above */
7040 tgl 650 0 : break;
651 : }
652 : }
653 : }
654 :
655 : /*
656 : * Append reduced OR to the winners list, if it's not degenerate, handling
657 : * the special case of one element correctly (can that really happen?).
658 : * Also be careful to maintain AND/OR flatness in case we pulled up a
659 : * sub-sub-OR-clause.
660 : */
661 0 : if (neworlist != NIL)
662 : {
6888 neilc 663 0 : if (list_length(neworlist) == 1)
6892 664 0 : winners = lappend(winners, linitial(neworlist));
665 : else
7040 tgl 666 0 : winners = lappend(winners, make_orclause(pull_ors(neworlist)));
667 : }
668 :
669 : /*
670 : * And return the constructed AND clause, again being wary of a single
671 : * element and AND/OR flatness.
672 : */
6888 neilc 673 0 : if (list_length(winners) == 1)
6892 674 0 : return (Expr *) linitial(winners);
675 : else
7040 tgl 676 0 : return make_andclause(pull_ands(winners));
677 : }
|