diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index ac945ca4d1..d8e1282e12 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -6304,63 +6304,6 @@ SELECT * FROM parent WHERE key = 2400; - - or_to_any_transform_limit (boolean) - - or_to_any_transform_limit configuration parameter - - - - - Sets the minimum length of arguments in an OR - expression exceeding which planner will try to lookup and group - multiple similar OR expressions to - ANY () - expressions. The grouping technique of this transformation is based - on the equivalence of variable sides. One side of such an expression - must be a constant clause, and the other must contain a variable - clause. The default value is 5. The value of - -1 completely disables the transformation. - - - The advantage of this OR-to-ANY transformation is - faster query planning and execution. In certain cases, this - transformation also leads to more effective plans containing - a single index scan instead of multiple bitmap scans. However, it - may also cause a planning regression when distinct - OR arguments are better to match to distinct indexes. - This may happen when they have different matching partial indexes or - have different distributions of other columns used in the query. - Generally, more groupable OR arguments mean that - transformation will be more likely to win than to lose. - - - For example, this query has its set of five OR - expressions transformed to ANY with the default - value of or_to_any_transform_limit. But not with - the increased value. - -# EXPLAIN SELECT * FROM tbl WHERE key = 1 OR key = 2 OR key = 3 OR key = 4 OR key = 5; - QUERY PLAN ------------------------------------------------------ - Seq Scan on tbl (cost=0.00..51.44 rows=64 width=4) - Filter: (key = ANY ('{1,2,3,4,5}'::integer[])) -(2 rows) - -# SET or_to_any_transform_limit = 6; -SET - -# EXPLAIN SELECT * FROM tbl WHERE key = 1 OR key = 2 OR key = 3 OR key = 4 OR key = 5; - QUERY PLAN ---------------------------------------------------------------------------- - Seq Scan on tbl (cost=0.00..67.38 rows=63 width=4) - Filter: ((key = 1) OR (key = 2) OR (key = 3) OR (key = 4) OR (key = 5)) -(2 rows) - - - - - plan_cache_mode (enum) diff --git a/src/backend/nodes/queryjumblefuncs.c b/src/backend/nodes/queryjumblefuncs.c index de29d51c63..be823a7f8f 100644 --- a/src/backend/nodes/queryjumblefuncs.c +++ b/src/backend/nodes/queryjumblefuncs.c @@ -141,33 +141,6 @@ JumbleQuery(Query *query) return jstate; } -JumbleState * -JumbleExpr(Expr *expr, uint64 *exprId) -{ - JumbleState *jstate = NULL; - - Assert(exprId != NULL); - - jstate = (JumbleState *) palloc(sizeof(JumbleState)); - - /* Set up workspace for query jumbling */ - jstate->jumble = (unsigned char *) palloc(JUMBLE_SIZE); - jstate->jumble_len = 0; - jstate->clocations_buf_size = 32; - jstate->clocations = (LocationLen *) - palloc(jstate->clocations_buf_size * sizeof(LocationLen)); - jstate->clocations_count = 0; - jstate->highest_extern_param_id = 0; - - /* Compute query ID */ - _jumbleNode(jstate, (Node *) expr); - *exprId = DatumGetUInt64(hash_any_extended(jstate->jumble, - jstate->jumble_len, - 0)); - - return jstate; -} - /* * Enables query identifier computation. * diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c index f1a1bac3d4..cbcf83f847 100644 --- a/src/backend/optimizer/prep/prepqual.c +++ b/src/backend/optimizer/prep/prepqual.c @@ -31,25 +31,16 @@ #include "postgres.h" -#include "catalog/namespace.h" -#include "catalog/pg_operator.h" -#include "common/hashfn.h" #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" -#include "nodes/queryjumble.h" #include "optimizer/optimizer.h" -#include "parser/parse_coerce.h" -#include "parser/parse_oper.h" #include "utils/lsyscache.h" -#include "utils/syscache.h" -int or_to_any_transform_limit = 5; static List *pull_ands(List *andlist); static List *pull_ors(List *orlist); static Expr *find_duplicate_ors(Expr *qual, bool is_check); static Expr *process_duplicate_ors(List *orlist); -static List *transform_or_to_any(List *orlist); /* @@ -275,376 +266,6 @@ negate_clause(Node *node) return (Node *) make_notclause((Expr *) node); } -/* - * The key for grouping similar operator expressions in transform_or_to_any(). - */ -typedef struct OrClauseGroupKey -{ - /* We need this to put this structure into list together with other nodes */ - NodeTag type; - - /* The expression of the variable side of operator */ - Expr *expr; - /* The operator of the operator expression */ - Oid opno; - /* The collation of the operator expression */ - Oid inputcollid; - /* The type of constant side of operator */ - Oid consttype; -} OrClauseGroupKey; - -/* - * The group of similar operator expressions in transform_or_to_any(). - */ -typedef struct OrClauseGroupEntry -{ - OrClauseGroupKey key; - - /* The list of constant sides of operators */ - List *consts; - - /* - * List of source expressions. We need this for convenience in case we - * will give up on transformation. - */ - List *exprs; -} OrClauseGroupEntry; - -/* - * The hash function for OrClauseGroupKey. - */ -static uint32 -orclause_hash(const void *data, Size keysize) -{ - OrClauseGroupKey *key = (OrClauseGroupKey *) data; - uint64 exprHash; - - Assert(keysize == sizeof(OrClauseGroupKey)); - Assert(IsA(data, Invalid)); - - (void) JumbleExpr(key->expr, &exprHash); - - return hash_combine((uint32) exprHash, - hash_combine((uint32) key->opno, - hash_combine((uint32) key->consttype, - (uint32) key->inputcollid))); -} - -/* - * The copy function for OrClauseGroupKey. - */ -static void * -orclause_keycopy(void *dest, const void *src, Size keysize) -{ - OrClauseGroupKey *src_key = (OrClauseGroupKey *) src; - OrClauseGroupKey *dst_key = (OrClauseGroupKey *) dest; - - Assert(sizeof(OrClauseGroupKey) == keysize); - Assert(IsA(src, Invalid)); - - dst_key->type = T_Invalid; - dst_key->expr = src_key->expr; - dst_key->opno = src_key->opno; - dst_key->consttype = src_key->consttype; - dst_key->inputcollid = src_key->inputcollid; - - return dst_key; -} - -/* - * The equality function for OrClauseGroupKey. - */ -static int -orclause_match(const void *data1, const void *data2, Size keysize) -{ - OrClauseGroupKey *key1 = (OrClauseGroupKey *) data1; - OrClauseGroupKey *key2 = (OrClauseGroupKey *) data2; - - Assert(sizeof(OrClauseGroupKey) == keysize); - Assert(IsA(key1, Invalid)); - Assert(IsA(key2, Invalid)); - - if (key1->opno == key2->opno && - key1->consttype == key2->consttype && - key1->inputcollid == key2->inputcollid && - equal(key1->expr, key2->expr)) - return 0; - - return 1; -} - -/* - * transform_or_to_any - - * Discover the args of an OR expression and try to group similar OR - * expressions to SAOP expressions. - * - * This transformation groups two-sided equality expression. One side of - * such an expression must be a plain constant or constant expression. The - * other side must be a variable expression without volatile functions. - * To group quals, opno, inputcollid of variable expression, and type of - * constant expression must be equal too. - * - * The grouping technique is based on the equivalence of variable sides of - * the expression: using exprId and equal() routine, it groups constant sides - * of similar clauses into an array. After the grouping procedure, each - * couple ('variable expression' and 'constant array') forms a new SAOP - * operation, which is added to the args list of the returning expression. - */ -static List * -transform_or_to_any(List *orlist) -{ - List *neworlist = NIL; - List *entries = NIL; - ListCell *lc; - HASHCTL info; - HTAB *or_group_htab = NULL; - int len_ors = list_length(orlist); - OrClauseGroupEntry *entry = NULL; - - Assert(or_to_any_transform_limit >= 0 && - len_ors >= or_to_any_transform_limit); - - MemSet(&info, 0, sizeof(info)); - info.keysize = sizeof(OrClauseGroupKey); - info.entrysize = sizeof(OrClauseGroupEntry); - info.hash = orclause_hash; - info.keycopy = orclause_keycopy; - info.match = orclause_match; - or_group_htab = hash_create("OR Groups", - len_ors, - &info, - HASH_ELEM | HASH_FUNCTION | HASH_COMPARE | HASH_KEYCOPY); - - foreach(lc, orlist) - { - Node *orqual = lfirst(lc); - Node *const_expr; - Node *nconst_expr; - OrClauseGroupKey hashkey; - bool found; - Oid opno; - Oid consttype; - Node *leftop, - *rightop; - - if (!IsA(orqual, OpExpr)) - { - entries = lappend(entries, orqual); - continue; - } - - opno = ((OpExpr *) orqual)->opno; - if (get_op_rettype(opno) != BOOLOID) - { - /* Only operator returning boolean suits OR -> ANY transformation */ - entries = lappend(entries, orqual); - continue; - } - - /* - * Detect the constant side of the clause. Recall non-constant - * expression can be made not only with Vars, but also with Params, - * which is not bonded with any relation. Thus, we detect the const - * side - if another side is constant too, the orqual couldn't be an - * OpExpr. Get pointers to constant and expression sides of the qual. - */ - leftop = get_leftop(orqual); - if (IsA(leftop, RelabelType)) - leftop = (Node *) ((RelabelType *) leftop)->arg; - rightop = get_rightop(orqual); - if (IsA(rightop, RelabelType)) - rightop = (Node *) ((RelabelType *) rightop)->arg; - - if (IsA(leftop, Const)) - { - opno = get_commutator(opno); - - if (!OidIsValid(opno)) - { - /* commutator doesn't exist, we can't reverse the order */ - entries = lappend(entries, orqual); - continue; - } - - nconst_expr = get_rightop(orqual); - const_expr = get_leftop(orqual); - } - else if (IsA(rightop, Const)) - { - const_expr = get_rightop(orqual); - nconst_expr = get_leftop(orqual); - } - else - { - entries = lappend(entries, orqual); - continue; - } - - /* - * Forbid transformation for composite types, records, and volatile - * expressions. - */ - consttype = exprType(const_expr); - if (type_is_rowtype(exprType(const_expr)) || - type_is_rowtype(consttype) || - contain_volatile_functions((Node *) nconst_expr)) - { - entries = lappend(entries, orqual); - continue; - } - - /* - * At this point we definitely have a transformable clause. Classify - * it and add into specific group of clauses, or create new group. - */ - hashkey.type = T_Invalid; - hashkey.expr = (Expr *) nconst_expr; - hashkey.opno = opno; - hashkey.consttype = consttype; - hashkey.inputcollid = exprCollation(const_expr); - entry = hash_search(or_group_htab, &hashkey, HASH_ENTER, &found); - - if (unlikely(found)) - { - entry->consts = lappend(entry->consts, const_expr); - entry->exprs = lappend(entry->exprs, orqual); - } - else - { - entry->consts = list_make1(const_expr); - entry->exprs = list_make1(orqual); - - /* - * Add the entry to the list. It is needed exclusively to manage - * the problem with the order of transformed clauses in explain. - * Hash value can depend on the platform and version. Hence, - * sequental scan of the hash table would prone to change the - * order of clauses in lists and, as a result, break regression - * tests accidentially. - */ - entries = lappend(entries, entry); - } - } - - /* Let's convert each group of clauses to an ANY expression. */ - - /* - * Go through the list of groups and convert each, where number of consts - * more than 1. trivial groups move to OR-list again - */ - foreach(lc, entries) - { - Oid scalar_type; - Oid array_type; - - if (!IsA(lfirst(lc), Invalid)) - { - neworlist = lappend(neworlist, lfirst(lc)); - continue; - } - - entry = (OrClauseGroupEntry *) lfirst(lc); - - Assert(list_length(entry->consts) > 0); - Assert(list_length(entry->exprs) == list_length(entry->consts)); - - if (list_length(entry->consts) == 1) - { - /* - * Only one element returns origin expression into the BoolExpr - * args list unchanged. - */ - list_free(entry->consts); - neworlist = list_concat(neworlist, entry->exprs); - continue; - } - - /* - * Do the transformation. - */ - scalar_type = entry->key.consttype; - array_type = OidIsValid(scalar_type) ? get_array_type(scalar_type) : - InvalidOid; - - if (OidIsValid(array_type)) - { - /* - * OK: coerce all the right-hand non-Var inputs to the common type - * and build an ArrayExpr for them. - */ - List *aexprs = NIL; - ArrayExpr *newa = NULL; - ScalarArrayOpExpr *saopexpr = NULL; - HeapTuple opertup; - Form_pg_operator operform; - List *namelist = NIL; - ListCell *lc2; - - foreach(lc2, entry->consts) - { - Node *node = (Node *) lfirst(lc2); - - node = coerce_to_common_type(NULL, node, scalar_type, - "OR ANY Transformation"); - aexprs = lappend(aexprs, node); - } - - newa = makeNode(ArrayExpr); - /* array_collid will be set by parse_collate.c */ - newa->element_typeid = scalar_type; - newa->array_typeid = array_type; - newa->multidims = false; - newa->elements = aexprs; - newa->location = -1; - - /* - * Try to cast this expression to Const. Due to current strict - * transformation rules it should be done [almost] every time. - */ - newa = (ArrayExpr *) eval_const_expressions(NULL, (Node *) newa); - - opertup = SearchSysCache1(OPEROID, - ObjectIdGetDatum(entry->key.opno)); - if (!HeapTupleIsValid(opertup)) - elog(ERROR, "cache lookup failed for operator %u", - entry->key.opno); - - operform = (Form_pg_operator) GETSTRUCT(opertup); - if (!OperatorIsVisible(entry->key.opno)) - namelist = lappend(namelist, makeString(get_namespace_name(operform->oprnamespace))); - - namelist = lappend(namelist, makeString(pstrdup(NameStr(operform->oprname)))); - ReleaseSysCache(opertup); - - saopexpr = - (ScalarArrayOpExpr *) - make_scalar_array_op(NULL, - namelist, - true, - (Node *) entry->key.expr, - (Node *) newa, - -1); - saopexpr->inputcollid = entry->key.inputcollid; - - neworlist = lappend(neworlist, (void *) saopexpr); - } - else - { - /* - * If the const node's (right side of operator expression) type - * don't have “true” array type, then we cannnot do the - * transformation. We simply concatenate the expression node. - */ - list_free(entry->consts); - neworlist = list_concat(neworlist, entry->exprs); - } - } - hash_destroy(or_group_htab); - list_free(entries); - - /* One more trick: assemble correct clause */ - return neworlist; -} /* * canonicalize_qual @@ -980,22 +601,10 @@ process_duplicate_ors(List *orlist) } /* - * If no winners, we can't do OR-to-ANY transformation. + * If no winners, we can't transform the OR */ if (winners == NIL) - { - /* - * Make an attempt to group similar OR clauses into SAOP if the list - * is lengthy enough. - */ - if (or_to_any_transform_limit >= 0 && - list_length(orlist) >= or_to_any_transform_limit) - orlist = transform_or_to_any(orlist); - - /* Transformation could group all OR clauses to a single SAOP */ - return (list_length(orlist) == 1) ? - (Expr *) linitial(orlist) : make_orclause(orlist); - } + return make_orclause(orlist); /* * Generate new OR list consisting of the remaining sub-clauses. @@ -1042,11 +651,6 @@ process_duplicate_ors(List *orlist) } } - /* Make an attempt to group similar OR clauses into ANY operation */ - if (or_to_any_transform_limit >= 0 && - list_length(neworlist) >= or_to_any_transform_limit) - neworlist = transform_or_to_any(neworlist); - /* * Append reduced OR to the winners list, if it's not degenerate, handling * the special case of one element correctly (can that really happen?). diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c index 72ee913ddd..c68fdc008b 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -3668,18 +3668,6 @@ struct config_int ConfigureNamesInt[] = NULL, NULL, NULL }, - { - {"or_to_any_transform_limit", PGC_USERSET, QUERY_TUNING_OTHER, - gettext_noop("Sets the minimum length of the list of OR clauses to attempt the OR-to-ANY transformation."), - gettext_noop("Once the limit is reached, the planner will try to replace expression like " - "'x=c1 OR x=c2 ..' to the expression 'x = ANY(ARRAY[c1,c2,..])'"), - GUC_EXPLAIN - }, - &or_to_any_transform_limit, - 5, -1, INT_MAX, - NULL, NULL, NULL - }, - /* End-of-list marker */ { {NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 2bfd255108..2166ea4a87 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -392,7 +392,6 @@ # - Planner Method Configuration - #enable_async_append = on -#or_to_any_transform_limit = 5 #enable_bitmapscan = on #enable_gathermerge = on #enable_hashagg = on diff --git a/src/include/nodes/queryjumble.h b/src/include/nodes/queryjumble.h index 5643ee8f65..f1c55c8067 100644 --- a/src/include/nodes/queryjumble.h +++ b/src/include/nodes/queryjumble.h @@ -65,7 +65,6 @@ extern PGDLLIMPORT int compute_query_id; extern const char *CleanQuerytext(const char *query, int *location, int *len); extern JumbleState *JumbleQuery(Query *query); -extern JumbleState *JumbleExpr(Expr *expr, uint64 *exprId); extern void EnableQueryId(void); extern PGDLLIMPORT bool query_id_enabled; diff --git a/src/include/optimizer/optimizer.h b/src/include/optimizer/optimizer.h index 960dfb97a3..7b63c5cf71 100644 --- a/src/include/optimizer/optimizer.h +++ b/src/include/optimizer/optimizer.h @@ -133,8 +133,6 @@ extern void extract_query_dependencies(Node *query, /* in prep/prepqual.c: */ -extern PGDLLIMPORT int or_to_any_transform_limit; - extern Node *negate_clause(Node *node); extern Expr *canonicalize_qual(Expr *qual, bool is_check); diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index b4b42173e5..cf6eac5734 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -1889,165 +1889,6 @@ SELECT count(*) FROM tenk1 10 (1 row) -SET or_to_any_transform_limit = 0; -EXPLAIN (COSTS OFF) -SELECT * FROM tenk1 - WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42); - QUERY PLAN ------------------------------------------------------------------------------- - Index Scan using tenk1_thous_tenthous on tenk1 - Index Cond: ((thousand = 42) AND (tenthous = ANY ('{1,3,42}'::integer[]))) -(2 rows) - -SELECT * FROM tenk1 - WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42); - unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ----------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- - 42 | 5530 | 0 | 2 | 2 | 2 | 42 | 42 | 42 | 42 | 42 | 84 | 85 | QBAAAA | SEIAAA | OOOOxx -(1 row) - -SET or_to_any_transform_limit = 3; -EXPLAIN (COSTS OFF) -- or_transformation still works -SELECT * FROM tenk1 - WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42); - QUERY PLAN ------------------------------------------------------------------------------- - Index Scan using tenk1_thous_tenthous on tenk1 - Index Cond: ((thousand = 42) AND (tenthous = ANY ('{1,3,42}'::integer[]))) -(2 rows) - -SET or_to_any_transform_limit = 4; -EXPLAIN (COSTS OFF) -- or_transformation must be disabled -SELECT * FROM tenk1 - WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42); - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------ - Bitmap Heap Scan on tenk1 - Recheck Cond: (((thousand = 42) AND (tenthous = 1)) OR ((thousand = 42) AND (tenthous = 3)) OR ((thousand = 42) AND (tenthous = 42))) - -> BitmapOr - -> Bitmap Index Scan on tenk1_thous_tenthous - Index Cond: ((thousand = 42) AND (tenthous = 1)) - -> Bitmap Index Scan on tenk1_thous_tenthous - Index Cond: ((thousand = 42) AND (tenthous = 3)) - -> Bitmap Index Scan on tenk1_thous_tenthous - Index Cond: ((thousand = 42) AND (tenthous = 42)) -(9 rows) - -RESET or_to_any_transform_limit; -SET or_to_any_transform_limit = 0; -EXPLAIN (COSTS OFF) -SELECT count(*) FROM tenk1 - WHERE hundred = 42 AND (thousand = 42 OR thousand = 99); - QUERY PLAN ------------------------------------------------------------------------------------- - Aggregate - -> Bitmap Heap Scan on tenk1 - Recheck Cond: ((hundred = 42) AND (thousand = ANY ('{42,99}'::integer[]))) - -> BitmapAnd - -> Bitmap Index Scan on tenk1_hundred - Index Cond: (hundred = 42) - -> Bitmap Index Scan on tenk1_thous_tenthous - Index Cond: (thousand = ANY ('{42,99}'::integer[])) -(8 rows) - -SELECT count(*) FROM tenk1 - WHERE hundred = 42 AND (thousand = 42 OR thousand = 99); - count -------- - 10 -(1 row) - -EXPLAIN (COSTS OFF) -SELECT count(*) FROM tenk1 - WHERE hundred = 42 AND (thousand < 42 OR thousand < 99 OR 43 > thousand OR 42 > thousand); - QUERY PLAN ------------------------------------------------------------------------------------------- - Aggregate - -> Bitmap Heap Scan on tenk1 - Recheck Cond: ((hundred = 42) AND (thousand < ANY ('{42,99,43,42}'::integer[]))) - -> BitmapAnd - -> Bitmap Index Scan on tenk1_hundred - Index Cond: (hundred = 42) - -> Bitmap Index Scan on tenk1_thous_tenthous - Index Cond: (thousand < ANY ('{42,99,43,42}'::integer[])) -(8 rows) - -EXPLAIN (COSTS OFF) -SELECT count(*) FROM tenk1 - WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3) OR thousand = 41; - QUERY PLAN --------------------------------------------------------------------------------------------------------- - Aggregate - -> Bitmap Heap Scan on tenk1 - Recheck Cond: (((thousand = 42) AND (tenthous = ANY ('{1,3}'::integer[]))) OR (thousand = 41)) - -> BitmapOr - -> Bitmap Index Scan on tenk1_thous_tenthous - Index Cond: ((thousand = 42) AND (tenthous = ANY ('{1,3}'::integer[]))) - -> Bitmap Index Scan on tenk1_thous_tenthous - Index Cond: (thousand = 41) -(8 rows) - -SELECT count(*) FROM tenk1 - WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3) OR thousand = 41; - count -------- - 10 -(1 row) - -EXPLAIN (COSTS OFF) -SELECT count(*) FROM tenk1 - WHERE hundred = 42 AND (thousand = 42 OR thousand = 99 OR tenthous < 2) OR thousand = 41; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------ - Aggregate - -> Bitmap Heap Scan on tenk1 - Recheck Cond: (((hundred = 42) AND ((thousand = ANY ('{42,99}'::integer[])) OR (tenthous < 2))) OR (thousand = 41)) - -> BitmapOr - -> BitmapAnd - -> Bitmap Index Scan on tenk1_hundred - Index Cond: (hundred = 42) - -> BitmapOr - -> Bitmap Index Scan on tenk1_thous_tenthous - Index Cond: (thousand = ANY ('{42,99}'::integer[])) - -> Bitmap Index Scan on tenk1_thous_tenthous - Index Cond: (tenthous < 2) - -> Bitmap Index Scan on tenk1_thous_tenthous - Index Cond: (thousand = 41) -(14 rows) - -SELECT count(*) FROM tenk1 - WHERE hundred = 42 AND (thousand = 42 OR thousand = 99 OR tenthous < 2) OR thousand = 41; - count -------- - 20 -(1 row) - -EXPLAIN (COSTS OFF) -SELECT count(*) FROM tenk1 - WHERE hundred = 42 AND (thousand = 42 OR thousand = 41 OR thousand = 99 AND tenthous = 2); - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- - Aggregate - -> Bitmap Heap Scan on tenk1 - Recheck Cond: ((hundred = 42) AND ((thousand = ANY ('{42,41}'::integer[])) OR ((thousand = 99) AND (tenthous = 2)))) - -> BitmapAnd - -> Bitmap Index Scan on tenk1_hundred - Index Cond: (hundred = 42) - -> BitmapOr - -> Bitmap Index Scan on tenk1_thous_tenthous - Index Cond: (thousand = ANY ('{42,41}'::integer[])) - -> Bitmap Index Scan on tenk1_thous_tenthous - Index Cond: ((thousand = 99) AND (tenthous = 2)) -(11 rows) - -SELECT count(*) FROM tenk1 - WHERE hundred = 42 AND (thousand = 42 OR thousand = 41 OR thousand = 99 AND tenthous = 2); - count -------- - 10 -(1 row) - -RESET or_to_any_transform_limit; -- -- Check behavior with duplicate index column contents -- diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out index 407d251a50..8b640c2fc2 100644 --- a/src/test/regress/expected/join.out +++ b/src/test/regress/expected/join.out @@ -4233,56 +4233,6 @@ select * from tenk1 a join tenk1 b on Index Cond: (unique2 = 7) (19 rows) -SET or_to_any_transform_limit = 0; -explain (costs off) -select * from tenk1 a join tenk1 b on - (a.unique1 = 1 and b.unique1 = 2) or - ((a.unique2 = 3 or a.unique2 = 7) and b.hundred = 4); - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------- - Nested Loop - Join Filter: (((a.unique1 = 1) AND (b.unique1 = 2)) OR ((a.unique2 = ANY ('{3,7}'::integer[])) AND (b.hundred = 4))) - -> Bitmap Heap Scan on tenk1 b - Recheck Cond: ((unique1 = 2) OR (hundred = 4)) - -> BitmapOr - -> Bitmap Index Scan on tenk1_unique1 - Index Cond: (unique1 = 2) - -> Bitmap Index Scan on tenk1_hundred - Index Cond: (hundred = 4) - -> Materialize - -> Bitmap Heap Scan on tenk1 a - Recheck Cond: ((unique1 = 1) OR (unique2 = ANY ('{3,7}'::integer[]))) - -> BitmapOr - -> Bitmap Index Scan on tenk1_unique1 - Index Cond: (unique1 = 1) - -> Bitmap Index Scan on tenk1_unique2 - Index Cond: (unique2 = ANY ('{3,7}'::integer[])) -(17 rows) - -explain (costs off) -select * from tenk1 a join tenk1 b on - (a.unique1 < 20 or a.unique1 = 3 or a.unique1 = 1 and b.unique1 = 2) or - ((a.unique2 = 3 or a.unique2 = 7) and b.hundred = 4); - QUERY PLAN ---------------------------------------------------------------------------------------------------------------------------------------------------------------- - Nested Loop - Join Filter: ((a.unique1 < 20) OR (a.unique1 = 3) OR ((a.unique1 = 1) AND (b.unique1 = 2)) OR ((a.unique2 = ANY ('{3,7}'::integer[])) AND (b.hundred = 4))) - -> Seq Scan on tenk1 b - -> Materialize - -> Bitmap Heap Scan on tenk1 a - Recheck Cond: ((unique1 < 20) OR (unique1 = 3) OR (unique1 = 1) OR (unique2 = ANY ('{3,7}'::integer[]))) - -> BitmapOr - -> Bitmap Index Scan on tenk1_unique1 - Index Cond: (unique1 < 20) - -> Bitmap Index Scan on tenk1_unique1 - Index Cond: (unique1 = 3) - -> Bitmap Index Scan on tenk1_unique1 - Index Cond: (unique1 = 1) - -> Bitmap Index Scan on tenk1_unique2 - Index Cond: (unique2 = ANY ('{3,7}'::integer[])) -(15 rows) - -RESET or_to_any_transform_limit; -- -- test placement of movable quals in a parameterized join tree -- diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index db507eff44..46b78ba3c4 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -3,7 +3,6 @@ -- -- Force generic plans to be used for all prepared statements in this file. set plan_cache_mode = force_generic_plan; -set or_to_any_transform_limit = 0; create table lp (a char) partition by list (a); create table lp_default partition of lp default; create table lp_ef partition of lp for values in ('e', 'f'); @@ -83,23 +82,23 @@ explain (costs off) select * from lp where a is null; (2 rows) explain (costs off) select * from lp where a = 'a' or a = 'c'; - QUERY PLAN ------------------------------------------------ + QUERY PLAN +---------------------------------------------------------- Append -> Seq Scan on lp_ad lp_1 - Filter: (a = ANY ('{a,c}'::bpchar[])) + Filter: ((a = 'a'::bpchar) OR (a = 'c'::bpchar)) -> Seq Scan on lp_bc lp_2 - Filter: (a = ANY ('{a,c}'::bpchar[])) + Filter: ((a = 'a'::bpchar) OR (a = 'c'::bpchar)) (5 rows) explain (costs off) select * from lp where a is not null and (a = 'a' or a = 'c'); - QUERY PLAN ---------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------------------- Append -> Seq Scan on lp_ad lp_1 - Filter: ((a IS NOT NULL) AND (a = ANY ('{a,c}'::bpchar[]))) + Filter: ((a IS NOT NULL) AND ((a = 'a'::bpchar) OR (a = 'c'::bpchar))) -> Seq Scan on lp_bc lp_2 - Filter: ((a IS NOT NULL) AND (a = ANY ('{a,c}'::bpchar[]))) + Filter: ((a IS NOT NULL) AND ((a = 'a'::bpchar) OR (a = 'c'::bpchar))) (5 rows) explain (costs off) select * from lp where a <> 'g'; @@ -516,10 +515,10 @@ explain (costs off) select * from rlp where a <= 31; (27 rows) explain (costs off) select * from rlp where a = 1 or a = 7; - QUERY PLAN ------------------------------------------- + QUERY PLAN +-------------------------------- Seq Scan on rlp2 rlp - Filter: (a = ANY ('{1,7}'::integer[])) + Filter: ((a = 1) OR (a = 7)) (2 rows) explain (costs off) select * from rlp where a = 1 or b = 'ab'; @@ -597,13 +596,13 @@ explain (costs off) select * from rlp where a < 1 or (a > 20 and a < 25); -- where clause contradicts sub-partition's constraint explain (costs off) select * from rlp where a = 20 or a = 40; - QUERY PLAN --------------------------------------------------- + QUERY PLAN +---------------------------------------- Append -> Seq Scan on rlp4_1 rlp_1 - Filter: (a = ANY ('{20,40}'::integer[])) + Filter: ((a = 20) OR (a = 40)) -> Seq Scan on rlp5_default rlp_2 - Filter: (a = ANY ('{20,40}'::integer[])) + Filter: ((a = 20) OR (a = 40)) (5 rows) explain (costs off) select * from rlp3 where a = 20; /* empty */ @@ -2073,10 +2072,10 @@ explain (costs off) select * from hp where a = 1 and b = 'abcde'; explain (costs off) select * from hp where a = 1 and b = 'abcde' and (c = 2 or c = 3); - QUERY PLAN --------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------- Seq Scan on hp2 hp - Filter: ((c = ANY ('{2,3}'::integer[])) AND (a = 1) AND (b = 'abcde'::text)) + Filter: ((a = 1) AND (b = 'abcde'::text) AND ((c = 2) OR (c = 3))) (2 rows) drop table hp2; diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql index 7059b4ea86..e296891cab 100644 --- a/src/test/regress/sql/create_index.sql +++ b/src/test/regress/sql/create_index.sql @@ -738,51 +738,6 @@ SELECT count(*) FROM tenk1 SELECT count(*) FROM tenk1 WHERE hundred = 42 AND (thousand = 42 OR thousand = 99); -SET or_to_any_transform_limit = 0; -EXPLAIN (COSTS OFF) -SELECT * FROM tenk1 - WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42); -SELECT * FROM tenk1 - WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42); -SET or_to_any_transform_limit = 3; -EXPLAIN (COSTS OFF) -- or_transformation still works -SELECT * FROM tenk1 - WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42); -SET or_to_any_transform_limit = 4; -EXPLAIN (COSTS OFF) -- or_transformation must be disabled -SELECT * FROM tenk1 - WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42); -RESET or_to_any_transform_limit; - -SET or_to_any_transform_limit = 0; -EXPLAIN (COSTS OFF) -SELECT count(*) FROM tenk1 - WHERE hundred = 42 AND (thousand = 42 OR thousand = 99); -SELECT count(*) FROM tenk1 - WHERE hundred = 42 AND (thousand = 42 OR thousand = 99); -EXPLAIN (COSTS OFF) -SELECT count(*) FROM tenk1 - WHERE hundred = 42 AND (thousand < 42 OR thousand < 99 OR 43 > thousand OR 42 > thousand); - -EXPLAIN (COSTS OFF) -SELECT count(*) FROM tenk1 - WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3) OR thousand = 41; -SELECT count(*) FROM tenk1 - WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3) OR thousand = 41; - -EXPLAIN (COSTS OFF) -SELECT count(*) FROM tenk1 - WHERE hundred = 42 AND (thousand = 42 OR thousand = 99 OR tenthous < 2) OR thousand = 41; -SELECT count(*) FROM tenk1 - WHERE hundred = 42 AND (thousand = 42 OR thousand = 99 OR tenthous < 2) OR thousand = 41; - -EXPLAIN (COSTS OFF) -SELECT count(*) FROM tenk1 - WHERE hundred = 42 AND (thousand = 42 OR thousand = 41 OR thousand = 99 AND tenthous = 2); -SELECT count(*) FROM tenk1 - WHERE hundred = 42 AND (thousand = 42 OR thousand = 41 OR thousand = 99 AND tenthous = 2); -RESET or_to_any_transform_limit; - -- -- Check behavior with duplicate index column contents -- diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql index 266461fb5b..c4c6c7b8ba 100644 --- a/src/test/regress/sql/join.sql +++ b/src/test/regress/sql/join.sql @@ -1409,17 +1409,6 @@ select * from tenk1 a join tenk1 b on (a.unique1 = 1 and b.unique1 = 2) or ((a.unique2 = 3 or a.unique2 = 7) and b.hundred = 4); -SET or_to_any_transform_limit = 0; -explain (costs off) -select * from tenk1 a join tenk1 b on - (a.unique1 = 1 and b.unique1 = 2) or - ((a.unique2 = 3 or a.unique2 = 7) and b.hundred = 4); -explain (costs off) -select * from tenk1 a join tenk1 b on - (a.unique1 < 20 or a.unique1 = 3 or a.unique1 = 1 and b.unique1 = 2) or - ((a.unique2 = 3 or a.unique2 = 7) and b.hundred = 4); -RESET or_to_any_transform_limit; - -- -- test placement of movable quals in a parameterized join tree -- diff --git a/src/test/regress/sql/partition_prune.sql b/src/test/regress/sql/partition_prune.sql index c49153f38a..dc71693861 100644 --- a/src/test/regress/sql/partition_prune.sql +++ b/src/test/regress/sql/partition_prune.sql @@ -4,7 +4,6 @@ -- Force generic plans to be used for all prepared statements in this file. set plan_cache_mode = force_generic_plan; -set or_to_any_transform_limit = 0; create table lp (a char) partition by list (a); create table lp_default partition of lp default; @@ -22,7 +21,6 @@ explain (costs off) select * from lp where a is not null; explain (costs off) select * from lp where a is null; explain (costs off) select * from lp where a = 'a' or a = 'c'; explain (costs off) select * from lp where a is not null and (a = 'a' or a = 'c'); - explain (costs off) select * from lp where a <> 'g'; explain (costs off) select * from lp where a <> 'a' and a <> 'd'; explain (costs off) select * from lp where a not in ('a', 'd'); diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 704e61dcaa..c83417ce9d 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -1703,8 +1703,6 @@ NumericVar OM_uint32 OP OSAPerGroupState -OrClauseGroupEntry -OrClauseGroupKey OSAPerQueryState OSInfo OSSLCipher