v9-0001-Replace-OR-clause-to_ANY.diff.txt
text/plain
Filename: v9-0001-Replace-OR-clause-to_ANY.diff.txt
Type: text/plain
Part: 1
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