Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "postgres.h"
00034
00035 #include "nodes/makefuncs.h"
00036 #include "optimizer/clauses.h"
00037 #include "optimizer/prep.h"
00038 #include "utils/lsyscache.h"
00039
00040
00041 static List *pull_ands(List *andlist);
00042 static List *pull_ors(List *orlist);
00043 static Expr *find_duplicate_ors(Expr *qual);
00044 static Expr *process_duplicate_ors(List *orlist);
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073 Node *
00074 negate_clause(Node *node)
00075 {
00076 if (node == NULL)
00077 elog(ERROR, "can't negate an empty subexpression");
00078 switch (nodeTag(node))
00079 {
00080 case T_Const:
00081 {
00082 Const *c = (Const *) node;
00083
00084
00085 if (c->constisnull)
00086 return makeBoolConst(false, true);
00087
00088 return makeBoolConst(!DatumGetBool(c->constvalue), false);
00089 }
00090 break;
00091 case T_OpExpr:
00092 {
00093
00094
00095
00096 OpExpr *opexpr = (OpExpr *) node;
00097 Oid negator = get_negator(opexpr->opno);
00098
00099 if (negator)
00100 {
00101 OpExpr *newopexpr = makeNode(OpExpr);
00102
00103 newopexpr->opno = negator;
00104 newopexpr->opfuncid = InvalidOid;
00105 newopexpr->opresulttype = opexpr->opresulttype;
00106 newopexpr->opretset = opexpr->opretset;
00107 newopexpr->opcollid = opexpr->opcollid;
00108 newopexpr->inputcollid = opexpr->inputcollid;
00109 newopexpr->args = opexpr->args;
00110 newopexpr->location = opexpr->location;
00111 return (Node *) newopexpr;
00112 }
00113 }
00114 break;
00115 case T_ScalarArrayOpExpr:
00116 {
00117
00118
00119
00120
00121 ScalarArrayOpExpr *saopexpr = (ScalarArrayOpExpr *) node;
00122 Oid negator = get_negator(saopexpr->opno);
00123
00124 if (negator)
00125 {
00126 ScalarArrayOpExpr *newopexpr = makeNode(ScalarArrayOpExpr);
00127
00128 newopexpr->opno = negator;
00129 newopexpr->opfuncid = InvalidOid;
00130 newopexpr->useOr = !saopexpr->useOr;
00131 newopexpr->inputcollid = saopexpr->inputcollid;
00132 newopexpr->args = saopexpr->args;
00133 newopexpr->location = saopexpr->location;
00134 return (Node *) newopexpr;
00135 }
00136 }
00137 break;
00138 case T_BoolExpr:
00139 {
00140 BoolExpr *expr = (BoolExpr *) node;
00141
00142 switch (expr->boolop)
00143 {
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 case AND_EXPR:
00160 {
00161 List *nargs = NIL;
00162 ListCell *lc;
00163
00164 foreach(lc, expr->args)
00165 {
00166 nargs = lappend(nargs,
00167 negate_clause(lfirst(lc)));
00168 }
00169 return (Node *) make_orclause(nargs);
00170 }
00171 break;
00172 case OR_EXPR:
00173 {
00174 List *nargs = NIL;
00175 ListCell *lc;
00176
00177 foreach(lc, expr->args)
00178 {
00179 nargs = lappend(nargs,
00180 negate_clause(lfirst(lc)));
00181 }
00182 return (Node *) make_andclause(nargs);
00183 }
00184 break;
00185 case NOT_EXPR:
00186
00187
00188
00189
00190
00191 return (Node *) linitial(expr->args);
00192 default:
00193 elog(ERROR, "unrecognized boolop: %d",
00194 (int) expr->boolop);
00195 break;
00196 }
00197 }
00198 break;
00199 case T_NullTest:
00200 {
00201 NullTest *expr = (NullTest *) node;
00202
00203
00204
00205
00206
00207
00208 if (!expr->argisrow)
00209 {
00210 NullTest *newexpr = makeNode(NullTest);
00211
00212 newexpr->arg = expr->arg;
00213 newexpr->nulltesttype = (expr->nulltesttype == IS_NULL ?
00214 IS_NOT_NULL : IS_NULL);
00215 newexpr->argisrow = expr->argisrow;
00216 return (Node *) newexpr;
00217 }
00218 }
00219 break;
00220 case T_BooleanTest:
00221 {
00222 BooleanTest *expr = (BooleanTest *) node;
00223 BooleanTest *newexpr = makeNode(BooleanTest);
00224
00225 newexpr->arg = expr->arg;
00226 switch (expr->booltesttype)
00227 {
00228 case IS_TRUE:
00229 newexpr->booltesttype = IS_NOT_TRUE;
00230 break;
00231 case IS_NOT_TRUE:
00232 newexpr->booltesttype = IS_TRUE;
00233 break;
00234 case IS_FALSE:
00235 newexpr->booltesttype = IS_NOT_FALSE;
00236 break;
00237 case IS_NOT_FALSE:
00238 newexpr->booltesttype = IS_FALSE;
00239 break;
00240 case IS_UNKNOWN:
00241 newexpr->booltesttype = IS_NOT_UNKNOWN;
00242 break;
00243 case IS_NOT_UNKNOWN:
00244 newexpr->booltesttype = IS_UNKNOWN;
00245 break;
00246 default:
00247 elog(ERROR, "unrecognized booltesttype: %d",
00248 (int) expr->booltesttype);
00249 break;
00250 }
00251 return (Node *) newexpr;
00252 }
00253 break;
00254 default:
00255
00256 break;
00257 }
00258
00259
00260
00261
00262
00263 return (Node *) make_notclause((Expr *) node);
00264 }
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284 Expr *
00285 canonicalize_qual(Expr *qual)
00286 {
00287 Expr *newqual;
00288
00289
00290 if (qual == NULL)
00291 return NULL;
00292
00293
00294
00295
00296
00297
00298 newqual = find_duplicate_ors(qual);
00299
00300 return newqual;
00301 }
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311 static List *
00312 pull_ands(List *andlist)
00313 {
00314 List *out_list = NIL;
00315 ListCell *arg;
00316
00317 foreach(arg, andlist)
00318 {
00319 Node *subexpr = (Node *) lfirst(arg);
00320
00321
00322
00323
00324
00325
00326
00327 if (and_clause(subexpr))
00328 out_list = list_concat(out_list,
00329 pull_ands(((BoolExpr *) subexpr)->args));
00330 else
00331 out_list = lappend(out_list, subexpr);
00332 }
00333 return out_list;
00334 }
00335
00336
00337
00338
00339
00340
00341
00342
00343 static List *
00344 pull_ors(List *orlist)
00345 {
00346 List *out_list = NIL;
00347 ListCell *arg;
00348
00349 foreach(arg, orlist)
00350 {
00351 Node *subexpr = (Node *) lfirst(arg);
00352
00353
00354
00355
00356
00357
00358
00359 if (or_clause(subexpr))
00360 out_list = list_concat(out_list,
00361 pull_ors(((BoolExpr *) subexpr)->args));
00362 else
00363 out_list = lappend(out_list, subexpr);
00364 }
00365 return out_list;
00366 }
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398 static Expr *
00399 find_duplicate_ors(Expr *qual)
00400 {
00401 if (or_clause((Node *) qual))
00402 {
00403 List *orlist = NIL;
00404 ListCell *temp;
00405
00406
00407 foreach(temp, ((BoolExpr *) qual)->args)
00408 orlist = lappend(orlist, find_duplicate_ors(lfirst(temp)));
00409
00410
00411
00412
00413
00414 return process_duplicate_ors(orlist);
00415 }
00416 else if (and_clause((Node *) qual))
00417 {
00418 List *andlist = NIL;
00419 ListCell *temp;
00420
00421
00422 foreach(temp, ((BoolExpr *) qual)->args)
00423 andlist = lappend(andlist, find_duplicate_ors(lfirst(temp)));
00424
00425 andlist = pull_ands(andlist);
00426
00427 return make_andclause(andlist);
00428 }
00429 else
00430 return qual;
00431 }
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441 static Expr *
00442 process_duplicate_ors(List *orlist)
00443 {
00444 List *reference = NIL;
00445 int num_subclauses = 0;
00446 List *winners;
00447 List *neworlist;
00448 ListCell *temp;
00449
00450 if (orlist == NIL)
00451 return NULL;
00452 if (list_length(orlist) == 1)
00453
00454 return linitial(orlist);
00455
00456
00457
00458
00459
00460
00461
00462 foreach(temp, orlist)
00463 {
00464 Expr *clause = (Expr *) lfirst(temp);
00465
00466 if (and_clause((Node *) clause))
00467 {
00468 List *subclauses = ((BoolExpr *) clause)->args;
00469 int nclauses = list_length(subclauses);
00470
00471 if (reference == NIL || nclauses < num_subclauses)
00472 {
00473 reference = subclauses;
00474 num_subclauses = nclauses;
00475 }
00476 }
00477 else
00478 {
00479 reference = list_make1(clause);
00480 break;
00481 }
00482 }
00483
00484
00485
00486
00487 reference = list_union(NIL, reference);
00488
00489
00490
00491
00492
00493 winners = NIL;
00494 foreach(temp, reference)
00495 {
00496 Expr *refclause = (Expr *) lfirst(temp);
00497 bool win = true;
00498 ListCell *temp2;
00499
00500 foreach(temp2, orlist)
00501 {
00502 Expr *clause = (Expr *) lfirst(temp2);
00503
00504 if (and_clause((Node *) clause))
00505 {
00506 if (!list_member(((BoolExpr *) clause)->args, refclause))
00507 {
00508 win = false;
00509 break;
00510 }
00511 }
00512 else
00513 {
00514 if (!equal(refclause, clause))
00515 {
00516 win = false;
00517 break;
00518 }
00519 }
00520 }
00521
00522 if (win)
00523 winners = lappend(winners, refclause);
00524 }
00525
00526
00527
00528
00529 if (winners == NIL)
00530 return make_orclause(orlist);
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542 neworlist = NIL;
00543 foreach(temp, orlist)
00544 {
00545 Expr *clause = (Expr *) lfirst(temp);
00546
00547 if (and_clause((Node *) clause))
00548 {
00549 List *subclauses = ((BoolExpr *) clause)->args;
00550
00551 subclauses = list_difference(subclauses, winners);
00552 if (subclauses != NIL)
00553 {
00554 if (list_length(subclauses) == 1)
00555 neworlist = lappend(neworlist, linitial(subclauses));
00556 else
00557 neworlist = lappend(neworlist, make_andclause(subclauses));
00558 }
00559 else
00560 {
00561 neworlist = NIL;
00562 break;
00563 }
00564 }
00565 else
00566 {
00567 if (!list_member(winners, clause))
00568 neworlist = lappend(neworlist, clause);
00569 else
00570 {
00571 neworlist = NIL;
00572 break;
00573 }
00574 }
00575 }
00576
00577
00578
00579
00580
00581
00582
00583 if (neworlist != NIL)
00584 {
00585 if (list_length(neworlist) == 1)
00586 winners = lappend(winners, linitial(neworlist));
00587 else
00588 winners = lappend(winners, make_orclause(pull_ors(neworlist)));
00589 }
00590
00591
00592
00593
00594
00595 if (list_length(winners) == 1)
00596 return (Expr *) linitial(winners);
00597 else
00598 return make_andclause(pull_ands(winners));
00599 }