PostgreSQL Source Code git master
Loading...
Searching...
No Matches
predtest.c File Reference
#include "postgres.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/pathnodes.h"
#include "optimizer/optimizer.h"
#include "utils/array.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
Include dependency graph for predtest.c:

Go to the source code of this file.

Data Structures

struct  PredIterInfoData
 
struct  ArrayConstIterState
 
struct  ArrayExprIterState
 
struct  OprProofCacheKey
 
struct  OprProofCacheEntry
 

Macros

#define MAX_SAOP_ARRAY_SIZE   100
 
#define iterate_begin(item, clause, info)
 
#define iterate_end(info)
 
#define RCLT   COMPARE_LT
 
#define RCLE   COMPARE_LE
 
#define RCEQ   COMPARE_EQ
 
#define RCGE   COMPARE_GE
 
#define RCGT   COMPARE_GT
 
#define RCNE   COMPARE_NE
 
#define none   0
 

Typedefs

typedef struct PredIterInfoDataPredIterInfo
 
typedef struct PredIterInfoData PredIterInfoData
 
typedef struct OprProofCacheKey OprProofCacheKey
 
typedef struct OprProofCacheEntry OprProofCacheEntry
 

Enumerations

enum  PredClass { CLASS_ATOM , CLASS_AND , CLASS_OR }
 

Functions

static bool predicate_implied_by_recurse (Node *clause, Node *predicate, bool weak)
 
static bool predicate_refuted_by_recurse (Node *clause, Node *predicate, bool weak)
 
static PredClass predicate_classify (Node *clause, PredIterInfo info)
 
static void list_startup_fn (Node *clause, PredIterInfo info)
 
static Nodelist_next_fn (PredIterInfo info)
 
static void list_cleanup_fn (PredIterInfo info)
 
static void boolexpr_startup_fn (Node *clause, PredIterInfo info)
 
static void arrayconst_startup_fn (Node *clause, PredIterInfo info)
 
static Nodearrayconst_next_fn (PredIterInfo info)
 
static void arrayconst_cleanup_fn (PredIterInfo info)
 
static void arrayexpr_startup_fn (Node *clause, PredIterInfo info)
 
static Nodearrayexpr_next_fn (PredIterInfo info)
 
static void arrayexpr_cleanup_fn (PredIterInfo info)
 
static bool predicate_implied_by_simple_clause (Expr *predicate, Node *clause, bool weak)
 
static bool predicate_refuted_by_simple_clause (Expr *predicate, Node *clause, bool weak)
 
static Nodeextract_not_arg (Node *clause)
 
static Nodeextract_strong_not_arg (Node *clause)
 
static bool clause_is_strict_for (Node *clause, Node *subexpr, bool allow_false)
 
static bool operator_predicate_proof (Expr *predicate, Node *clause, bool refute_it, bool weak)
 
static bool operator_same_subexprs_proof (Oid pred_op, Oid clause_op, bool refute_it)
 
static bool operator_same_subexprs_lookup (Oid pred_op, Oid clause_op, bool refute_it)
 
static Oid get_btree_test_op (Oid pred_op, Oid clause_op, bool refute_it)
 
static void InvalidateOprProofCacheCallBack (Datum arg, SysCacheIdentifier cacheid, uint32 hashvalue)
 
bool predicate_implied_by (List *predicate_list, List *clause_list, bool weak)
 
bool predicate_refuted_by (List *predicate_list, List *clause_list, bool weak)
 
static OprProofCacheEntrylookup_proof_cache (Oid pred_op, Oid clause_op, bool refute_it)
 

Variables

static const bool RC_implies_table [6][6]
 
static const bool RC_refutes_table [6][6]
 
static const CompareType RC_implic_table [6][6]
 
static const CompareType RC_refute_table [6][6]
 
static HTABOprProofCacheHash = NULL
 

Macro Definition Documentation

◆ iterate_begin

#define iterate_begin (   item,
  clause,
  info 
)
Value:
do { \
Node *item; \
(info).startup_fn((clause), &(info)); \
while ((item = (info).next_fn(&(info))) != NULL)
static int fb(int x)
Definition nodes.h:135

Definition at line 72 of file predtest.c.

73 { \
74 Node *item; \
75 (info).startup_fn((clause), &(info)); \
76 while ((item = (info).next_fn(&(info))) != NULL)

◆ iterate_end

#define iterate_end (   info)
Value:
(info).cleanup_fn(&(info)); \
} while (0)

Definition at line 78 of file predtest.c.

◆ MAX_SAOP_ARRAY_SIZE

#define MAX_SAOP_ARRAY_SIZE   100

Definition at line 40 of file predtest.c.

◆ none

#define none   0

Definition at line 1671 of file predtest.c.

◆ RCEQ

#define RCEQ   COMPARE_EQ

Definition at line 1665 of file predtest.c.

◆ RCGE

#define RCGE   COMPARE_GE

Definition at line 1666 of file predtest.c.

◆ RCGT

#define RCGT   COMPARE_GT

Definition at line 1667 of file predtest.c.

◆ RCLE

#define RCLE   COMPARE_LE

Definition at line 1664 of file predtest.c.

◆ RCLT

#define RCLT   COMPARE_LT

Definition at line 1663 of file predtest.c.

◆ RCNE

#define RCNE   COMPARE_NE

Definition at line 1668 of file predtest.c.

Typedef Documentation

◆ OprProofCacheEntry

◆ OprProofCacheKey

◆ PredIterInfo

Definition at line 57 of file predtest.c.

◆ PredIterInfoData

Enumeration Type Documentation

◆ PredClass

Enumerator
CLASS_ATOM 
CLASS_AND 
CLASS_OR 

Definition at line 50 of file predtest.c.

51{
52 CLASS_ATOM, /* expression that's not AND or OR */
53 CLASS_AND, /* expression with AND semantics */
54 CLASS_OR, /* expression with OR semantics */
55} PredClass;
PredClass
Definition predtest.c:51
@ CLASS_AND
Definition predtest.c:53
@ CLASS_OR
Definition predtest.c:54
@ CLASS_ATOM
Definition predtest.c:52

Function Documentation

◆ arrayconst_cleanup_fn()

static void arrayconst_cleanup_fn ( PredIterInfo  info)
static

Definition at line 1022 of file predtest.c.

1023{
1025
1026 pfree(state->elem_values);
1027 pfree(state->elem_nulls);
1028 list_free(state->opexpr.args);
1029 pfree(state);
1030}
void list_free(List *list)
Definition list.c:1546
void pfree(void *pointer)
Definition mcxt.c:1616

References list_free(), pfree(), and PredIterInfoData::state.

Referenced by predicate_classify().

◆ arrayconst_next_fn()

static Node * arrayconst_next_fn ( PredIterInfo  info)
static

Definition at line 1009 of file predtest.c.

1010{
1012
1013 if (state->next_elem >= state->num_elems)
1014 return NULL;
1015 state->const_expr.constvalue = state->elem_values[state->next_elem];
1016 state->const_expr.constisnull = state->elem_nulls[state->next_elem];
1017 state->next_elem++;
1018 return (Node *) &(state->opexpr);
1019}

References fb(), and PredIterInfoData::state.

Referenced by predicate_classify().

◆ arrayconst_startup_fn()

static void arrayconst_startup_fn ( Node clause,
PredIterInfo  info 
)
static

Definition at line 960 of file predtest.c.

961{
962 ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
966 int16 elmlen;
967 bool elmbyval;
968 char elmalign;
969
970 /* Create working state struct */
972 info->state = state;
973
974 /* Deconstruct the array literal */
975 arrayconst = (Const *) lsecond(saop->args);
978 &elmlen, &elmbyval, &elmalign);
981 elmlen, elmbyval, elmalign,
982 &state->elem_values, &state->elem_nulls,
983 &state->num_elems);
984
985 /* Set up a dummy OpExpr to return as the per-item node */
986 state->opexpr.xpr.type = T_OpExpr;
987 state->opexpr.opno = saop->opno;
988 state->opexpr.opfuncid = saop->opfuncid;
989 state->opexpr.opresulttype = BOOLOID;
990 state->opexpr.opretset = false;
991 state->opexpr.opcollid = InvalidOid;
992 state->opexpr.inputcollid = saop->inputcollid;
993 state->opexpr.args = list_copy(saop->args);
994
995 /* Set up a dummy Const node to hold the per-element values */
996 state->const_expr.xpr.type = T_Const;
997 state->const_expr.consttype = ARR_ELEMTYPE(arrayval);
998 state->const_expr.consttypmod = -1;
999 state->const_expr.constcollid = arrayconst->constcollid;
1000 state->const_expr.constlen = elmlen;
1001 state->const_expr.constbyval = elmbyval;
1002 lsecond(state->opexpr.args) = &state->const_expr;
1003
1004 /* Initialize iteration state */
1005 state->next_elem = 0;
1006}
#define DatumGetArrayTypeP(X)
Definition array.h:261
#define ARR_ELEMTYPE(a)
Definition array.h:292
void deconstruct_array(const ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
int16_t int16
Definition c.h:553
#define palloc_object(type)
Definition fe_memutils.h:74
List * list_copy(const List *oldlist)
Definition list.c:1573
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition lsyscache.c:2421
#define lsecond(l)
Definition pg_list.h:183
#define InvalidOid

References ScalarArrayOpExpr::args, ARR_ELEMTYPE, DatumGetArrayTypeP, deconstruct_array(), fb(), get_typlenbyvalalign(), InvalidOid, list_copy(), lsecond, ScalarArrayOpExpr::opno, palloc_object, and PredIterInfoData::state.

Referenced by predicate_classify().

◆ arrayexpr_cleanup_fn()

static void arrayexpr_cleanup_fn ( PredIterInfo  info)
static

Definition at line 1082 of file predtest.c.

1083{
1085
1086 list_free(state->opexpr.args);
1087 pfree(state);
1088}

References list_free(), pfree(), and PredIterInfoData::state.

Referenced by predicate_classify().

◆ arrayexpr_next_fn()

static Node * arrayexpr_next_fn ( PredIterInfo  info)
static

Definition at line 1070 of file predtest.c.

1071{
1073
1074 if (state->next == NULL)
1075 return NULL;
1076 lsecond(state->opexpr.args) = lfirst(state->next);
1077 state->next = lnext(info->state_list, state->next);
1078 return (Node *) &(state->opexpr);
1079}
#define lfirst(lc)
Definition pg_list.h:172
static ListCell * lnext(const List *l, const ListCell *c)
Definition pg_list.h:343
List * state_list
Definition predtest.c:63
struct state * next
Definition regguts.h:332

References fb(), lfirst, lnext(), lsecond, state::next, PredIterInfoData::state, and PredIterInfoData::state_list.

Referenced by predicate_classify().

◆ arrayexpr_startup_fn()

static void arrayexpr_startup_fn ( Node clause,
PredIterInfo  info 
)
static

Definition at line 1043 of file predtest.c.

1044{
1045 ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
1047 ArrayExpr *arrayexpr;
1048
1049 /* Create working state struct */
1051 info->state = state;
1052
1053 /* Set up a dummy OpExpr to return as the per-item node */
1054 state->opexpr.xpr.type = T_OpExpr;
1055 state->opexpr.opno = saop->opno;
1056 state->opexpr.opfuncid = saop->opfuncid;
1057 state->opexpr.opresulttype = BOOLOID;
1058 state->opexpr.opretset = false;
1059 state->opexpr.opcollid = InvalidOid;
1060 state->opexpr.inputcollid = saop->inputcollid;
1061 state->opexpr.args = list_copy(saop->args);
1062
1063 /* Initialize iteration variable to first member of ArrayExpr */
1064 arrayexpr = (ArrayExpr *) lsecond(saop->args);
1065 info->state_list = arrayexpr->elements;
1066 state->next = list_head(arrayexpr->elements);
1067}
static ListCell * list_head(const List *l)
Definition pg_list.h:128

References ScalarArrayOpExpr::args, fb(), InvalidOid, list_copy(), list_head(), lsecond, state::next, ScalarArrayOpExpr::opno, palloc_object, PredIterInfoData::state, and PredIterInfoData::state_list.

Referenced by predicate_classify().

◆ boolexpr_startup_fn()

static void boolexpr_startup_fn ( Node clause,
PredIterInfo  info 
)
static

Definition at line 939 of file predtest.c.

940{
941 info->state_list = ((BoolExpr *) clause)->args;
942 info->state = list_head(info->state_list);
943}

References list_head(), PredIterInfoData::state, and PredIterInfoData::state_list.

Referenced by predicate_classify().

◆ clause_is_strict_for()

static bool clause_is_strict_for ( Node clause,
Node subexpr,
bool  allow_false 
)
static

Definition at line 1461 of file predtest.c.

1462{
1463 ListCell *lc;
1464
1465 /* safety checks */
1466 if (clause == NULL || subexpr == NULL)
1467 return false;
1468
1469 /*
1470 * Look through any RelabelType nodes, so that we can match, say,
1471 * varcharcol with lower(varcharcol::text). (In general we could recurse
1472 * through any nullness-preserving, immutable operation.) We should not
1473 * see stacked RelabelTypes here.
1474 */
1475 if (IsA(clause, RelabelType))
1476 clause = (Node *) ((RelabelType *) clause)->arg;
1477 if (IsA(subexpr, RelabelType))
1478 subexpr = (Node *) ((RelabelType *) subexpr)->arg;
1479
1480 /* Base case */
1481 if (equal(clause, subexpr))
1482 return true;
1483
1484 /*
1485 * If we have a strict operator or function, a NULL result is guaranteed
1486 * if any input is forced NULL by subexpr. This is OK even if the op or
1487 * func isn't immutable, since it won't even be called on NULL input.
1488 */
1489 if (is_opclause(clause) &&
1490 op_strict(((OpExpr *) clause)->opno))
1491 {
1492 foreach(lc, ((OpExpr *) clause)->args)
1493 {
1494 if (clause_is_strict_for((Node *) lfirst(lc), subexpr, false))
1495 return true;
1496 }
1497 return false;
1498 }
1499 if (is_funcclause(clause) &&
1500 func_strict(((FuncExpr *) clause)->funcid))
1501 {
1502 foreach(lc, ((FuncExpr *) clause)->args)
1503 {
1504 if (clause_is_strict_for((Node *) lfirst(lc), subexpr, false))
1505 return true;
1506 }
1507 return false;
1508 }
1509
1510 /*
1511 * CoerceViaIO is strict (whether or not the I/O functions it calls are).
1512 * Likewise, ArrayCoerceExpr is strict for its array argument (regardless
1513 * of what the per-element expression is), ConvertRowtypeExpr is strict at
1514 * the row level, and CoerceToDomain is strict too. These are worth
1515 * checking mainly because it saves us having to explain to users why some
1516 * type coercions are known strict and others aren't.
1517 */
1518 if (IsA(clause, CoerceViaIO))
1519 return clause_is_strict_for((Node *) ((CoerceViaIO *) clause)->arg,
1520 subexpr, false);
1521 if (IsA(clause, ArrayCoerceExpr))
1522 return clause_is_strict_for((Node *) ((ArrayCoerceExpr *) clause)->arg,
1523 subexpr, false);
1524 if (IsA(clause, ConvertRowtypeExpr))
1525 return clause_is_strict_for((Node *) ((ConvertRowtypeExpr *) clause)->arg,
1526 subexpr, false);
1527 if (IsA(clause, CoerceToDomain))
1528 return clause_is_strict_for((Node *) ((CoerceToDomain *) clause)->arg,
1529 subexpr, false);
1530
1531 /*
1532 * ScalarArrayOpExpr is a special case. Note that we'd only reach here
1533 * with a ScalarArrayOpExpr clause if we failed to deconstruct it into an
1534 * AND or OR tree, as for example if it has too many array elements.
1535 */
1536 if (IsA(clause, ScalarArrayOpExpr))
1537 {
1538 ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
1539 Node *scalarnode = (Node *) linitial(saop->args);
1540 Node *arraynode = (Node *) lsecond(saop->args);
1541
1542 /*
1543 * If we can prove the scalar input to be null, and the operator is
1544 * strict, then the SAOP result has to be null --- unless the array is
1545 * empty. For an empty array, we'd get either false (for ANY) or true
1546 * (for ALL). So if allow_false = true then the proof succeeds anyway
1547 * for the ANY case; otherwise we can only make the proof if we can
1548 * prove the array non-empty.
1549 */
1551 op_strict(saop->opno))
1552 {
1553 int nelems = 0;
1554
1555 if (allow_false && saop->useOr)
1556 return true; /* can succeed even if array is empty */
1557
1558 if (arraynode && IsA(arraynode, Const))
1559 {
1562
1563 /*
1564 * If array is constant NULL then we can succeed, as in the
1565 * case below.
1566 */
1567 if (arrayconst->constisnull)
1568 return true;
1569
1570 /* Otherwise, we can compute the number of elements. */
1571 arrval = DatumGetArrayTypeP(arrayconst->constvalue);
1573 }
1574 else if (arraynode && IsA(arraynode, ArrayExpr) &&
1575 !((ArrayExpr *) arraynode)->multidims)
1576 {
1577 /*
1578 * We can also reliably count the number of array elements if
1579 * the input is a non-multidim ARRAY[] expression.
1580 */
1581 nelems = list_length(((ArrayExpr *) arraynode)->elements);
1582 }
1583
1584 /* Proof succeeds if array is definitely non-empty */
1585 if (nelems > 0)
1586 return true;
1587 }
1588
1589 /*
1590 * If we can prove the array input to be null, the proof succeeds in
1591 * all cases, since ScalarArrayOpExpr will always return NULL for a
1592 * NULL array. Otherwise, we're done here.
1593 */
1594 return clause_is_strict_for(arraynode, subexpr, false);
1595 }
1596
1597 /*
1598 * When recursing into an expression, we might find a NULL constant.
1599 * That's certainly NULL, whether it matches subexpr or not.
1600 */
1601 if (IsA(clause, Const))
1602 return ((Const *) clause)->constisnull;
1603
1604 return false;
1605}
#define ARR_NDIM(a)
Definition array.h:290
#define ARR_DIMS(a)
Definition array.h:294
int ArrayGetNItems(int ndim, const int *dims)
Definition arrayutils.c:57
Datum arg
Definition elog.c:1322
bool equal(const void *a, const void *b)
Definition equalfuncs.c:223
bool op_strict(Oid opno)
Definition lsyscache.c:1627
bool func_strict(Oid funcid)
Definition lsyscache.c:1911
static bool is_opclause(const void *clause)
Definition nodeFuncs.h:76
static bool is_funcclause(const void *clause)
Definition nodeFuncs.h:69
#define IsA(nodeptr, _type_)
Definition nodes.h:164
static int list_length(const List *l)
Definition pg_list.h:152
#define linitial(l)
Definition pg_list.h:178
static bool clause_is_strict_for(Node *clause, Node *subexpr, bool allow_false)
Definition predtest.c:1461

References arg, ScalarArrayOpExpr::args, ARR_DIMS, ARR_NDIM, ArrayGetNItems(), clause_is_strict_for(), DatumGetArrayTypeP, equal(), fb(), func_strict(), is_funcclause(), is_opclause(), IsA, lfirst, linitial, list_length(), lsecond, op_strict(), ScalarArrayOpExpr::opno, and ScalarArrayOpExpr::useOr.

Referenced by clause_is_strict_for(), predicate_implied_by_simple_clause(), and predicate_refuted_by_simple_clause().

◆ extract_not_arg()

static Node * extract_not_arg ( Node clause)
static

Definition at line 1387 of file predtest.c.

1388{
1389 if (clause == NULL)
1390 return NULL;
1391 if (IsA(clause, BoolExpr))
1392 {
1393 BoolExpr *bexpr = (BoolExpr *) clause;
1394
1395 if (bexpr->boolop == NOT_EXPR)
1396 return (Node *) linitial(bexpr->args);
1397 }
1398 else if (IsA(clause, BooleanTest))
1399 {
1400 BooleanTest *btest = (BooleanTest *) clause;
1401
1402 if (btest->booltesttype == IS_NOT_TRUE ||
1403 btest->booltesttype == IS_FALSE ||
1404 btest->booltesttype == IS_UNKNOWN)
1405 return (Node *) btest->arg;
1406 }
1407 return NULL;
1408}
@ IS_NOT_TRUE
Definition primnodes.h:2002
@ IS_UNKNOWN
Definition primnodes.h:2002
@ IS_FALSE
Definition primnodes.h:2002
@ NOT_EXPR
Definition primnodes.h:964

References fb(), IS_FALSE, IS_NOT_TRUE, IS_UNKNOWN, IsA, linitial, and NOT_EXPR.

Referenced by predicate_refuted_by_recurse().

◆ extract_strong_not_arg()

static Node * extract_strong_not_arg ( Node clause)
static

Definition at line 1415 of file predtest.c.

1416{
1417 if (clause == NULL)
1418 return NULL;
1419 if (IsA(clause, BoolExpr))
1420 {
1421 BoolExpr *bexpr = (BoolExpr *) clause;
1422
1423 if (bexpr->boolop == NOT_EXPR)
1424 return (Node *) linitial(bexpr->args);
1425 }
1426 else if (IsA(clause, BooleanTest))
1427 {
1428 BooleanTest *btest = (BooleanTest *) clause;
1429
1430 if (btest->booltesttype == IS_FALSE)
1431 return (Node *) btest->arg;
1432 }
1433 return NULL;
1434}

References fb(), IS_FALSE, IsA, linitial, and NOT_EXPR.

Referenced by predicate_refuted_by_recurse().

◆ get_btree_test_op()

static Oid get_btree_test_op ( Oid  pred_op,
Oid  clause_op,
bool  refute_it 
)
static

Definition at line 2331 of file predtest.c.

2332{
2334
2335 cache_entry = lookup_proof_cache(pred_op, clause_op, refute_it);
2336 if (refute_it)
2337 return cache_entry->refute_test_op;
2338 else
2339 return cache_entry->implic_test_op;
2340}
static OprProofCacheEntry * lookup_proof_cache(Oid pred_op, Oid clause_op, bool refute_it)
Definition predtest.c:2102

References fb(), and lookup_proof_cache().

Referenced by operator_predicate_proof().

◆ InvalidateOprProofCacheCallBack()

static void InvalidateOprProofCacheCallBack ( Datum  arg,
SysCacheIdentifier  cacheid,
uint32  hashvalue 
)
static

Definition at line 2347 of file predtest.c.

2349{
2350 HASH_SEQ_STATUS status;
2352
2354
2355 /* Currently we just reset all entries; hard to be smarter ... */
2357
2358 while ((hentry = (OprProofCacheEntry *) hash_seq_search(&status)) != NULL)
2359 {
2360 hentry->have_implic = false;
2361 hentry->have_refute = false;
2362 }
2363}
#define Assert(condition)
Definition c.h:885
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition dynahash.c:1415
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition dynahash.c:1380
static HTAB * OprProofCacheHash
Definition predtest.c:2094

References Assert, fb(), hash_seq_init(), hash_seq_search(), and OprProofCacheHash.

Referenced by lookup_proof_cache().

◆ list_cleanup_fn()

static void list_cleanup_fn ( PredIterInfo  info)
static

Definition at line 929 of file predtest.c.

930{
931 /* Nothing to clean up */
932}

Referenced by predicate_classify().

◆ list_next_fn()

static Node * list_next_fn ( PredIterInfo  info)
static

Definition at line 916 of file predtest.c.

917{
918 ListCell *l = (ListCell *) info->state;
919 Node *n;
920
921 if (l == NULL)
922 return NULL;
923 n = lfirst(l);
924 info->state = lnext(info->state_list, l);
925 return n;
926}

References fb(), lfirst, lnext(), PredIterInfoData::state, and PredIterInfoData::state_list.

Referenced by predicate_classify().

◆ list_startup_fn()

static void list_startup_fn ( Node clause,
PredIterInfo  info 
)
static

Definition at line 909 of file predtest.c.

910{
911 info->state_list = (List *) clause;
912 info->state = list_head(info->state_list);
913}
Definition pg_list.h:54

References list_head(), PredIterInfoData::state, and PredIterInfoData::state_list.

Referenced by predicate_classify().

◆ lookup_proof_cache()

static OprProofCacheEntry * lookup_proof_cache ( Oid  pred_op,
Oid  clause_op,
bool  refute_it 
)
static

Definition at line 2102 of file predtest.c.

2103{
2106 bool cfound;
2107 bool same_subexprs = false;
2109 bool found = false;
2112 ListCell *lcp,
2113 *lcc;
2114
2115 /*
2116 * Find or make a cache entry for this pair of operators.
2117 */
2118 if (OprProofCacheHash == NULL)
2119 {
2120 /* First time through: initialize the hash table */
2121 HASHCTL ctl;
2122
2123 ctl.keysize = sizeof(OprProofCacheKey);
2124 ctl.entrysize = sizeof(OprProofCacheEntry);
2125 OprProofCacheHash = hash_create("Btree proof lookup cache", 256,
2127
2128 /* Arrange to flush cache on pg_amop changes */
2131 (Datum) 0);
2132 }
2133
2134 key.pred_op = pred_op;
2135 key.clause_op = clause_op;
2137 &key,
2138 HASH_ENTER, &cfound);
2139 if (!cfound)
2140 {
2141 /* new cache entry, set it invalid */
2142 cache_entry->have_implic = false;
2143 cache_entry->have_refute = false;
2144 }
2145 else
2146 {
2147 /* pre-existing cache entry, see if we know the answer yet */
2148 if (refute_it ? cache_entry->have_refute : cache_entry->have_implic)
2150 }
2151
2152 /*
2153 * Try to find a btree opfamily containing the given operators.
2154 *
2155 * We must find a btree opfamily that contains both operators, else the
2156 * implication can't be determined. Also, the opfamily must contain a
2157 * suitable test operator taking the operators' righthand datatypes.
2158 *
2159 * If there are multiple matching opfamilies, assume we can use any one to
2160 * determine the logical relationship of the two operators and the correct
2161 * corresponding test operator. This should work for any logically
2162 * consistent opfamilies.
2163 *
2164 * Note that we can determine the operators' relationship for
2165 * same-subexprs cases even from an opfamily that lacks a usable test
2166 * operator. This can happen in cases with incomplete sets of cross-type
2167 * comparison operators.
2168 */
2170 if (clause_op_infos)
2172 else /* no point in looking */
2174
2175 foreach(lcp, pred_op_infos)
2176 {
2178 Oid opfamily_id = pred_op_info->opfamily_id;
2179
2180 foreach(lcc, clause_op_infos)
2181 {
2186
2187 /* Must find them in same opfamily */
2188 if (opfamily_id != clause_op_info->opfamily_id)
2189 continue;
2190 /* Lefttypes should match */
2191 Assert(clause_op_info->oplefttype == pred_op_info->oplefttype);
2192
2193 pred_cmptype = pred_op_info->cmptype;
2194 clause_cmptype = clause_op_info->cmptype;
2195
2196 /*
2197 * Check to see if we can make a proof for same-subexpressions
2198 * cases based on the operators' relationship in this opfamily.
2199 */
2200 if (refute_it)
2202 else
2204
2205 /*
2206 * Look up the "test" cmptype number in the implication table
2207 */
2208 if (refute_it)
2210 else
2212
2213 if (test_cmptype == 0)
2214 {
2215 /* Can't determine implication using this interpretation */
2216 continue;
2217 }
2218
2219 /*
2220 * See if opfamily has an operator for the test cmptype and the
2221 * datatypes.
2222 */
2223 if (test_cmptype == RCNE)
2224 {
2226 pred_op_info->oprighttype,
2227 clause_op_info->oprighttype,
2228 COMPARE_EQ);
2229 if (OidIsValid(test_op))
2231 }
2232 else
2233 {
2235 pred_op_info->oprighttype,
2236 clause_op_info->oprighttype,
2237 test_cmptype);
2238 }
2239
2240 if (!OidIsValid(test_op))
2241 continue;
2242
2243 /*
2244 * Last check: test_op must be immutable.
2245 *
2246 * Note that we require only the test_op to be immutable, not the
2247 * original clause_op. (pred_op is assumed to have been checked
2248 * immutable by the caller.) Essentially we are assuming that the
2249 * opfamily is consistent even if it contains operators that are
2250 * merely stable.
2251 */
2253 {
2254 found = true;
2255 break;
2256 }
2257 }
2258
2259 if (found)
2260 break;
2261 }
2262
2265
2266 if (!found)
2267 {
2268 /* couldn't find a suitable comparison operator */
2270 }
2271
2272 /*
2273 * If we think we were able to prove something about same-subexpressions
2274 * cases, check to make sure the clause_op is immutable before believing
2275 * it completely. (Usually, the clause_op would be immutable if the
2276 * pred_op is, but it's not entirely clear that this must be true in all
2277 * cases, so let's check.)
2278 */
2279 if (same_subexprs &&
2280 op_volatile(clause_op) != PROVOLATILE_IMMUTABLE)
2281 same_subexprs = false;
2282
2283 /* Cache the results, whether positive or negative */
2284 if (refute_it)
2285 {
2286 cache_entry->refute_test_op = test_op;
2287 cache_entry->same_subexprs_refutes = same_subexprs;
2288 cache_entry->have_refute = true;
2289 }
2290 else
2291 {
2292 cache_entry->implic_test_op = test_op;
2293 cache_entry->same_subexprs_implies = same_subexprs;
2294 cache_entry->have_implic = true;
2295 }
2296
2297 return cache_entry;
2298}
#define OidIsValid(objectId)
Definition c.h:800
CompareType
Definition cmptype.h:32
@ COMPARE_EQ
Definition cmptype.h:36
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:952
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:358
@ HASH_ENTER
Definition hsearch.h:114
#define HASH_ELEM
Definition hsearch.h:95
#define HASH_BLOBS
Definition hsearch.h:97
void CacheRegisterSyscacheCallback(SysCacheIdentifier cacheid, SyscacheCallbackFunction func, Datum arg)
Definition inval.c:1816
void list_free_deep(List *list)
Definition list.c:1560
Oid get_opfamily_member_for_cmptype(Oid opfamily, Oid lefttype, Oid righttype, CompareType cmptype)
Definition lsyscache.c:197
List * get_op_index_interpretation(Oid opno)
Definition lsyscache.c:666
char op_volatile(Oid opno)
Definition lsyscache.c:1643
Oid get_negator(Oid opno)
Definition lsyscache.c:1683
#define NIL
Definition pg_list.h:68
uint64_t Datum
Definition postgres.h:70
unsigned int Oid
static const CompareType RC_implic_table[6][6]
Definition predtest.c:1699
static const bool RC_refutes_table[6][6]
Definition predtest.c:1686
static const bool RC_implies_table[6][6]
Definition predtest.c:1673
#define RCNE
Definition predtest.c:1668
static void InvalidateOprProofCacheCallBack(Datum arg, SysCacheIdentifier cacheid, uint32 hashvalue)
Definition predtest.c:2347
static const CompareType RC_refute_table[6][6]
Definition predtest.c:1712
tree ctl
Definition radixtree.h:1838
Size keysize
Definition hsearch.h:75

References Assert, CacheRegisterSyscacheCallback(), COMPARE_EQ, ctl, fb(), get_negator(), get_op_index_interpretation(), get_opfamily_member_for_cmptype(), HASH_BLOBS, hash_create(), HASH_ELEM, HASH_ENTER, hash_search(), InvalidateOprProofCacheCallBack(), InvalidOid, HASHCTL::keysize, lfirst, list_free_deep(), NIL, OidIsValid, op_volatile(), OprProofCacheHash, RC_implic_table, RC_implies_table, RC_refute_table, RC_refutes_table, and RCNE.

Referenced by get_btree_test_op(), and operator_same_subexprs_lookup().

◆ operator_predicate_proof()

static bool operator_predicate_proof ( Expr predicate,
Node clause,
bool  refute_it,
bool  weak 
)
static

Definition at line 1780 of file predtest.c.

1782{
1787 Oid pred_op,
1788 clause_op,
1789 test_op;
1791 *pred_rightop,
1795 *clause_const;
1796 Expr *test_expr;
1799 bool isNull;
1800 EState *estate;
1801 MemoryContext oldcontext;
1802
1803 /*
1804 * Both expressions must be binary opclauses, else we can't do anything.
1805 *
1806 * Note: in future we might extend this logic to other operator-based
1807 * constructs such as DistinctExpr. But the planner isn't very smart
1808 * about DistinctExpr in general, and this probably isn't the first place
1809 * to fix if you want to improve that.
1810 */
1811 if (!is_opclause(predicate))
1812 return false;
1814 if (list_length(pred_opexpr->args) != 2)
1815 return false;
1816 if (!is_opclause(clause))
1817 return false;
1818 clause_opexpr = (OpExpr *) clause;
1819 if (list_length(clause_opexpr->args) != 2)
1820 return false;
1821
1822 /*
1823 * If they're marked with different collations then we can't do anything.
1824 * This is a cheap test so let's get it out of the way early.
1825 */
1826 pred_collation = pred_opexpr->inputcollid;
1827 clause_collation = clause_opexpr->inputcollid;
1829 return false;
1830
1831 /* Grab the operator OIDs now too. We may commute these below. */
1832 pred_op = pred_opexpr->opno;
1833 clause_op = clause_opexpr->opno;
1834
1835 /*
1836 * We have to match up at least one pair of input expressions.
1837 */
1838 pred_leftop = (Node *) linitial(pred_opexpr->args);
1839 pred_rightop = (Node *) lsecond(pred_opexpr->args);
1842
1844 {
1846 {
1847 /* We have x op1 y and x op2 y */
1848 return operator_same_subexprs_proof(pred_op, clause_op, refute_it);
1849 }
1850 else
1851 {
1852 /* Fail unless rightops are both Consts */
1853 if (pred_rightop == NULL || !IsA(pred_rightop, Const))
1854 return false;
1857 return false;
1859 }
1860 }
1862 {
1863 /* Fail unless leftops are both Consts */
1864 if (pred_leftop == NULL || !IsA(pred_leftop, Const))
1865 return false;
1868 return false;
1870 /* Commute both operators so we can assume Consts are on the right */
1871 pred_op = get_commutator(pred_op);
1872 if (!OidIsValid(pred_op))
1873 return false;
1874 clause_op = get_commutator(clause_op);
1875 if (!OidIsValid(clause_op))
1876 return false;
1877 }
1878 else if (equal(pred_leftop, clause_rightop))
1879 {
1881 {
1882 /* We have x op1 y and y op2 x */
1883 /* Commute pred_op that we can treat this like a straight match */
1884 pred_op = get_commutator(pred_op);
1885 if (!OidIsValid(pred_op))
1886 return false;
1887 return operator_same_subexprs_proof(pred_op, clause_op, refute_it);
1888 }
1889 else
1890 {
1891 /* Fail unless pred_rightop/clause_leftop are both Consts */
1892 if (pred_rightop == NULL || !IsA(pred_rightop, Const))
1893 return false;
1896 return false;
1898 /* Commute clause_op so we can assume Consts are on the right */
1899 clause_op = get_commutator(clause_op);
1900 if (!OidIsValid(clause_op))
1901 return false;
1902 }
1903 }
1904 else if (equal(pred_rightop, clause_leftop))
1905 {
1906 /* Fail unless pred_leftop/clause_rightop are both Consts */
1907 if (pred_leftop == NULL || !IsA(pred_leftop, Const))
1908 return false;
1911 return false;
1913 /* Commute pred_op so we can assume Consts are on the right */
1914 pred_op = get_commutator(pred_op);
1915 if (!OidIsValid(pred_op))
1916 return false;
1917 }
1918 else
1919 {
1920 /* Failed to match up any of the subexpressions, so we lose */
1921 return false;
1922 }
1923
1924 /*
1925 * We have two identical subexpressions, and two other subexpressions that
1926 * are not identical but are both Consts; and we have commuted the
1927 * operators if necessary so that the Consts are on the right. We'll need
1928 * to compare the Consts' values. If either is NULL, we can't do that, so
1929 * usually the proof fails ... but in some cases we can claim success.
1930 */
1931 if (clause_const->constisnull)
1932 {
1933 /* If clause_op isn't strict, we can't prove anything */
1934 if (!op_strict(clause_op))
1935 return false;
1936
1937 /*
1938 * At this point we know that the clause returns NULL. For proof
1939 * types that assume truth of the clause, this means the proof is
1940 * vacuously true (a/k/a "false implies anything"). That's all proof
1941 * types except weak implication.
1942 */
1943 if (!(weak && !refute_it))
1944 return true;
1945
1946 /*
1947 * For weak implication, it's still possible for the proof to succeed,
1948 * if the predicate can also be proven NULL. In that case we've got
1949 * NULL => NULL which is valid for this proof type.
1950 */
1951 if (pred_const->constisnull && op_strict(pred_op))
1952 return true;
1953 /* Else the proof fails */
1954 return false;
1955 }
1956 if (pred_const->constisnull)
1957 {
1958 /*
1959 * If the pred_op is strict, we know the predicate yields NULL, which
1960 * means the proof succeeds for either weak implication or weak
1961 * refutation.
1962 */
1963 if (weak && op_strict(pred_op))
1964 return true;
1965 /* Else the proof fails */
1966 return false;
1967 }
1968
1969 /*
1970 * Lookup the constant-comparison operator using the system catalogs and
1971 * the operator implication tables.
1972 */
1973 test_op = get_btree_test_op(pred_op, clause_op, refute_it);
1974
1975 if (!OidIsValid(test_op))
1976 {
1977 /* couldn't find a suitable comparison operator */
1978 return false;
1979 }
1980
1981 /*
1982 * Evaluate the test. For this we need an EState.
1983 */
1984 estate = CreateExecutorState();
1985
1986 /* We can use the estate's working context to avoid memory leaks. */
1987 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1988
1989 /* Build expression tree */
1991 BOOLOID,
1992 false,
1993 (Expr *) pred_const,
1994 (Expr *) clause_const,
1995 InvalidOid,
1997
1998 /* Fill in opfuncids */
2000
2001 /* Prepare it for execution */
2003
2004 /* And execute it. */
2006 GetPerTupleExprContext(estate),
2007 &isNull);
2008
2009 /* Get back to outer memory context */
2010 MemoryContextSwitchTo(oldcontext);
2011
2012 /* Release all the junk we just created */
2013 FreeExecutorState(estate);
2014
2015 if (isNull)
2016 {
2017 /* Treat a null result as non-proof ... but it's a tad fishy ... */
2018 elog(DEBUG2, "null predicate test result");
2019 return false;
2020 }
2021 return DatumGetBool(test_result);
2022}
#define DEBUG2
Definition elog.h:29
#define elog(elevel,...)
Definition elog.h:226
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition execExpr.c:143
void FreeExecutorState(EState *estate)
Definition execUtils.c:192
EState * CreateExecutorState(void)
Definition execUtils.c:88
#define GetPerTupleExprContext(estate)
Definition executor.h:656
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition executor.h:436
Oid get_commutator(Oid opno)
Definition lsyscache.c:1659
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition makefuncs.c:701
void fix_opfuncids(Node *node)
Definition nodeFuncs.c:1840
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
static bool DatumGetBool(Datum X)
Definition postgres.h:100
static bool operator_same_subexprs_proof(Oid pred_op, Oid clause_op, bool refute_it)
Definition predtest.c:2033
static Oid get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it)
Definition predtest.c:2331
MemoryContext es_query_cxt
Definition execnodes.h:713

References CreateExecutorState(), DatumGetBool(), DEBUG2, elog, equal(), EState::es_query_cxt, ExecEvalExprSwitchContext(), ExecInitExpr(), fb(), fix_opfuncids(), FreeExecutorState(), get_btree_test_op(), get_commutator(), GetPerTupleExprContext, InvalidOid, is_opclause(), IsA, linitial, list_length(), lsecond, make_opclause(), MemoryContextSwitchTo(), OidIsValid, op_strict(), and operator_same_subexprs_proof().

Referenced by predicate_implied_by_simple_clause(), and predicate_refuted_by_simple_clause().

◆ operator_same_subexprs_lookup()

static bool operator_same_subexprs_lookup ( Oid  pred_op,
Oid  clause_op,
bool  refute_it 
)
static

Definition at line 2306 of file predtest.c.

2307{
2309
2310 cache_entry = lookup_proof_cache(pred_op, clause_op, refute_it);
2311 if (refute_it)
2312 return cache_entry->same_subexprs_refutes;
2313 else
2314 return cache_entry->same_subexprs_implies;
2315}

References fb(), and lookup_proof_cache().

Referenced by operator_same_subexprs_proof().

◆ operator_same_subexprs_proof()

static bool operator_same_subexprs_proof ( Oid  pred_op,
Oid  clause_op,
bool  refute_it 
)
static

Definition at line 2033 of file predtest.c.

2034{
2035 /*
2036 * A simple and general rule is that the predicate is proven if clause_op
2037 * and pred_op are the same, or refuted if they are each other's negators.
2038 * We need not check immutability since the pred_op is already known
2039 * immutable. (Actually, by this point we may have the commutator of a
2040 * known-immutable pred_op, but that should certainly be immutable too.
2041 * Likewise we don't worry whether the pred_op's negator is immutable.)
2042 *
2043 * Note: the "same" case won't get here if we actually had EXPR1 clause_op
2044 * EXPR2 and EXPR1 pred_op EXPR2, because the overall-expression-equality
2045 * test in predicate_implied_by_simple_clause would have caught it. But
2046 * we can see the same operator after having commuted the pred_op.
2047 */
2048 if (refute_it)
2049 {
2050 if (get_negator(pred_op) == clause_op)
2051 return true;
2052 }
2053 else
2054 {
2055 if (pred_op == clause_op)
2056 return true;
2057 }
2058
2059 /*
2060 * Otherwise, see if we can determine the implication by finding the
2061 * operators' relationship via some btree opfamily.
2062 */
2063 return operator_same_subexprs_lookup(pred_op, clause_op, refute_it);
2064}
static bool operator_same_subexprs_lookup(Oid pred_op, Oid clause_op, bool refute_it)
Definition predtest.c:2306

References fb(), get_negator(), and operator_same_subexprs_lookup().

Referenced by operator_predicate_proof().

◆ predicate_classify()

static PredClass predicate_classify ( Node clause,
PredIterInfo  info 
)
static

Definition at line 827 of file predtest.c.

828{
829 /* Caller should not pass us NULL, nor a RestrictInfo clause */
830 Assert(clause != NULL);
831 Assert(!IsA(clause, RestrictInfo));
832
833 /*
834 * If we see a List, assume it's an implicit-AND list; this is the correct
835 * semantics for lists of RestrictInfo nodes.
836 */
837 if (IsA(clause, List))
838 {
840 info->next_fn = list_next_fn;
842 return CLASS_AND;
843 }
844
845 /* Handle normal AND and OR boolean clauses */
846 if (is_andclause(clause))
847 {
849 info->next_fn = list_next_fn;
851 return CLASS_AND;
852 }
853 if (is_orclause(clause))
854 {
856 info->next_fn = list_next_fn;
858 return CLASS_OR;
859 }
860
861 /* Handle ScalarArrayOpExpr */
862 if (IsA(clause, ScalarArrayOpExpr))
863 {
864 ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause;
865 Node *arraynode = (Node *) lsecond(saop->args);
866
867 /*
868 * We can break this down into an AND or OR structure, but only if we
869 * know how to iterate through expressions for the array's elements.
870 * We can do that if the array operand is a non-null constant or a
871 * simple ArrayExpr.
872 */
873 if (arraynode && IsA(arraynode, Const) &&
874 !((Const *) arraynode)->constisnull)
875 {
877 int nelems;
878
881 if (nelems <= MAX_SAOP_ARRAY_SIZE)
882 {
886 return saop->useOr ? CLASS_OR : CLASS_AND;
887 }
888 }
889 else if (arraynode && IsA(arraynode, ArrayExpr) &&
890 !((ArrayExpr *) arraynode)->multidims &&
892 {
896 return saop->useOr ? CLASS_OR : CLASS_AND;
897 }
898 }
899
900 /* None of the above, so it's an atom */
901 return CLASS_ATOM;
902}
static bool is_andclause(const void *clause)
Definition nodeFuncs.h:107
static bool is_orclause(const void *clause)
Definition nodeFuncs.h:116
static Node * arrayconst_next_fn(PredIterInfo info)
Definition predtest.c:1009
static Node * arrayexpr_next_fn(PredIterInfo info)
Definition predtest.c:1070
static void arrayexpr_startup_fn(Node *clause, PredIterInfo info)
Definition predtest.c:1043
static void boolexpr_startup_fn(Node *clause, PredIterInfo info)
Definition predtest.c:939
static void arrayconst_startup_fn(Node *clause, PredIterInfo info)
Definition predtest.c:960
#define MAX_SAOP_ARRAY_SIZE
Definition predtest.c:40
static void list_cleanup_fn(PredIterInfo info)
Definition predtest.c:929
static Node * list_next_fn(PredIterInfo info)
Definition predtest.c:916
static void arrayconst_cleanup_fn(PredIterInfo info)
Definition predtest.c:1022
static void list_startup_fn(Node *clause, PredIterInfo info)
Definition predtest.c:909
static void arrayexpr_cleanup_fn(PredIterInfo info)
Definition predtest.c:1082
void(* startup_fn)(Node *clause, PredIterInfo info)
Definition predtest.c:65
void(* cleanup_fn)(PredIterInfo info)
Definition predtest.c:69
Node *(* next_fn)(PredIterInfo info)
Definition predtest.c:67

References ScalarArrayOpExpr::args, ARR_DIMS, ARR_NDIM, arrayconst_cleanup_fn(), arrayconst_next_fn(), arrayconst_startup_fn(), arrayexpr_cleanup_fn(), arrayexpr_next_fn(), arrayexpr_startup_fn(), ArrayGetNItems(), Assert, boolexpr_startup_fn(), CLASS_AND, CLASS_ATOM, CLASS_OR, PredIterInfoData::cleanup_fn, DatumGetArrayTypeP, fb(), is_andclause(), is_orclause(), IsA, list_cleanup_fn(), list_length(), list_next_fn(), list_startup_fn(), lsecond, MAX_SAOP_ARRAY_SIZE, PredIterInfoData::next_fn, PredIterInfoData::startup_fn, and ScalarArrayOpExpr::useOr.

Referenced by predicate_implied_by_recurse(), and predicate_refuted_by_recurse().

◆ predicate_implied_by()

bool predicate_implied_by ( List predicate_list,
List clause_list,
bool  weak 
)

Definition at line 153 of file predtest.c.

155{
156 Node *p,
157 *c;
158
159 if (predicate_list == NIL)
160 return true; /* no predicate: implication is vacuous */
161 if (clause_list == NIL)
162 return false; /* no restriction: implication must fail */
163
164 /*
165 * If either input is a single-element list, replace it with its lone
166 * member; this avoids one useless level of AND-recursion. We only need
167 * to worry about this at top level, since eval_const_expressions should
168 * have gotten rid of any trivial ANDs or ORs below that.
169 */
170 if (list_length(predicate_list) == 1)
172 else
173 p = (Node *) predicate_list;
174 if (list_length(clause_list) == 1)
175 c = (Node *) linitial(clause_list);
176 else
177 c = (Node *) clause_list;
178
179 /* And away we go ... */
181}
static bool predicate_implied_by_recurse(Node *clause, Node *predicate, bool weak)
Definition predtest.c:291
char * c

References fb(), linitial, list_length(), NIL, and predicate_implied_by_recurse().

Referenced by add_predicate_to_index_quals(), build_paths_for_OR(), check_index_predicates(), choose_bitmap_and(), ConstraintImpliedByRelConstraint(), create_bitmap_scan_plan(), create_bitmap_subplan(), create_indexscan_plan(), infer_arbiter_indexes(), and test_predtest().

◆ predicate_implied_by_recurse()

static bool predicate_implied_by_recurse ( Node clause,
Node predicate,
bool  weak 
)
static

Definition at line 291 of file predtest.c.

293{
297 bool result;
298
299 /* skip through RestrictInfo */
300 Assert(clause != NULL);
301 if (IsA(clause, RestrictInfo))
302 clause = (Node *) ((RestrictInfo *) clause)->clause;
303
305
306 switch (predicate_classify(clause, &clause_info))
307 {
308 case CLASS_AND:
309 switch (pclass)
310 {
311 case CLASS_AND:
312
313 /*
314 * AND-clause => AND-clause if A implies each of B's items
315 */
316 result = true;
318 {
320 weak))
321 {
322 result = false;
323 break;
324 }
325 }
327 return result;
328
329 case CLASS_OR:
330
331 /*
332 * AND-clause => OR-clause if A implies any of B's items
333 *
334 * Needed to handle (x AND y) => ((x AND y) OR z)
335 */
336 result = false;
338 {
340 weak))
341 {
342 result = true;
343 break;
344 }
345 }
347 if (result)
348 return result;
349
350 /*
351 * Also check if any of A's items implies B
352 *
353 * Needed to handle ((x OR y) AND z) => (x OR y)
354 */
356 {
358 weak))
359 {
360 result = true;
361 break;
362 }
363 }
365 return result;
366
367 case CLASS_ATOM:
368
369 /*
370 * AND-clause => atom if any of A's items implies B
371 */
372 result = false;
374 {
376 weak))
377 {
378 result = true;
379 break;
380 }
381 }
383 return result;
384 }
385 break;
386
387 case CLASS_OR:
388 switch (pclass)
389 {
390 case CLASS_OR:
391
392 /*
393 * OR-clause => OR-clause if each of A's items implies any
394 * of B's items. Messy but can't do it any more simply.
395 */
396 result = true;
398 {
399 bool presult = false;
400
402 {
404 weak))
405 {
406 presult = true;
407 break;
408 }
409 }
411 if (!presult)
412 {
413 result = false; /* doesn't imply any of B's */
414 break;
415 }
416 }
418 return result;
419
420 case CLASS_AND:
421 case CLASS_ATOM:
422
423 /*
424 * OR-clause => AND-clause if each of A's items implies B
425 *
426 * OR-clause => atom if each of A's items implies B
427 */
428 result = true;
430 {
432 weak))
433 {
434 result = false;
435 break;
436 }
437 }
439 return result;
440 }
441 break;
442
443 case CLASS_ATOM:
444 switch (pclass)
445 {
446 case CLASS_AND:
447
448 /*
449 * atom => AND-clause if A implies each of B's items
450 */
451 result = true;
453 {
455 weak))
456 {
457 result = false;
458 break;
459 }
460 }
462 return result;
463
464 case CLASS_OR:
465
466 /*
467 * atom => OR-clause if A implies any of B's items
468 */
469 result = false;
471 {
473 weak))
474 {
475 result = true;
476 break;
477 }
478 }
480 return result;
481
482 case CLASS_ATOM:
483
484 /*
485 * atom => atom is the base case
486 */
487 return
489 clause,
490 weak);
491 }
492 break;
493 }
494
495 /* can't get here */
496 elog(ERROR, "predicate_classify returned a bogus value");
497 return false;
498}
#define ERROR
Definition elog.h:39
#define iterate_end(info)
Definition predtest.c:78
static bool predicate_implied_by_simple_clause(Expr *predicate, Node *clause, bool weak)
Definition predtest.c:1099
static PredClass predicate_classify(Node *clause, PredIterInfo info)
Definition predtest.c:827
#define iterate_begin(item, clause, info)
Definition predtest.c:72

References Assert, CLASS_AND, CLASS_ATOM, CLASS_OR, elog, ERROR, fb(), IsA, iterate_begin, iterate_end, predicate_classify(), predicate_implied_by_recurse(), and predicate_implied_by_simple_clause().

Referenced by predicate_implied_by(), predicate_implied_by_recurse(), and predicate_refuted_by_recurse().

◆ predicate_implied_by_simple_clause()

static bool predicate_implied_by_simple_clause ( Expr predicate,
Node clause,
bool  weak 
)
static

Definition at line 1099 of file predtest.c.

1101{
1102 /* Allow interrupting long proof attempts */
1104
1105 /*
1106 * A simple and general rule is that a clause implies itself, hence we
1107 * check if they are equal(); this works for any kind of expression, and
1108 * for either implication definition. (Actually, there is an implied
1109 * assumption that the functions in the expression are immutable --- but
1110 * this was checked for the predicate by the caller.)
1111 */
1112 if (equal((Node *) predicate, clause))
1113 return true;
1114
1115 /* Next we have some clause-type-specific strategies */
1116 switch (nodeTag(clause))
1117 {
1118 case T_OpExpr:
1119 {
1120 OpExpr *op = (OpExpr *) clause;
1121
1122 /*----------
1123 * For boolean x, "x = TRUE" is equivalent to "x", likewise
1124 * "x = FALSE" is equivalent to "NOT x". These can be worth
1125 * checking because, while we preferentially simplify boolean
1126 * comparisons down to "x" and "NOT x", the other form has to
1127 * be dealt with anyway in the context of index conditions.
1128 *
1129 * We could likewise check whether the predicate is boolean
1130 * equality to a constant; but there are no known use-cases
1131 * for that at the moment, assuming that the predicate has
1132 * been through constant-folding.
1133 *----------
1134 */
1135 if (op->opno == BooleanEqualOperator)
1136 {
1137 Node *rightop;
1138
1139 Assert(list_length(op->args) == 2);
1140 rightop = lsecond(op->args);
1141 /* We might never see null Consts here, but better check */
1142 if (rightop && IsA(rightop, Const) &&
1143 !((Const *) rightop)->constisnull)
1144 {
1145 Node *leftop = linitial(op->args);
1146
1148 {
1149 /* X = true implies X */
1150 if (equal(predicate, leftop))
1151 return true;
1152 }
1153 else
1154 {
1155 /* X = false implies NOT X */
1156 if (is_notclause(predicate) &&
1158 return true;
1159 }
1160 }
1161 }
1162 }
1163 break;
1164 default:
1165 break;
1166 }
1167
1168 /* ... and some predicate-type-specific ones */
1169 switch (nodeTag(predicate))
1170 {
1171 case T_NullTest:
1172 {
1174
1175 switch (predntest->nulltesttype)
1176 {
1177 case IS_NOT_NULL:
1178
1179 /*
1180 * If the predicate is of the form "foo IS NOT NULL",
1181 * and we are considering strong implication, we can
1182 * conclude that the predicate is implied if the
1183 * clause is strict for "foo", i.e., it must yield
1184 * false or NULL when "foo" is NULL. In that case
1185 * truth of the clause ensures that "foo" isn't NULL.
1186 * (Again, this is a safe conclusion because "foo"
1187 * must be immutable.) This doesn't work for weak
1188 * implication, though. Also, "row IS NOT NULL" does
1189 * not act in the simple way we have in mind.
1190 */
1191 if (!weak &&
1192 !predntest->argisrow &&
1193 clause_is_strict_for(clause,
1194 (Node *) predntest->arg,
1195 true))
1196 return true;
1197 break;
1198 case IS_NULL:
1199 break;
1200 }
1201 }
1202 break;
1203 default:
1204 break;
1205 }
1206
1207 /*
1208 * Finally, if both clauses are binary operator expressions, we may be
1209 * able to prove something using the system's knowledge about operators;
1210 * those proof rules are encapsulated in operator_predicate_proof().
1211 */
1212 return operator_predicate_proof(predicate, clause, false, weak);
1213}
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
static bool is_notclause(const void *clause)
Definition nodeFuncs.h:125
static Expr * get_notclausearg(const void *notclause)
Definition nodeFuncs.h:134
#define nodeTag(nodeptr)
Definition nodes.h:139
static bool operator_predicate_proof(Expr *predicate, Node *clause, bool refute_it, bool weak)
Definition predtest.c:1780
@ IS_NULL
Definition primnodes.h:1978
@ IS_NOT_NULL
Definition primnodes.h:1978
Oid opno
Definition primnodes.h:851
List * args
Definition primnodes.h:869

References OpExpr::args, Assert, CHECK_FOR_INTERRUPTS, clause_is_strict_for(), DatumGetBool(), equal(), fb(), get_notclausearg(), IS_NOT_NULL, is_notclause(), IS_NULL, IsA, linitial, list_length(), lsecond, nodeTag, operator_predicate_proof(), and OpExpr::opno.

Referenced by predicate_implied_by_recurse().

◆ predicate_refuted_by()

bool predicate_refuted_by ( List predicate_list,
List clause_list,
bool  weak 
)

Definition at line 223 of file predtest.c.

225{
226 Node *p,
227 *c;
228
229 if (predicate_list == NIL)
230 return false; /* no predicate: no refutation is possible */
231 if (clause_list == NIL)
232 return false; /* no restriction: refutation must fail */
233
234 /*
235 * If either input is a single-element list, replace it with its lone
236 * member; this avoids one useless level of AND-recursion. We only need
237 * to worry about this at top level, since eval_const_expressions should
238 * have gotten rid of any trivial ANDs or ORs below that.
239 */
240 if (list_length(predicate_list) == 1)
242 else
243 p = (Node *) predicate_list;
244 if (list_length(clause_list) == 1)
245 c = (Node *) linitial(clause_list);
246 else
247 c = (Node *) clause_list;
248
249 /* And away we go ... */
251}
static bool predicate_refuted_by_recurse(Node *clause, Node *predicate, bool weak)
Definition predtest.c:532

References fb(), linitial, list_length(), NIL, and predicate_refuted_by_recurse().

Referenced by gen_partprune_steps_internal(), relation_excluded_by_constraints(), and test_predtest().

◆ predicate_refuted_by_recurse()

static bool predicate_refuted_by_recurse ( Node clause,
Node predicate,
bool  weak 
)
static

Definition at line 532 of file predtest.c.

534{
538 Node *not_arg;
539 bool result;
540
541 /* skip through RestrictInfo */
542 Assert(clause != NULL);
543 if (IsA(clause, RestrictInfo))
544 clause = (Node *) ((RestrictInfo *) clause)->clause;
545
547
548 switch (predicate_classify(clause, &clause_info))
549 {
550 case CLASS_AND:
551 switch (pclass)
552 {
553 case CLASS_AND:
554
555 /*
556 * AND-clause R=> AND-clause if A refutes any of B's items
557 *
558 * Needed to handle (x AND y) R=> ((!x OR !y) AND z)
559 */
560 result = false;
562 {
564 weak))
565 {
566 result = true;
567 break;
568 }
569 }
571 if (result)
572 return result;
573
574 /*
575 * Also check if any of A's items refutes B
576 *
577 * Needed to handle ((x OR y) AND z) R=> (!x AND !y)
578 */
580 {
582 weak))
583 {
584 result = true;
585 break;
586 }
587 }
589 return result;
590
591 case CLASS_OR:
592
593 /*
594 * AND-clause R=> OR-clause if A refutes each of B's items
595 */
596 result = true;
598 {
600 weak))
601 {
602 result = false;
603 break;
604 }
605 }
607 return result;
608
609 case CLASS_ATOM:
610
611 /*
612 * If B is a NOT-type clause, A R=> B if A => B's arg
613 *
614 * Since, for either type of refutation, we are starting
615 * with the premise that A is true, we can use a strong
616 * implication test in all cases. That proves B's arg is
617 * true, which is more than we need for weak refutation if
618 * B is a simple NOT, but it allows not worrying about
619 * exactly which kind of negation clause we have.
620 */
622 if (not_arg &&
624 false))
625 return true;
626
627 /*
628 * AND-clause R=> atom if any of A's items refutes B
629 */
630 result = false;
632 {
634 weak))
635 {
636 result = true;
637 break;
638 }
639 }
641 return result;
642 }
643 break;
644
645 case CLASS_OR:
646 switch (pclass)
647 {
648 case CLASS_OR:
649
650 /*
651 * OR-clause R=> OR-clause if A refutes each of B's items
652 */
653 result = true;
655 {
657 weak))
658 {
659 result = false;
660 break;
661 }
662 }
664 return result;
665
666 case CLASS_AND:
667
668 /*
669 * OR-clause R=> AND-clause if each of A's items refutes
670 * any of B's items.
671 */
672 result = true;
674 {
675 bool presult = false;
676
678 {
680 weak))
681 {
682 presult = true;
683 break;
684 }
685 }
687 if (!presult)
688 {
689 result = false; /* citem refutes nothing */
690 break;
691 }
692 }
694 return result;
695
696 case CLASS_ATOM:
697
698 /*
699 * If B is a NOT-type clause, A R=> B if A => B's arg
700 *
701 * Same logic as for the AND-clause case above.
702 */
704 if (not_arg &&
706 false))
707 return true;
708
709 /*
710 * OR-clause R=> atom if each of A's items refutes B
711 */
712 result = true;
714 {
716 weak))
717 {
718 result = false;
719 break;
720 }
721 }
723 return result;
724 }
725 break;
726
727 case CLASS_ATOM:
728
729 /*
730 * If A is a strong NOT-clause, A R=> B if B => A's arg
731 *
732 * Since A is strong, we may assume A's arg is false (not just
733 * not-true). If B weakly implies A's arg, then B can be neither
734 * true nor null, so that strong refutation is proven. If B
735 * strongly implies A's arg, then B cannot be true, so that weak
736 * refutation is proven.
737 */
739 if (not_arg &&
741 !weak))
742 return true;
743
744 switch (pclass)
745 {
746 case CLASS_AND:
747
748 /*
749 * atom R=> AND-clause if A refutes any of B's items
750 */
751 result = false;
753 {
755 weak))
756 {
757 result = true;
758 break;
759 }
760 }
762 return result;
763
764 case CLASS_OR:
765
766 /*
767 * atom R=> OR-clause if A refutes each of B's items
768 */
769 result = true;
771 {
773 weak))
774 {
775 result = false;
776 break;
777 }
778 }
780 return result;
781
782 case CLASS_ATOM:
783
784 /*
785 * If B is a NOT-type clause, A R=> B if A => B's arg
786 *
787 * Same logic as for the AND-clause case above.
788 */
790 if (not_arg &&
792 false))
793 return true;
794
795 /*
796 * atom R=> atom is the base case
797 */
798 return
800 clause,
801 weak);
802 }
803 break;
804 }
805
806 /* can't get here */
807 elog(ERROR, "predicate_classify returned a bogus value");
808 return false;
809}
static bool predicate_refuted_by_simple_clause(Expr *predicate, Node *clause, bool weak)
Definition predtest.c:1226
static Node * extract_strong_not_arg(Node *clause)
Definition predtest.c:1415
static Node * extract_not_arg(Node *clause)
Definition predtest.c:1387

References Assert, CLASS_AND, CLASS_ATOM, CLASS_OR, elog, ERROR, extract_not_arg(), extract_strong_not_arg(), fb(), IsA, iterate_begin, iterate_end, predicate_classify(), predicate_implied_by_recurse(), predicate_refuted_by_recurse(), and predicate_refuted_by_simple_clause().

Referenced by predicate_refuted_by(), and predicate_refuted_by_recurse().

◆ predicate_refuted_by_simple_clause()

static bool predicate_refuted_by_simple_clause ( Expr predicate,
Node clause,
bool  weak 
)
static

Definition at line 1226 of file predtest.c.

1228{
1229 /* Allow interrupting long proof attempts */
1231
1232 /*
1233 * A simple clause can't refute itself, so unlike the implication case,
1234 * checking for equal() clauses isn't helpful.
1235 *
1236 * But relation_excluded_by_constraints() checks for self-contradictions
1237 * in a list of clauses, so that we may get here with predicate and clause
1238 * being actually pointer-equal, and that is worth eliminating quickly.
1239 */
1240 if ((Node *) predicate == clause)
1241 return false;
1242
1243 /* Next we have some clause-type-specific strategies */
1244 switch (nodeTag(clause))
1245 {
1246 case T_NullTest:
1247 {
1248 NullTest *clausentest = (NullTest *) clause;
1249
1250 /* row IS NULL does not act in the simple way we have in mind */
1251 if (clausentest->argisrow)
1252 return false;
1253
1254 switch (clausentest->nulltesttype)
1255 {
1256 case IS_NULL:
1257 {
1258 switch (nodeTag(predicate))
1259 {
1260 case T_NullTest:
1261 {
1263
1264 /*
1265 * row IS NULL does not act in the
1266 * simple way we have in mind
1267 */
1268 if (predntest->argisrow)
1269 return false;
1270
1271 /*
1272 * foo IS NULL refutes foo IS NOT
1273 * NULL, at least in the non-row case,
1274 * for both strong and weak refutation
1275 */
1276 if (predntest->nulltesttype == IS_NOT_NULL &&
1277 equal(predntest->arg, clausentest->arg))
1278 return true;
1279 }
1280 break;
1281 default:
1282 break;
1283 }
1284
1285 /*
1286 * foo IS NULL weakly refutes any predicate that
1287 * is strict for foo, since then the predicate
1288 * must yield false or NULL (and since foo appears
1289 * in the predicate, it's known immutable).
1290 */
1291 if (weak &&
1293 (Node *) clausentest->arg,
1294 true))
1295 return true;
1296
1297 return false; /* we can't succeed below... */
1298 }
1299 break;
1300 case IS_NOT_NULL:
1301 break;
1302 }
1303 }
1304 break;
1305 default:
1306 break;
1307 }
1308
1309 /* ... and some predicate-type-specific ones */
1310 switch (nodeTag(predicate))
1311 {
1312 case T_NullTest:
1313 {
1315
1316 /* row IS NULL does not act in the simple way we have in mind */
1317 if (predntest->argisrow)
1318 return false;
1319
1320 switch (predntest->nulltesttype)
1321 {
1322 case IS_NULL:
1323 {
1324 switch (nodeTag(clause))
1325 {
1326 case T_NullTest:
1327 {
1328 NullTest *clausentest = (NullTest *) clause;
1329
1330 /*
1331 * row IS NULL does not act in the
1332 * simple way we have in mind
1333 */
1334 if (clausentest->argisrow)
1335 return false;
1336
1337 /*
1338 * foo IS NOT NULL refutes foo IS NULL
1339 * for both strong and weak refutation
1340 */
1341 if (clausentest->nulltesttype == IS_NOT_NULL &&
1342 equal(clausentest->arg, predntest->arg))
1343 return true;
1344 }
1345 break;
1346 default:
1347 break;
1348 }
1349
1350 /*
1351 * When the predicate is of the form "foo IS
1352 * NULL", we can conclude that the predicate is
1353 * refuted if the clause is strict for "foo" (see
1354 * notes for implication case). That works for
1355 * either strong or weak refutation.
1356 */
1357 if (clause_is_strict_for(clause,
1358 (Node *) predntest->arg,
1359 true))
1360 return true;
1361 }
1362 break;
1363 case IS_NOT_NULL:
1364 break;
1365 }
1366
1367 return false; /* we can't succeed below... */
1368 }
1369 break;
1370 default:
1371 break;
1372 }
1373
1374 /*
1375 * Finally, if both clauses are binary operator expressions, we may be
1376 * able to prove something using the system's knowledge about operators.
1377 */
1378 return operator_predicate_proof(predicate, clause, true, weak);
1379}

References CHECK_FOR_INTERRUPTS, clause_is_strict_for(), equal(), fb(), IS_NOT_NULL, IS_NULL, nodeTag, and operator_predicate_proof().

Referenced by predicate_refuted_by_recurse().

Variable Documentation

◆ OprProofCacheHash

HTAB* OprProofCacheHash = NULL
static

Definition at line 2094 of file predtest.c.

Referenced by InvalidateOprProofCacheCallBack(), and lookup_proof_cache().

◆ RC_implic_table

const CompareType RC_implic_table[6][6]
static
Initial value:
= {
}
#define RCGE
Definition predtest.c:1666
#define RCLE
Definition predtest.c:1664
#define none
Definition predtest.c:1671
#define RCGT
Definition predtest.c:1667
#define RCLT
Definition predtest.c:1663
#define RCEQ
Definition predtest.c:1665

Definition at line 1699 of file predtest.c.

1699 {
1700/*
1701 * The predicate operator:
1702 * LT LE EQ GE GT NE
1703 */
1704 {RCGE, RCGE, none, none, none, RCGE}, /* LT */
1705 {RCGT, RCGE, none, none, none, RCGT}, /* LE */
1706 {RCGT, RCGE, RCEQ, RCLE, RCLT, RCNE}, /* EQ */
1707 {none, none, none, RCLE, RCLT, RCLT}, /* GE */
1708 {none, none, none, RCLE, RCLE, RCLE}, /* GT */
1709 {none, none, none, none, none, RCEQ} /* NE */
1710};

Referenced by lookup_proof_cache().

◆ RC_implies_table

const bool RC_implies_table[6][6]
static
Initial value:
= {
{true, true, none, none, none, true},
{none, true, none, none, none, none},
{none, true, true, true, none, none},
{none, none, none, true, none, none},
{none, none, none, true, true, true},
{none, none, none, none, none, true}
}

Definition at line 1673 of file predtest.c.

1673 {
1674/*
1675 * The predicate operator:
1676 * LT LE EQ GE GT NE
1677 */
1678 {true, true, none, none, none, true}, /* LT */
1679 {none, true, none, none, none, none}, /* LE */
1680 {none, true, true, true, none, none}, /* EQ */
1681 {none, none, none, true, none, none}, /* GE */
1682 {none, none, none, true, true, true}, /* GT */
1683 {none, none, none, none, none, true} /* NE */
1684};

Referenced by lookup_proof_cache().

◆ RC_refute_table

const CompareType RC_refute_table[6][6]
static
Initial value:

Definition at line 1712 of file predtest.c.

1712 {
1713/*
1714 * The predicate operator:
1715 * LT LE EQ GE GT NE
1716 */
1717 {none, none, RCGE, RCGE, RCGE, none}, /* LT */
1718 {none, none, RCGT, RCGT, RCGE, none}, /* LE */
1719 {RCLE, RCLT, RCNE, RCGT, RCGE, RCEQ}, /* EQ */
1720 {RCLE, RCLT, RCLT, none, none, none}, /* GE */
1721 {RCLE, RCLE, RCLE, none, none, none}, /* GT */
1722 {none, none, RCEQ, none, none, none} /* NE */
1723};

Referenced by lookup_proof_cache().

◆ RC_refutes_table

const bool RC_refutes_table[6][6]
static
Initial value:
= {
{none, none, true, true, true, none},
{none, none, none, none, true, none},
{true, none, none, none, true, true},
{true, none, none, none, none, none},
{true, true, true, none, none, none},
{none, none, true, none, none, none}
}

Definition at line 1686 of file predtest.c.

1686 {
1687/*
1688 * The predicate operator:
1689 * LT LE EQ GE GT NE
1690 */
1691 {none, none, true, true, true, none}, /* LT */
1692 {none, none, none, none, true, none}, /* LE */
1693 {true, none, none, none, true, true}, /* EQ */
1694 {true, none, none, none, none, none}, /* GE */
1695 {true, true, true, none, none, none}, /* GT */
1696 {none, none, true, none, none, none} /* NE */
1697};

Referenced by lookup_proof_cache().