00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "postgres.h"
00017
00018 #include "catalog/pg_proc.h"
00019 #include "catalog/pg_type.h"
00020 #include "executor/executor.h"
00021 #include "miscadmin.h"
00022 #include "optimizer/clauses.h"
00023 #include "optimizer/planmain.h"
00024 #include "optimizer/predtest.h"
00025 #include "utils/array.h"
00026 #include "utils/inval.h"
00027 #include "utils/lsyscache.h"
00028 #include "utils/syscache.h"
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #define MAX_SAOP_ARRAY_SIZE 100
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 typedef enum
00049 {
00050 CLASS_ATOM,
00051 CLASS_AND,
00052 CLASS_OR
00053 } PredClass;
00054
00055 typedef struct PredIterInfoData *PredIterInfo;
00056
00057 typedef struct PredIterInfoData
00058 {
00059
00060 void *state;
00061
00062 void (*startup_fn) (Node *clause, PredIterInfo info);
00063
00064 Node *(*next_fn) (PredIterInfo info);
00065
00066 void (*cleanup_fn) (PredIterInfo info);
00067 } PredIterInfoData;
00068
00069 #define iterate_begin(item, clause, info) \
00070 do { \
00071 Node *item; \
00072 (info).startup_fn((clause), &(info)); \
00073 while ((item = (info).next_fn(&(info))) != NULL)
00074
00075 #define iterate_end(info) \
00076 (info).cleanup_fn(&(info)); \
00077 } while (0)
00078
00079
00080 static bool predicate_implied_by_recurse(Node *clause, Node *predicate);
00081 static bool predicate_refuted_by_recurse(Node *clause, Node *predicate);
00082 static PredClass predicate_classify(Node *clause, PredIterInfo info);
00083 static void list_startup_fn(Node *clause, PredIterInfo info);
00084 static Node *list_next_fn(PredIterInfo info);
00085 static void list_cleanup_fn(PredIterInfo info);
00086 static void boolexpr_startup_fn(Node *clause, PredIterInfo info);
00087 static void arrayconst_startup_fn(Node *clause, PredIterInfo info);
00088 static Node *arrayconst_next_fn(PredIterInfo info);
00089 static void arrayconst_cleanup_fn(PredIterInfo info);
00090 static void arrayexpr_startup_fn(Node *clause, PredIterInfo info);
00091 static Node *arrayexpr_next_fn(PredIterInfo info);
00092 static void arrayexpr_cleanup_fn(PredIterInfo info);
00093 static bool predicate_implied_by_simple_clause(Expr *predicate, Node *clause);
00094 static bool predicate_refuted_by_simple_clause(Expr *predicate, Node *clause);
00095 static Node *extract_not_arg(Node *clause);
00096 static Node *extract_strong_not_arg(Node *clause);
00097 static bool list_member_strip(List *list, Expr *datum);
00098 static bool btree_predicate_proof(Expr *predicate, Node *clause,
00099 bool refute_it);
00100 static Oid get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it);
00101 static void InvalidateOprProofCacheCallBack(Datum arg, int cacheid, uint32 hashvalue);
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 bool
00124 predicate_implied_by(List *predicate_list, List *restrictinfo_list)
00125 {
00126 Node *p,
00127 *r;
00128
00129 if (predicate_list == NIL)
00130 return true;
00131 if (restrictinfo_list == NIL)
00132 return false;
00133
00134
00135
00136
00137
00138
00139
00140 if (list_length(predicate_list) == 1)
00141 p = (Node *) linitial(predicate_list);
00142 else
00143 p = (Node *) predicate_list;
00144 if (list_length(restrictinfo_list) == 1)
00145 r = (Node *) linitial(restrictinfo_list);
00146 else
00147 r = (Node *) restrictinfo_list;
00148
00149
00150 return predicate_implied_by_recurse(r, p);
00151 }
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181 bool
00182 predicate_refuted_by(List *predicate_list, List *restrictinfo_list)
00183 {
00184 Node *p,
00185 *r;
00186
00187 if (predicate_list == NIL)
00188 return false;
00189 if (restrictinfo_list == NIL)
00190 return false;
00191
00192
00193
00194
00195
00196
00197
00198 if (list_length(predicate_list) == 1)
00199 p = (Node *) linitial(predicate_list);
00200 else
00201 p = (Node *) predicate_list;
00202 if (list_length(restrictinfo_list) == 1)
00203 r = (Node *) linitial(restrictinfo_list);
00204 else
00205 r = (Node *) restrictinfo_list;
00206
00207
00208 return predicate_refuted_by_recurse(r, p);
00209 }
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246 static bool
00247 predicate_implied_by_recurse(Node *clause, Node *predicate)
00248 {
00249 PredIterInfoData clause_info;
00250 PredIterInfoData pred_info;
00251 PredClass pclass;
00252 bool result;
00253
00254
00255 Assert(clause != NULL);
00256 if (IsA(clause, RestrictInfo))
00257 clause = (Node *) ((RestrictInfo *) clause)->clause;
00258
00259 pclass = predicate_classify(predicate, &pred_info);
00260
00261 switch (predicate_classify(clause, &clause_info))
00262 {
00263 case CLASS_AND:
00264 switch (pclass)
00265 {
00266 case CLASS_AND:
00267
00268
00269
00270
00271 result = true;
00272 iterate_begin(pitem, predicate, pred_info)
00273 {
00274 if (!predicate_implied_by_recurse(clause, pitem))
00275 {
00276 result = false;
00277 break;
00278 }
00279 }
00280 iterate_end(pred_info);
00281 return result;
00282
00283 case CLASS_OR:
00284
00285
00286
00287
00288
00289
00290 result = false;
00291 iterate_begin(pitem, predicate, pred_info)
00292 {
00293 if (predicate_implied_by_recurse(clause, pitem))
00294 {
00295 result = true;
00296 break;
00297 }
00298 }
00299 iterate_end(pred_info);
00300 if (result)
00301 return result;
00302
00303
00304
00305
00306
00307
00308 iterate_begin(citem, clause, clause_info)
00309 {
00310 if (predicate_implied_by_recurse(citem, predicate))
00311 {
00312 result = true;
00313 break;
00314 }
00315 }
00316 iterate_end(clause_info);
00317 return result;
00318
00319 case CLASS_ATOM:
00320
00321
00322
00323
00324 result = false;
00325 iterate_begin(citem, clause, clause_info)
00326 {
00327 if (predicate_implied_by_recurse(citem, predicate))
00328 {
00329 result = true;
00330 break;
00331 }
00332 }
00333 iterate_end(clause_info);
00334 return result;
00335 }
00336 break;
00337
00338 case CLASS_OR:
00339 switch (pclass)
00340 {
00341 case CLASS_OR:
00342
00343
00344
00345
00346
00347 result = true;
00348 iterate_begin(citem, clause, clause_info)
00349 {
00350 bool presult = false;
00351
00352 iterate_begin(pitem, predicate, pred_info)
00353 {
00354 if (predicate_implied_by_recurse(citem, pitem))
00355 {
00356 presult = true;
00357 break;
00358 }
00359 }
00360 iterate_end(pred_info);
00361 if (!presult)
00362 {
00363 result = false;
00364 break;
00365 }
00366 }
00367 iterate_end(clause_info);
00368 return result;
00369
00370 case CLASS_AND:
00371 case CLASS_ATOM:
00372
00373
00374
00375
00376
00377
00378 result = true;
00379 iterate_begin(citem, clause, clause_info)
00380 {
00381 if (!predicate_implied_by_recurse(citem, predicate))
00382 {
00383 result = false;
00384 break;
00385 }
00386 }
00387 iterate_end(clause_info);
00388 return result;
00389 }
00390 break;
00391
00392 case CLASS_ATOM:
00393 switch (pclass)
00394 {
00395 case CLASS_AND:
00396
00397
00398
00399
00400 result = true;
00401 iterate_begin(pitem, predicate, pred_info)
00402 {
00403 if (!predicate_implied_by_recurse(clause, pitem))
00404 {
00405 result = false;
00406 break;
00407 }
00408 }
00409 iterate_end(pred_info);
00410 return result;
00411
00412 case CLASS_OR:
00413
00414
00415
00416
00417 result = false;
00418 iterate_begin(pitem, predicate, pred_info)
00419 {
00420 if (predicate_implied_by_recurse(clause, pitem))
00421 {
00422 result = true;
00423 break;
00424 }
00425 }
00426 iterate_end(pred_info);
00427 return result;
00428
00429 case CLASS_ATOM:
00430
00431
00432
00433
00434 return
00435 predicate_implied_by_simple_clause((Expr *) predicate,
00436 clause);
00437 }
00438 break;
00439 }
00440
00441
00442 elog(ERROR, "predicate_classify returned a bogus value");
00443 return false;
00444 }
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476 static bool
00477 predicate_refuted_by_recurse(Node *clause, Node *predicate)
00478 {
00479 PredIterInfoData clause_info;
00480 PredIterInfoData pred_info;
00481 PredClass pclass;
00482 Node *not_arg;
00483 bool result;
00484
00485
00486 Assert(clause != NULL);
00487 if (IsA(clause, RestrictInfo))
00488 clause = (Node *) ((RestrictInfo *) clause)->clause;
00489
00490 pclass = predicate_classify(predicate, &pred_info);
00491
00492 switch (predicate_classify(clause, &clause_info))
00493 {
00494 case CLASS_AND:
00495 switch (pclass)
00496 {
00497 case CLASS_AND:
00498
00499
00500
00501
00502
00503
00504 result = false;
00505 iterate_begin(pitem, predicate, pred_info)
00506 {
00507 if (predicate_refuted_by_recurse(clause, pitem))
00508 {
00509 result = true;
00510 break;
00511 }
00512 }
00513 iterate_end(pred_info);
00514 if (result)
00515 return result;
00516
00517
00518
00519
00520
00521
00522 iterate_begin(citem, clause, clause_info)
00523 {
00524 if (predicate_refuted_by_recurse(citem, predicate))
00525 {
00526 result = true;
00527 break;
00528 }
00529 }
00530 iterate_end(clause_info);
00531 return result;
00532
00533 case CLASS_OR:
00534
00535
00536
00537
00538 result = true;
00539 iterate_begin(pitem, predicate, pred_info)
00540 {
00541 if (!predicate_refuted_by_recurse(clause, pitem))
00542 {
00543 result = false;
00544 break;
00545 }
00546 }
00547 iterate_end(pred_info);
00548 return result;
00549
00550 case CLASS_ATOM:
00551
00552
00553
00554
00555 not_arg = extract_not_arg(predicate);
00556 if (not_arg &&
00557 predicate_implied_by_recurse(clause, not_arg))
00558 return true;
00559
00560
00561
00562
00563 result = false;
00564 iterate_begin(citem, clause, clause_info)
00565 {
00566 if (predicate_refuted_by_recurse(citem, predicate))
00567 {
00568 result = true;
00569 break;
00570 }
00571 }
00572 iterate_end(clause_info);
00573 return result;
00574 }
00575 break;
00576
00577 case CLASS_OR:
00578 switch (pclass)
00579 {
00580 case CLASS_OR:
00581
00582
00583
00584
00585 result = true;
00586 iterate_begin(pitem, predicate, pred_info)
00587 {
00588 if (!predicate_refuted_by_recurse(clause, pitem))
00589 {
00590 result = false;
00591 break;
00592 }
00593 }
00594 iterate_end(pred_info);
00595 return result;
00596
00597 case CLASS_AND:
00598
00599
00600
00601
00602
00603 result = true;
00604 iterate_begin(citem, clause, clause_info)
00605 {
00606 bool presult = false;
00607
00608 iterate_begin(pitem, predicate, pred_info)
00609 {
00610 if (predicate_refuted_by_recurse(citem, pitem))
00611 {
00612 presult = true;
00613 break;
00614 }
00615 }
00616 iterate_end(pred_info);
00617 if (!presult)
00618 {
00619 result = false;
00620 break;
00621 }
00622 }
00623 iterate_end(clause_info);
00624 return result;
00625
00626 case CLASS_ATOM:
00627
00628
00629
00630
00631 not_arg = extract_not_arg(predicate);
00632 if (not_arg &&
00633 predicate_implied_by_recurse(clause, not_arg))
00634 return true;
00635
00636
00637
00638
00639 result = true;
00640 iterate_begin(citem, clause, clause_info)
00641 {
00642 if (!predicate_refuted_by_recurse(citem, predicate))
00643 {
00644 result = false;
00645 break;
00646 }
00647 }
00648 iterate_end(clause_info);
00649 return result;
00650 }
00651 break;
00652
00653 case CLASS_ATOM:
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664 not_arg = extract_strong_not_arg(clause);
00665 if (not_arg && equal(predicate, not_arg))
00666 return true;
00667
00668 switch (pclass)
00669 {
00670 case CLASS_AND:
00671
00672
00673
00674
00675 result = false;
00676 iterate_begin(pitem, predicate, pred_info)
00677 {
00678 if (predicate_refuted_by_recurse(clause, pitem))
00679 {
00680 result = true;
00681 break;
00682 }
00683 }
00684 iterate_end(pred_info);
00685 return result;
00686
00687 case CLASS_OR:
00688
00689
00690
00691
00692 result = true;
00693 iterate_begin(pitem, predicate, pred_info)
00694 {
00695 if (!predicate_refuted_by_recurse(clause, pitem))
00696 {
00697 result = false;
00698 break;
00699 }
00700 }
00701 iterate_end(pred_info);
00702 return result;
00703
00704 case CLASS_ATOM:
00705
00706
00707
00708
00709 not_arg = extract_not_arg(predicate);
00710 if (not_arg &&
00711 predicate_implied_by_recurse(clause, not_arg))
00712 return true;
00713
00714
00715
00716
00717 return
00718 predicate_refuted_by_simple_clause((Expr *) predicate,
00719 clause);
00720 }
00721 break;
00722 }
00723
00724
00725 elog(ERROR, "predicate_classify returned a bogus value");
00726 return false;
00727 }
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744 static PredClass
00745 predicate_classify(Node *clause, PredIterInfo info)
00746 {
00747
00748 Assert(clause != NULL);
00749 Assert(!IsA(clause, RestrictInfo));
00750
00751
00752
00753
00754
00755 if (IsA(clause, List))
00756 {
00757 info->startup_fn = list_startup_fn;
00758 info->next_fn = list_next_fn;
00759 info->cleanup_fn = list_cleanup_fn;
00760 return CLASS_AND;
00761 }
00762
00763
00764 if (and_clause(clause))
00765 {
00766 info->startup_fn = boolexpr_startup_fn;
00767 info->next_fn = list_next_fn;
00768 info->cleanup_fn = list_cleanup_fn;
00769 return CLASS_AND;
00770 }
00771 if (or_clause(clause))
00772 {
00773 info->startup_fn = boolexpr_startup_fn;
00774 info->next_fn = list_next_fn;
00775 info->cleanup_fn = list_cleanup_fn;
00776 return CLASS_OR;
00777 }
00778
00779
00780 if (IsA(clause, ScalarArrayOpExpr))
00781 {
00782 ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
00783 Node *arraynode = (Node *) lsecond(saop->args);
00784
00785
00786
00787
00788
00789
00790
00791 if (arraynode && IsA(arraynode, Const) &&
00792 !((Const *) arraynode)->constisnull)
00793 {
00794 ArrayType *arrayval;
00795 int nelems;
00796
00797 arrayval = DatumGetArrayTypeP(((Const *) arraynode)->constvalue);
00798 nelems = ArrayGetNItems(ARR_NDIM(arrayval), ARR_DIMS(arrayval));
00799 if (nelems <= MAX_SAOP_ARRAY_SIZE)
00800 {
00801 info->startup_fn = arrayconst_startup_fn;
00802 info->next_fn = arrayconst_next_fn;
00803 info->cleanup_fn = arrayconst_cleanup_fn;
00804 return saop->useOr ? CLASS_OR : CLASS_AND;
00805 }
00806 }
00807 else if (arraynode && IsA(arraynode, ArrayExpr) &&
00808 !((ArrayExpr *) arraynode)->multidims &&
00809 list_length(((ArrayExpr *) arraynode)->elements) <= MAX_SAOP_ARRAY_SIZE)
00810 {
00811 info->startup_fn = arrayexpr_startup_fn;
00812 info->next_fn = arrayexpr_next_fn;
00813 info->cleanup_fn = arrayexpr_cleanup_fn;
00814 return saop->useOr ? CLASS_OR : CLASS_AND;
00815 }
00816 }
00817
00818
00819 return CLASS_ATOM;
00820 }
00821
00822
00823
00824
00825
00826 static void
00827 list_startup_fn(Node *clause, PredIterInfo info)
00828 {
00829 info->state = (void *) list_head((List *) clause);
00830 }
00831
00832 static Node *
00833 list_next_fn(PredIterInfo info)
00834 {
00835 ListCell *l = (ListCell *) info->state;
00836 Node *n;
00837
00838 if (l == NULL)
00839 return NULL;
00840 n = lfirst(l);
00841 info->state = (void *) lnext(l);
00842 return n;
00843 }
00844
00845 static void
00846 list_cleanup_fn(PredIterInfo info)
00847 {
00848
00849 }
00850
00851
00852
00853
00854
00855 static void
00856 boolexpr_startup_fn(Node *clause, PredIterInfo info)
00857 {
00858 info->state = (void *) list_head(((BoolExpr *) clause)->args);
00859 }
00860
00861
00862
00863
00864
00865 typedef struct
00866 {
00867 OpExpr opexpr;
00868 Const constexpr;
00869 int next_elem;
00870 int num_elems;
00871 Datum *elem_values;
00872 bool *elem_nulls;
00873 } ArrayConstIterState;
00874
00875 static void
00876 arrayconst_startup_fn(Node *clause, PredIterInfo info)
00877 {
00878 ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
00879 ArrayConstIterState *state;
00880 Const *arrayconst;
00881 ArrayType *arrayval;
00882 int16 elmlen;
00883 bool elmbyval;
00884 char elmalign;
00885
00886
00887 state = (ArrayConstIterState *) palloc(sizeof(ArrayConstIterState));
00888 info->state = (void *) state;
00889
00890
00891 arrayconst = (Const *) lsecond(saop->args);
00892 arrayval = DatumGetArrayTypeP(arrayconst->constvalue);
00893 get_typlenbyvalalign(ARR_ELEMTYPE(arrayval),
00894 &elmlen, &elmbyval, &elmalign);
00895 deconstruct_array(arrayval,
00896 ARR_ELEMTYPE(arrayval),
00897 elmlen, elmbyval, elmalign,
00898 &state->elem_values, &state->elem_nulls,
00899 &state->num_elems);
00900
00901
00902 state->opexpr.xpr.type = T_OpExpr;
00903 state->opexpr.opno = saop->opno;
00904 state->opexpr.opfuncid = saop->opfuncid;
00905 state->opexpr.opresulttype = BOOLOID;
00906 state->opexpr.opretset = false;
00907 state->opexpr.opcollid = InvalidOid;
00908 state->opexpr.inputcollid = saop->inputcollid;
00909 state->opexpr.args = list_copy(saop->args);
00910
00911
00912 state->constexpr.xpr.type = T_Const;
00913 state->constexpr.consttype = ARR_ELEMTYPE(arrayval);
00914 state->constexpr.consttypmod = -1;
00915 state->constexpr.constcollid = arrayconst->constcollid;
00916 state->constexpr.constlen = elmlen;
00917 state->constexpr.constbyval = elmbyval;
00918 lsecond(state->opexpr.args) = &state->constexpr;
00919
00920
00921 state->next_elem = 0;
00922 }
00923
00924 static Node *
00925 arrayconst_next_fn(PredIterInfo info)
00926 {
00927 ArrayConstIterState *state = (ArrayConstIterState *) info->state;
00928
00929 if (state->next_elem >= state->num_elems)
00930 return NULL;
00931 state->constexpr.constvalue = state->elem_values[state->next_elem];
00932 state->constexpr.constisnull = state->elem_nulls[state->next_elem];
00933 state->next_elem++;
00934 return (Node *) &(state->opexpr);
00935 }
00936
00937 static void
00938 arrayconst_cleanup_fn(PredIterInfo info)
00939 {
00940 ArrayConstIterState *state = (ArrayConstIterState *) info->state;
00941
00942 pfree(state->elem_values);
00943 pfree(state->elem_nulls);
00944 list_free(state->opexpr.args);
00945 pfree(state);
00946 }
00947
00948
00949
00950
00951
00952 typedef struct
00953 {
00954 OpExpr opexpr;
00955 ListCell *next;
00956 } ArrayExprIterState;
00957
00958 static void
00959 arrayexpr_startup_fn(Node *clause, PredIterInfo info)
00960 {
00961 ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
00962 ArrayExprIterState *state;
00963 ArrayExpr *arrayexpr;
00964
00965
00966 state = (ArrayExprIterState *) palloc(sizeof(ArrayExprIterState));
00967 info->state = (void *) state;
00968
00969
00970 state->opexpr.xpr.type = T_OpExpr;
00971 state->opexpr.opno = saop->opno;
00972 state->opexpr.opfuncid = saop->opfuncid;
00973 state->opexpr.opresulttype = BOOLOID;
00974 state->opexpr.opretset = false;
00975 state->opexpr.opcollid = InvalidOid;
00976 state->opexpr.inputcollid = saop->inputcollid;
00977 state->opexpr.args = list_copy(saop->args);
00978
00979
00980 arrayexpr = (ArrayExpr *) lsecond(saop->args);
00981 state->next = list_head(arrayexpr->elements);
00982 }
00983
00984 static Node *
00985 arrayexpr_next_fn(PredIterInfo info)
00986 {
00987 ArrayExprIterState *state = (ArrayExprIterState *) info->state;
00988
00989 if (state->next == NULL)
00990 return NULL;
00991 lsecond(state->opexpr.args) = lfirst(state->next);
00992 state->next = lnext(state->next);
00993 return (Node *) &(state->opexpr);
00994 }
00995
00996 static void
00997 arrayexpr_cleanup_fn(PredIterInfo info)
00998 {
00999 ArrayExprIterState *state = (ArrayExprIterState *) info->state;
01000
01001 list_free(state->opexpr.args);
01002 pfree(state);
01003 }
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032 static bool
01033 predicate_implied_by_simple_clause(Expr *predicate, Node *clause)
01034 {
01035
01036 CHECK_FOR_INTERRUPTS();
01037
01038
01039 if (equal((Node *) predicate, clause))
01040 return true;
01041
01042
01043 if (predicate && IsA(predicate, NullTest) &&
01044 ((NullTest *) predicate)->nulltesttype == IS_NOT_NULL)
01045 {
01046 Expr *nonnullarg = ((NullTest *) predicate)->arg;
01047
01048
01049 if (!((NullTest *) predicate)->argisrow)
01050 {
01051 if (is_opclause(clause) &&
01052 list_member_strip(((OpExpr *) clause)->args, nonnullarg) &&
01053 op_strict(((OpExpr *) clause)->opno))
01054 return true;
01055 if (is_funcclause(clause) &&
01056 list_member_strip(((FuncExpr *) clause)->args, nonnullarg) &&
01057 func_strict(((FuncExpr *) clause)->funcid))
01058 return true;
01059 }
01060 return false;
01061 }
01062
01063
01064 return btree_predicate_proof(predicate, clause, false);
01065 }
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090 static bool
01091 predicate_refuted_by_simple_clause(Expr *predicate, Node *clause)
01092 {
01093
01094 CHECK_FOR_INTERRUPTS();
01095
01096
01097
01098 if ((Node *) predicate == clause)
01099 return false;
01100
01101
01102 if (predicate && IsA(predicate, NullTest) &&
01103 ((NullTest *) predicate)->nulltesttype == IS_NULL)
01104 {
01105 Expr *isnullarg = ((NullTest *) predicate)->arg;
01106
01107
01108 if (((NullTest *) predicate)->argisrow)
01109 return false;
01110
01111
01112 if (is_opclause(clause) &&
01113 list_member_strip(((OpExpr *) clause)->args, isnullarg) &&
01114 op_strict(((OpExpr *) clause)->opno))
01115 return true;
01116 if (is_funcclause(clause) &&
01117 list_member_strip(((FuncExpr *) clause)->args, isnullarg) &&
01118 func_strict(((FuncExpr *) clause)->funcid))
01119 return true;
01120
01121
01122 if (clause && IsA(clause, NullTest) &&
01123 ((NullTest *) clause)->nulltesttype == IS_NOT_NULL &&
01124 !((NullTest *) clause)->argisrow &&
01125 equal(((NullTest *) clause)->arg, isnullarg))
01126 return true;
01127
01128 return false;
01129 }
01130
01131
01132 if (clause && IsA(clause, NullTest) &&
01133 ((NullTest *) clause)->nulltesttype == IS_NULL)
01134 {
01135 Expr *isnullarg = ((NullTest *) clause)->arg;
01136
01137
01138 if (((NullTest *) clause)->argisrow)
01139 return false;
01140
01141
01142 if (predicate && IsA(predicate, NullTest) &&
01143 ((NullTest *) predicate)->nulltesttype == IS_NOT_NULL &&
01144 !((NullTest *) predicate)->argisrow &&
01145 equal(((NullTest *) predicate)->arg, isnullarg))
01146 return true;
01147
01148 return false;
01149 }
01150
01151
01152 return btree_predicate_proof(predicate, clause, true);
01153 }
01154
01155
01156
01157
01158
01159
01160 static Node *
01161 extract_not_arg(Node *clause)
01162 {
01163 if (clause == NULL)
01164 return NULL;
01165 if (IsA(clause, BoolExpr))
01166 {
01167 BoolExpr *bexpr = (BoolExpr *) clause;
01168
01169 if (bexpr->boolop == NOT_EXPR)
01170 return (Node *) linitial(bexpr->args);
01171 }
01172 else if (IsA(clause, BooleanTest))
01173 {
01174 BooleanTest *btest = (BooleanTest *) clause;
01175
01176 if (btest->booltesttype == IS_NOT_TRUE ||
01177 btest->booltesttype == IS_FALSE ||
01178 btest->booltesttype == IS_UNKNOWN)
01179 return (Node *) btest->arg;
01180 }
01181 return NULL;
01182 }
01183
01184
01185
01186
01187
01188 static Node *
01189 extract_strong_not_arg(Node *clause)
01190 {
01191 if (clause == NULL)
01192 return NULL;
01193 if (IsA(clause, BoolExpr))
01194 {
01195 BoolExpr *bexpr = (BoolExpr *) clause;
01196
01197 if (bexpr->boolop == NOT_EXPR)
01198 return (Node *) linitial(bexpr->args);
01199 }
01200 else if (IsA(clause, BooleanTest))
01201 {
01202 BooleanTest *btest = (BooleanTest *) clause;
01203
01204 if (btest->booltesttype == IS_FALSE)
01205 return (Node *) btest->arg;
01206 }
01207 return NULL;
01208 }
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218 static bool
01219 list_member_strip(List *list, Expr *datum)
01220 {
01221 ListCell *cell;
01222
01223 if (datum && IsA(datum, RelabelType))
01224 datum = ((RelabelType *) datum)->arg;
01225
01226 foreach(cell, list)
01227 {
01228 Expr *elem = (Expr *) lfirst(cell);
01229
01230 if (elem && IsA(elem, RelabelType))
01231 elem = ((RelabelType *) elem)->arg;
01232
01233 if (equal(elem, datum))
01234 return true;
01235 }
01236
01237 return false;
01238 }
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282 #define BTLT BTLessStrategyNumber
01283 #define BTLE BTLessEqualStrategyNumber
01284 #define BTEQ BTEqualStrategyNumber
01285 #define BTGE BTGreaterEqualStrategyNumber
01286 #define BTGT BTGreaterStrategyNumber
01287 #define BTNE ROWCOMPARE_NE
01288
01289 static const StrategyNumber BT_implic_table[6][6] = {
01290
01291
01292
01293
01294
01295 {BTGE, BTGE, 0, 0, 0, BTGE},
01296 {BTGT, BTGE, 0, 0, 0, BTGT},
01297 {BTGT, BTGE, BTEQ, BTLE, BTLT, BTNE},
01298 {0, 0, 0, BTLE, BTLT, BTLT},
01299 {0, 0, 0, BTLE, BTLE, BTLE},
01300 {0, 0, 0, 0, 0, BTEQ}
01301 };
01302
01303 static const StrategyNumber BT_refute_table[6][6] = {
01304
01305
01306
01307
01308
01309 {0, 0, BTGE, BTGE, BTGE, 0},
01310 {0, 0, BTGT, BTGT, BTGE, 0},
01311 {BTLE, BTLT, BTNE, BTGT, BTGE, BTEQ},
01312 {BTLE, BTLT, BTLT, 0, 0, 0},
01313 {BTLE, BTLE, BTLE, 0, 0, 0},
01314 {0, 0, BTEQ, 0, 0, 0}
01315 };
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340 static bool
01341 btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
01342 {
01343 Node *leftop,
01344 *rightop;
01345 Node *pred_var,
01346 *clause_var;
01347 Const *pred_const,
01348 *clause_const;
01349 bool pred_var_on_left,
01350 clause_var_on_left;
01351 Oid pred_collation,
01352 clause_collation;
01353 Oid pred_op,
01354 clause_op,
01355 test_op;
01356 Expr *test_expr;
01357 ExprState *test_exprstate;
01358 Datum test_result;
01359 bool isNull;
01360 EState *estate;
01361 MemoryContext oldcontext;
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372 if (!is_opclause(predicate))
01373 return false;
01374 leftop = get_leftop(predicate);
01375 rightop = get_rightop(predicate);
01376 if (rightop == NULL)
01377 return false;
01378 if (IsA(rightop, Const))
01379 {
01380 pred_var = leftop;
01381 pred_const = (Const *) rightop;
01382 pred_var_on_left = true;
01383 }
01384 else if (IsA(leftop, Const))
01385 {
01386 pred_var = rightop;
01387 pred_const = (Const *) leftop;
01388 pred_var_on_left = false;
01389 }
01390 else
01391 return false;
01392 if (pred_const->constisnull)
01393 return false;
01394
01395 if (!is_opclause(clause))
01396 return false;
01397 leftop = get_leftop((Expr *) clause);
01398 rightop = get_rightop((Expr *) clause);
01399 if (rightop == NULL)
01400 return false;
01401 if (IsA(rightop, Const))
01402 {
01403 clause_var = leftop;
01404 clause_const = (Const *) rightop;
01405 clause_var_on_left = true;
01406 }
01407 else if (IsA(leftop, Const))
01408 {
01409 clause_var = rightop;
01410 clause_const = (Const *) leftop;
01411 clause_var_on_left = false;
01412 }
01413 else
01414 return false;
01415 if (clause_const->constisnull)
01416 return false;
01417
01418
01419
01420
01421
01422
01423
01424
01425 if (!equal(pred_var, clause_var))
01426 return false;
01427
01428
01429
01430
01431 pred_collation = ((OpExpr *) predicate)->inputcollid;
01432 clause_collation = ((OpExpr *) clause)->inputcollid;
01433 if (pred_collation != clause_collation)
01434 return false;
01435
01436
01437
01438
01439
01440 pred_op = ((OpExpr *) predicate)->opno;
01441 if (!pred_var_on_left)
01442 {
01443 pred_op = get_commutator(pred_op);
01444 if (!OidIsValid(pred_op))
01445 return false;
01446 }
01447
01448 clause_op = ((OpExpr *) clause)->opno;
01449 if (!clause_var_on_left)
01450 {
01451 clause_op = get_commutator(clause_op);
01452 if (!OidIsValid(clause_op))
01453 return false;
01454 }
01455
01456
01457
01458
01459
01460 test_op = get_btree_test_op(pred_op, clause_op, refute_it);
01461
01462 if (!OidIsValid(test_op))
01463 {
01464
01465 return false;
01466 }
01467
01468
01469
01470
01471 estate = CreateExecutorState();
01472
01473
01474 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
01475
01476
01477 test_expr = make_opclause(test_op,
01478 BOOLOID,
01479 false,
01480 (Expr *) pred_const,
01481 (Expr *) clause_const,
01482 InvalidOid,
01483 pred_collation);
01484
01485
01486 fix_opfuncids((Node *) test_expr);
01487
01488
01489 test_exprstate = ExecInitExpr(test_expr, NULL);
01490
01491
01492 test_result = ExecEvalExprSwitchContext(test_exprstate,
01493 GetPerTupleExprContext(estate),
01494 &isNull, NULL);
01495
01496
01497 MemoryContextSwitchTo(oldcontext);
01498
01499
01500 FreeExecutorState(estate);
01501
01502 if (isNull)
01503 {
01504
01505 elog(DEBUG2, "null predicate test result");
01506 return false;
01507 }
01508 return DatumGetBool(test_result);
01509 }
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519 typedef struct OprProofCacheKey
01520 {
01521 Oid pred_op;
01522 Oid clause_op;
01523 } OprProofCacheKey;
01524
01525 typedef struct OprProofCacheEntry
01526 {
01527
01528 OprProofCacheKey key;
01529
01530 bool have_implic;
01531 bool have_refute;
01532 Oid implic_test_op;
01533 Oid refute_test_op;
01534 } OprProofCacheEntry;
01535
01536 static HTAB *OprProofCacheHash = NULL;
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552 static Oid
01553 get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it)
01554 {
01555 OprProofCacheKey key;
01556 OprProofCacheEntry *cache_entry;
01557 bool cfound;
01558 Oid test_op = InvalidOid;
01559 bool found = false;
01560 List *pred_op_infos,
01561 *clause_op_infos;
01562 ListCell *lcp,
01563 *lcc;
01564
01565
01566
01567
01568 if (OprProofCacheHash == NULL)
01569 {
01570
01571 HASHCTL ctl;
01572
01573 MemSet(&ctl, 0, sizeof(ctl));
01574 ctl.keysize = sizeof(OprProofCacheKey);
01575 ctl.entrysize = sizeof(OprProofCacheEntry);
01576 ctl.hash = tag_hash;
01577 OprProofCacheHash = hash_create("Btree proof lookup cache", 256,
01578 &ctl, HASH_ELEM | HASH_FUNCTION);
01579
01580
01581 CacheRegisterSyscacheCallback(AMOPOPID,
01582 InvalidateOprProofCacheCallBack,
01583 (Datum) 0);
01584 }
01585
01586 key.pred_op = pred_op;
01587 key.clause_op = clause_op;
01588 cache_entry = (OprProofCacheEntry *) hash_search(OprProofCacheHash,
01589 (void *) &key,
01590 HASH_ENTER, &cfound);
01591 if (!cfound)
01592 {
01593
01594 cache_entry->have_implic = false;
01595 cache_entry->have_refute = false;
01596 }
01597 else
01598 {
01599
01600 if (refute_it)
01601 {
01602 if (cache_entry->have_refute)
01603 return cache_entry->refute_test_op;
01604 }
01605 else
01606 {
01607 if (cache_entry->have_implic)
01608 return cache_entry->implic_test_op;
01609 }
01610 }
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624 clause_op_infos = get_op_btree_interpretation(clause_op);
01625 if (clause_op_infos)
01626 pred_op_infos = get_op_btree_interpretation(pred_op);
01627 else
01628 pred_op_infos = NIL;
01629
01630 foreach(lcp, pred_op_infos)
01631 {
01632 OpBtreeInterpretation *pred_op_info = lfirst(lcp);
01633 Oid opfamily_id = pred_op_info->opfamily_id;
01634
01635 foreach(lcc, clause_op_infos)
01636 {
01637 OpBtreeInterpretation *clause_op_info = lfirst(lcc);
01638 StrategyNumber pred_strategy,
01639 clause_strategy,
01640 test_strategy;
01641
01642
01643 if (opfamily_id != clause_op_info->opfamily_id)
01644 continue;
01645
01646 Assert(clause_op_info->oplefttype == pred_op_info->oplefttype);
01647
01648 pred_strategy = pred_op_info->strategy;
01649 clause_strategy = clause_op_info->strategy;
01650
01651
01652
01653
01654 if (refute_it)
01655 test_strategy = BT_refute_table[clause_strategy - 1][pred_strategy - 1];
01656 else
01657 test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1];
01658
01659 if (test_strategy == 0)
01660 {
01661
01662 continue;
01663 }
01664
01665
01666
01667
01668
01669 if (test_strategy == BTNE)
01670 {
01671 test_op = get_opfamily_member(opfamily_id,
01672 pred_op_info->oprighttype,
01673 clause_op_info->oprighttype,
01674 BTEqualStrategyNumber);
01675 if (OidIsValid(test_op))
01676 test_op = get_negator(test_op);
01677 }
01678 else
01679 {
01680 test_op = get_opfamily_member(opfamily_id,
01681 pred_op_info->oprighttype,
01682 clause_op_info->oprighttype,
01683 test_strategy);
01684 }
01685
01686 if (!OidIsValid(test_op))
01687 continue;
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698 if (op_volatile(test_op) == PROVOLATILE_IMMUTABLE)
01699 {
01700 found = true;
01701 break;
01702 }
01703 }
01704
01705 if (found)
01706 break;
01707 }
01708
01709 list_free_deep(pred_op_infos);
01710 list_free_deep(clause_op_infos);
01711
01712 if (!found)
01713 {
01714
01715 test_op = InvalidOid;
01716 }
01717
01718
01719 if (refute_it)
01720 {
01721 cache_entry->refute_test_op = test_op;
01722 cache_entry->have_refute = true;
01723 }
01724 else
01725 {
01726 cache_entry->implic_test_op = test_op;
01727 cache_entry->have_implic = true;
01728 }
01729
01730 return test_op;
01731 }
01732
01733
01734
01735
01736
01737 static void
01738 InvalidateOprProofCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
01739 {
01740 HASH_SEQ_STATUS status;
01741 OprProofCacheEntry *hentry;
01742
01743 Assert(OprProofCacheHash != NULL);
01744
01745
01746 hash_seq_init(&status, OprProofCacheHash);
01747
01748 while ((hentry = (OprProofCacheEntry *) hash_seq_search(&status)) != NULL)
01749 {
01750 hentry->have_implic = false;
01751 hentry->have_refute = false;
01752 }
01753 }