diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 46212a77c64..290422005a3 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -102,7 +102,7 @@ static Node *make_nulltest_from_distinct(ParseState *pstate, A_Expr *distincta, Node *arg); typedef struct OrClauseGroupEntry { - char *hash_leftvar_key; + int32 hash_leftvar_key; Node *node; List *consts; @@ -111,63 +111,47 @@ typedef struct OrClauseGroupEntry Node *expr; } OrClauseGroupEntry; -static int -or_name_match(const void *key1, const void *key2, Size keysize) +/* + * TODO: consider different algorithm to manage complexity + * in the case of many different clauses, + * like Rabin-Karp or Boyer–Moore algorithms. + */ +static char * +clear_patterns(const char *str, const char *start_pattern) { - const char *name1 = *(const char *const *) key1; - const char *name2 = *(const char *const *) key2; + int i = 0; + int j = 0; + int start_pattern_len = strlen(start_pattern); + char *res = palloc0(sizeof(*res) * (strlen(str) + 1)); - return strcmp(name1, name2); -} - -static uint32 -or_name_hash(const void *key, Size keysize) -{ - const char *name = *(const char *const *) key; + for (i = 0; str[i];) + { + if (i >= start_pattern_len && strncmp(&str[i - start_pattern_len], + start_pattern, + start_pattern_len) == 0) + { + while (str[i] && !(str[i] == '{' || str[i] == '}')) + i++; + } + if (str[i]) + res[j++] = str[i++]; + } - return DatumGetInt32(hash_any((unsigned char *)name, strlen(name))); + return res; } -static char * +static int32 get_key_nconst_node(Node *nconst_node) { - if (IsA(nconst_node, OpExpr)) - { - OpExpr *clause = (OpExpr*) nconst_node; - OpExpr *temp = makeNode(OpExpr); - - temp->opno = clause->opno; - temp->opfuncid = InvalidOid; - temp->opresulttype = clause->opresulttype; - temp->opretset = clause->opretset; - temp->opcollid = clause->opcollid; - temp->inputcollid = clause->inputcollid; - temp->location = -1; - - temp->args = list_copy(clause->args); - return nodeToString(temp); - } - else if (IsA(nconst_node, Var)) - { - Var *clause = (Var*) nconst_node; - Var *var = makeNode(Var); - - var->varno = clause->varno; - var->varattno = clause->varattno; - var->vartype = clause->vartype; - var->vartypmod = clause->vartypmod; - var->varcollid = clause->varcollid; - var->varlevelsup = clause->varlevelsup; - var->varattnosyn = clause->varattno; - var->location = -1; - - return nodeToString(var); - } - else - { - return NULL; - } - } + char *str = nodeToString(nconst_node); + + str = clear_patterns(str, " :location"); + + if (str == NULL) + return 0; + + return DatumGetInt32(hash_any((unsigned char *)str, strlen(str))); +} static Node * transformBoolExprOr(ParseState *pstate, BoolExpr *expr_orig) @@ -179,14 +163,12 @@ transformBoolExprOr(ParseState *pstate, BoolExpr *expr_orig) int len_ors = list_length(expr_orig->args); MemSet(&info, 0, sizeof(info)); - info.keysize = sizeof(char *); + info.keysize = sizeof(int); info.entrysize = sizeof(OrClauseGroupEntry); - info.hash = or_name_hash; - info.match = or_name_match; or_group_htab = hash_create("OR Groups", len_ors, &info, - HASH_ELEM | HASH_FUNCTION | HASH_COMPARE); + HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); /* If this is not an 'OR' expression, skip the transformation */ if (expr_orig->boolop != OR_EXPR || !enable_or_transformation || len_ors == 1 || !or_group_htab) @@ -200,7 +182,7 @@ transformBoolExprOr(ParseState *pstate, BoolExpr *expr_orig) Node *nconst_expr = NULL; OrClauseGroupEntry *gentry = NULL; bool found; - char *str; + int32 hash; /* At first, transform the arg and evaluate constant expressions. */ orqual = transformExprRecurse(pstate, (Node *) arg); @@ -237,9 +219,9 @@ transformBoolExprOr(ParseState *pstate, BoolExpr *expr_orig) continue; } - str = get_key_nconst_node(nconst_expr); + hash = get_key_nconst_node(nconst_expr); - if (!op_mergejoinable(((OpExpr *) orqual)->opno, exprType(nconst_expr)) || str == NULL) + if (!op_mergejoinable(((OpExpr *) orqual)->opno, exprType(nconst_expr)) || hash == 0) { or_list = lappend(or_list, orqual); continue; @@ -254,7 +236,7 @@ transformBoolExprOr(ParseState *pstate, BoolExpr *expr_orig) * like a hash table. But also we believe, that the case of many * different variable sides is very rare. */ - gentry = hash_search(or_group_htab, &str, HASH_FIND, &found); + gentry = hash_search(or_group_htab, &hash, HASH_FIND, &found); if (found) { @@ -267,11 +249,11 @@ transformBoolExprOr(ParseState *pstate, BoolExpr *expr_orig) } /* New clause group needed */ - gentry = hash_search(or_group_htab, &str, HASH_ENTER, &found); + gentry = hash_search(or_group_htab, &hash, HASH_ENTER, &found); gentry->node = nconst_expr; gentry->consts = list_make1(const_expr); gentry->expr = orqual; - gentry->hash_leftvar_key = str; + gentry->hash_leftvar_key = hash; } if (or_group_htab && (hash_get_num_entries(or_group_htab) < 1 || diff --git a/src/test/regress/expected/partition_prune.out b/src/test/regress/expected/partition_prune.out index fe815417c13..804fea9f34c 100644 --- a/src/test/regress/expected/partition_prune.out +++ b/src/test/regress/expected/partition_prune.out @@ -702,34 +702,11 @@ explain (costs off) select * from rlp where a = 1 or a = 7; (2 rows) explain (costs off) select * from rlp where a = 1 or b = 'ab'; - QUERY PLAN -------------------------------------------------------- - Append - -> Seq Scan on rlp1 rlp_1 - Filter: (((b)::text = 'ab'::text) OR (a = 1)) - -> Seq Scan on rlp2 rlp_2 - Filter: (((b)::text = 'ab'::text) OR (a = 1)) - -> Seq Scan on rlp3abcd rlp_3 - Filter: (((b)::text = 'ab'::text) OR (a = 1)) - -> Seq Scan on rlp4_1 rlp_4 - Filter: (((b)::text = 'ab'::text) OR (a = 1)) - -> Seq Scan on rlp4_2 rlp_5 - Filter: (((b)::text = 'ab'::text) OR (a = 1)) - -> Seq Scan on rlp4_default rlp_6 - Filter: (((b)::text = 'ab'::text) OR (a = 1)) - -> Seq Scan on rlp5_1 rlp_7 - Filter: (((b)::text = 'ab'::text) OR (a = 1)) - -> Seq Scan on rlp5_default rlp_8 - Filter: (((b)::text = 'ab'::text) OR (a = 1)) - -> Seq Scan on rlp_default_10 rlp_9 - Filter: (((b)::text = 'ab'::text) OR (a = 1)) - -> Seq Scan on rlp_default_30 rlp_10 - Filter: (((b)::text = 'ab'::text) OR (a = 1)) - -> Seq Scan on rlp_default_null rlp_11 - Filter: (((b)::text = 'ab'::text) OR (a = 1)) - -> Seq Scan on rlp_default_default rlp_12 - Filter: (((b)::text = 'ab'::text) OR (a = 1)) -(25 rows) + QUERY PLAN +-------------------------- + Result + One-Time Filter: false +(2 rows) explain (costs off) select * from rlp where a > 20 and a < 27; QUERY PLAN diff --git a/src/test/regress/expected/sysviews.out b/src/test/regress/expected/sysviews.out index 8a380c29a4c..566f51df428 100644 --- a/src/test/regress/expected/sysviews.out +++ b/src/test/regress/expected/sysviews.out @@ -134,7 +134,7 @@ select name, setting from pg_settings where name like 'enable%'; enable_seqscan | on enable_sort | on enable_tidscan | on -(22 rows) +(23 rows) -- There are always wait event descriptions for various types. select type, count(*) > 0 as ok FROM pg_wait_events