Em qua., 28 de jun. de 2023 às 18:45, Tomas Vondra < tomas.von...@enterprisedb.com> escreveu:
> On 6/27/23 20:55, Ranier Vilela wrote: > > Hi, > > > >>I finished writing the code patch for transformation "Or" expressions to > >>"Any" expressions. I didn't see any problems in regression tests, even > >>when I changed the constant at which the minimum or expression is > >>replaced by any at 0. I ran my patch on sqlancer and so far the code has > >>never fallen. > > Thanks for working on this. > > > > I took the liberty of making some modifications to the patch. > > I didn't compile or test it. > > Please feel free to use them. > > > > I don't want to be rude, but this doesn't seem very helpful. > Sorry, It was not my intention to cause interruptions. > - You made some changes, but you don't even attempt to explain what you > changed or why you changed it. > 1. Reduce scope 2. Eliminate unnecessary variables 3. Eliminate unnecessary expressions > > - You haven't even tried to compile the code, nor tested it. If it > happens to compile, wow could others even know it actually behaves the > way you wanted? > Attached v2 with make check pass all tests. Ubuntu 64 bits gcc 64 bits > - You responded in a way that breaks the original thread, so it's not > clear which message you're responding to. > It was a pretty busy day. Sorry for the noise, I hope I was of some help. regards, Ranier Vilela P.S. 0001-Replace-clause-X-N1-OR-X-N2-.-with-X-ANY-N1-N2-on.patch fails with 4 tests.
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 346fd272b6..74c256258d 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -95,6 +95,291 @@ static Expr *make_distinct_op(ParseState *pstate, List *opname, static Node *make_nulltest_from_distinct(ParseState *pstate, A_Expr *distincta, Node *arg); +typedef struct OrClauseGroupEntry +{ + Node *node; + List *consts; + Oid scalar_type; + Oid opno; + Expr *expr; +} OrClauseGroupEntry; + +static int const_transform_or_limit = 0; + +static Node * +transformBoolExprOr(ParseState *pstate, Expr *expr_orig) +{ + List *or_list = NIL; + List *groups_list = NIL; + ListCell *lc_eargs; + Node *result; + BoolExpr *expr; + const char *opname; + bool change_apply = false; + bool or_statement; + + Assert(IsA(expr, BoolExpr)); + + expr = (BoolExpr *) expr_orig; + if (list_length(expr->args) < const_transform_or_limit) + return transformBoolExpr(pstate, (BoolExpr *)expr_orig); + + /* If this is not expression "Or", then will do it the old way. */ + switch (expr->boolop) + { + case AND_EXPR: + opname = "AND"; + break; + case OR_EXPR: + return transformBoolExpr(pstate, (BoolExpr *)expr_orig); + break; + case NOT_EXPR: + opname = "NOT"; + break; + default: + elog(ERROR, "unrecognized boolop: %d", (int) expr->boolop); + opname = NULL; /* keep compiler quiet */ + break; + } + + /* + * NOTE: + * It is an OR-clause. So, rinfo->orclause is a BoolExpr node, contains + * a list of sub-restrictinfo args, and rinfo->clause - which is the + * same expression, made from bare clauses. To not break selectivity + * caches and other optimizations, use both: + * - use rinfos from orclause if no transformation needed + * - use bare quals from rinfo->clause in the case of transformation, + * to create new RestrictInfo: in this case we have no options to avoid + * selectivity estimation procedure. + */ + or_statement = false; + expr = (BoolExpr *)copyObject(expr_orig); + foreach(lc_eargs, expr->args) + { + A_Expr *arg = (A_Expr *) lfirst(lc_eargs); + Node *bare_orarg; + Node *const_expr; + Node *non_const_expr; + ListCell *lc_groups; + OrClauseGroupEntry *gentry; + bool allow_transformation; + + /* + * The first step: checking that the expression consists only of equality. + * We can only do this here, while arg is still row data type, namely A_Expr. + * After applying transformExprRecurce, we already know that it will be OpExr type, + * but checking the expression for equality is already becoming impossible for us. + * Sometimes we have the chance to devide expression into the groups on + * equality and inequality. This is possible if all list items are not at the + * same level of a single BoolExpr expression, otherwise all of them cannot be converted. + */ + + if (!arg) + break; + + allow_transformation = ( + arg->type == T_A_Expr && (arg)->kind == AEXPR_OP && + list_length((arg)->name) >=1 && strcmp(strVal(linitial((arg)->name)), "=") == 0 + ); + + + bare_orarg = transformExprRecurse(pstate, (Node *)arg); + bare_orarg = coerce_to_boolean(pstate, bare_orarg, opname); + + /* + * The next step: transform all the inputs, and detect whether any contain + * Vars. + */ + if (!allow_transformation || !bare_orarg || !IsA(bare_orarg, OpExpr) || !contain_vars_of_level(bare_orarg, 0)) + { + /* Again, it's not the expr we can transform */ + or_list = lappend(or_list, bare_orarg); + continue; + } + + /* + * Get pointers to constant and expression sides of the clause + */ + non_const_expr = get_leftop(bare_orarg); + const_expr = get_rightop(bare_orarg); + + /* + * At this point we definitely have a transformable clause. + * Classify it and add into specific group of clauses, or create new + * group. + * TODO: to manage complexity in the case of many different clauses + * (X1=C1) OR (X2=C2 OR) ... (XN = CN) we could invent something + * like a hash table (htab key ???). + */ + foreach(lc_groups, groups_list) + { + OrClauseGroupEntry *v = (OrClauseGroupEntry *) lfirst(lc_groups); + + Assert(v->node != NULL); + + if (equal(v->node, non_const_expr)) + { + v->consts = lappend(v->consts, const_expr); + non_const_expr = NULL; + break; + } + } + + if (non_const_expr == NULL) + /* + * The clause classified successfully and added into existed + * clause group. + */ + continue; + + /* New clause group needed */ + gentry = palloc(sizeof(OrClauseGroupEntry)); + gentry->node = non_const_expr; + gentry->consts = list_make1(const_expr); + gentry->opno = ((OpExpr *)bare_orarg)->opno; + gentry->expr = (Expr *)bare_orarg; + groups_list = lappend(groups_list, (void *) gentry); + } + + if (groups_list == NIL) + { + /* + * No any transformations possible with this rinfo, just add itself + * to the list and go further. + */ + list_free(or_list); + + return transformBoolExpr(pstate, (BoolExpr *)expr_orig); + } + else + { + ListCell *lc_args; + + /* Let's convert each group of clauses to an IN operation. */ + + /* + * 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_args, groups_list) + { + OrClauseGroupEntry *gentry = (OrClauseGroupEntry *) lfirst(lc_args); + List *allexprs; + Oid scalar_type; + + Assert(list_length(gentry->consts) > 0); + + if (list_length(gentry->consts) == 1) + { + /* + * Only one element in the class. Return rinfo into the BoolExpr + * args list unchanged. + */ + list_free(gentry->consts); + or_list = lappend(or_list, gentry->expr); + continue; + } + + /* + * Do the transformation. It's been a long way ;) + * + * First of all, try to select a common type for the array elements. Note that + * since the LHS' type is first in the list, it will be preferred when + * there is doubt (eg, when all the RHS items are unknown literals). + * + * Note: use list_concat here not lcons, to avoid damaging rnonvars. + * + * As a source of insides, use make_scalar_array_op() + */ + allexprs = list_concat(list_make1(gentry->node), gentry->consts); + scalar_type = select_common_type(NULL, allexprs, NULL, NULL); + + if (OidIsValid(scalar_type) && + scalar_type != RECORDOID && + verify_common_type(scalar_type, allexprs)) + { + /* + * OK: coerce all the right-hand non-Var inputs to the common type + * and build an ArrayExpr for them. + */ + List *aexprs; + ArrayExpr *newa; + ScalarArrayOpExpr *saopexpr; + ListCell *l; + + aexprs = NIL; + + foreach(l, gentry->consts) + { + Node *rexpr = (Node *) lfirst(l); + + rexpr = coerce_to_common_type(pstate, rexpr, + scalar_type, + "IN"); + aexprs = lappend(aexprs, rexpr); + } + + newa = makeNode(ArrayExpr); + /* array_collid will be set by parse_collate.c */ + newa->element_typeid = scalar_type; + newa->array_typeid = get_array_type(scalar_type); + newa->multidims = false; + newa->elements = aexprs; + newa->location = -1; /* Position of the new clause is undefined */ + + saopexpr = (ScalarArrayOpExpr *)make_scalar_array_op(pstate, + list_make1(makeString((char *) "=")), + true, + gentry->node, + (Node *) newa, + -1); /* Position of the new clause is undefined */ + + /* + * TODO: here we can try to coerce the array to a Const and find + * hash func instead of linear search (see 50e17ad281b). + * convert_saop_to_hashed_saop((Node *) saopexpr); + * We don't have to do this anymore, do we? + */ + + or_list = lappend(or_list, (void *) saopexpr); + change_apply = true; + } + else + { + list_free(gentry->consts); + or_list = lappend(or_list, gentry->expr); + continue; + } + } + + if (!change_apply) + { + or_statement = false; + } + list_free_deep(groups_list); + } + + if (or_statement) + { + /* One more trick: assemble correct clause */ + expr = list_length(or_list) > 1 ? makeBoolExpr(OR_EXPR, list_copy(or_list), -1) : linitial(or_list); + result = (Node *)expr; + } + /* + * There was no reasons to create a new expresion, so + * run the original BoolExpr conversion with using + * transformBoolExpr function + */ + else + { + result = transformBoolExpr(pstate, (BoolExpr *)expr_orig); + } + list_free(or_list); + + return result; +} /* * transformExpr - @@ -208,7 +493,7 @@ transformExprRecurse(ParseState *pstate, Node *expr) } case T_BoolExpr: - result = transformBoolExpr(pstate, (BoolExpr *) expr); + result = (Node *)transformBoolExprOr(pstate, (Expr *)expr); break; case T_FuncCall: diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 260854747b..01918e6aea 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -1630,6 +1630,7 @@ NumericSumAccum NumericVar OM_uint32 OP +OrClauseGroupEntry OSAPerGroupState OSAPerQueryState OSInfo
ok 1 - test_setup 318 ms # parallel group (20 tests): varchar char name int2 txid oid boolean uuid int4 text pg_lsn money float4 regproc float8 bit enum int8 numeric rangetypes ok 2 + boolean 72 ms ok 3 + char 31 ms ok 4 + name 36 ms ok 5 + varchar 30 ms ok 6 + text 82 ms ok 7 + int2 64 ms ok 8 + int4 79 ms ok 9 + int8 141 ms ok 10 + oid 69 ms ok 11 + float4 92 ms ok 12 + float8 101 ms ok 13 + bit 121 ms ok 14 + numeric 438 ms ok 15 + txid 62 ms ok 16 + uuid 74 ms ok 17 + enum 134 ms ok 18 + money 87 ms ok 19 + rangetypes 554 ms ok 20 + pg_lsn 79 ms ok 21 + regproc 98 ms # parallel group (20 tests): md5 lseg circle timetz point numerology path macaddr time macaddr8 line date inet interval strings polygon multirangetypes box timestamp timestamptz ok 22 + strings 194 ms ok 23 + md5 23 ms ok 24 + numerology 76 ms ok 25 + point 74 ms ok 26 + lseg 26 ms ok 27 + line 90 ms ok 28 + box 334 ms ok 29 + path 85 ms ok 30 + polygon 288 ms ok 31 + circle 33 ms ok 32 + date 107 ms ok 33 + time 84 ms ok 34 + timetz 44 ms ok 35 + timestamp 386 ms ok 36 + timestamptz 423 ms ok 37 + interval 137 ms ok 38 + inet 114 ms ok 39 + macaddr 82 ms ok 40 + macaddr8 85 ms ok 41 + multirangetypes 328 ms # parallel group (12 tests): unicode comments xid misc_sanity expressions tstypes mvcc horology type_sanity geometry opr_sanity regex ok 42 + geometry 176 ms ok 43 + horology 134 ms ok 44 + tstypes 108 ms ok 45 + regex 572 ms ok 46 + type_sanity 157 ms ok 47 + opr_sanity 417 ms ok 48 + misc_sanity 52 ms ok 49 + comments 46 ms ok 50 + expressions 76 ms ok 51 + unicode 21 ms ok 52 + xid 50 ms ok 53 + mvcc 128 ms # parallel group (5 tests): copyselect copydml copy insert_conflict insert ok 54 + copy 84 ms ok 55 + copyselect 36 ms ok 56 + copydml 40 ms ok 57 + insert 349 ms ok 58 + insert_conflict 159 ms # parallel group (7 tests): create_function_c create_operator create_type create_schema create_misc create_procedure create_table ok 59 + create_function_c 15 ms ok 60 + create_misc 63 ms ok 61 + create_operator 33 ms ok 62 + create_procedure 68 ms ok 63 + create_table 422 ms ok 64 + create_type 51 ms ok 65 + create_schema 59 ms # parallel group (5 tests): index_including index_including_gist create_view create_index_spgist create_index not ok 66 + create_index 871 ms ok 67 + create_index_spgist 626 ms ok 68 + create_view 407 ms ok 69 + index_including 191 ms ok 70 + index_including_gist 357 ms # parallel group (16 tests): create_cast create_aggregate hash_func drop_if_exists roleattributes select typed_table errors create_function_sql create_am constraints vacuum infinite_recurse updatable_views inherit triggers ok 71 + create_aggregate 77 ms ok 72 + create_function_sql 185 ms ok 73 + create_cast 29 ms ok 74 + constraints 242 ms ok 75 + triggers 1110 ms ok 76 + select 118 ms ok 77 + inherit 827 ms ok 78 + typed_table 128 ms ok 79 + vacuum 507 ms ok 80 + drop_if_exists 107 ms ok 81 + updatable_views 734 ms ok 82 + roleattributes 116 ms ok 83 + create_am 224 ms ok 84 + hash_func 104 ms ok 85 + errors 149 ms ok 86 + infinite_recurse 519 ms ok 87 - sanity_check 123 ms # parallel group (20 tests): select_distinct_on select_having delete select_implicit random case namespace prepared_xacts select_into select_distinct transactions portals union subselect arrays update hash_index join aggregates btree_index ok 88 + select_into 218 ms ok 89 + select_distinct 305 ms ok 90 + select_distinct_on 58 ms ok 91 + select_implicit 62 ms ok 92 + select_having 57 ms ok 93 + subselect 459 ms ok 94 + union 390 ms ok 95 + case 110 ms not ok 96 + join 893 ms ok 97 + aggregates 941 ms ok 98 + transactions 344 ms ok 99 + random 77 ms ok 100 + portals 351 ms ok 101 + arrays 533 ms ok 102 + btree_index 2071 ms ok 103 + hash_index 848 ms ok 104 + update 623 ms ok 105 + delete 54 ms ok 106 + namespace 107 ms ok 107 + prepared_xacts 169 ms # parallel group (20 tests): init_privs security_label drop_operator tablesample lock object_address replica_identity password collate groupingsets identity matview generated rowsecurity spgist gin gist brin join_hash privileges ok 108 + brin 1933 ms ok 109 + gin 1259 ms ok 110 + gist 1401 ms ok 111 + spgist 1136 ms ok 112 + privileges 2243 ms ok 113 + init_privs 60 ms ok 114 + security_label 75 ms ok 115 + collate 441 ms ok 116 + matview 817 ms ok 117 + lock 237 ms ok 118 + replica_identity 393 ms ok 119 + rowsecurity 1037 ms ok 120 + object_address 283 ms ok 121 + tablesample 183 ms ok 122 + groupingsets 577 ms ok 123 + drop_operator 147 ms ok 124 + password 409 ms ok 125 + identity 590 ms ok 126 + generated 958 ms ok 127 + join_hash 1938 ms # parallel group (2 tests): brin_bloom brin_multi ok 128 + brin_bloom 102 ms ok 129 + brin_multi 240 ms # parallel group (16 tests): async collate.icu.utf8 dbsize alter_operator tid tsrf tidrangescan tidscan create_role sysviews alter_generic misc_functions misc incremental_sort merge create_table_like ok 130 + create_table_like 358 ms ok 131 + alter_generic 150 ms ok 132 + alter_operator 38 ms ok 133 + misc 198 ms ok 134 + async 16 ms ok 135 + dbsize 34 ms ok 136 + merge 299 ms ok 137 + misc_functions 172 ms ok 138 + sysviews 132 ms ok 139 + tsrf 65 ms ok 140 + tid 55 ms ok 141 + tidscan 97 ms ok 142 + tidrangescan 90 ms ok 143 + collate.icu.utf8 17 ms ok 144 + incremental_sort 220 ms ok 145 + create_role 103 ms # parallel group (7 tests): collate.windows.win1252 collate.linux.utf8 amutils psql_crosstab rules psql stats_ext ok 146 + rules 387 ms ok 147 + psql 434 ms ok 148 + psql_crosstab 42 ms ok 149 + amutils 23 ms not ok 150 + stats_ext 1818 ms ok 151 + collate.linux.utf8 16 ms ok 152 + collate.windows.win1252 15 ms ok 153 - select_parallel 855 ms ok 154 - write_parallel 92 ms ok 155 - vacuum_parallel 129 ms # parallel group (2 tests): subscription publication ok 156 + publication 410 ms ok 157 + subscription 61 ms # parallel group (17 tests): portals_p2 advisory_lock combocid tsdicts xmlmap dependency guc functional_deps equivclass select_views window bitmapops tsearch cluster indirect_toast foreign_data foreign_key ok 158 + select_views 272 ms ok 159 + portals_p2 60 ms ok 160 + foreign_key 1234 ms ok 161 + cluster 532 ms ok 162 + dependency 183 ms ok 163 + guc 196 ms ok 164 + bitmapops 505 ms ok 165 + combocid 113 ms ok 166 + tsearch 508 ms ok 167 + tsdicts 132 ms ok 168 + foreign_data 724 ms ok 169 + window 394 ms ok 170 + xmlmap 174 ms ok 171 + functional_deps 225 ms ok 172 + advisory_lock 75 ms ok 173 + indirect_toast 661 ms ok 174 + equivclass 228 ms # parallel group (7 tests): jsonpath_encoding json_encoding jsonpath sqljson jsonb_jsonpath json jsonb ok 175 + json 135 ms ok 176 + jsonb 314 ms ok 177 + json_encoding 21 ms ok 178 + jsonpath 51 ms ok 179 + jsonpath_encoding 17 ms ok 180 + jsonb_jsonpath 113 ms ok 181 + sqljson 72 ms # parallel group (18 tests): limit prepare returning plancache conversion temp xml copy2 rowtypes sequence polymorphism truncate with domain rangefuncs largeobject plpgsql alter_table ok 182 + plancache 198 ms ok 183 + limit 103 ms ok 184 + plpgsql 832 ms ok 185 + copy2 343 ms ok 186 + temp 256 ms ok 187 + domain 449 ms ok 188 + rangefuncs 463 ms ok 189 + prepare 125 ms ok 190 + conversion 221 ms ok 191 + truncate 417 ms ok 192 + alter_table 1638 ms ok 193 + sequence 381 ms ok 194 + polymorphism 404 ms ok 195 + rowtypes 345 ms ok 196 + returning 146 ms ok 197 + largeobject 480 ms ok 198 + with 431 ms ok 199 + xml 283 ms # parallel group (12 tests): hash_part reloptions explain partition_info memoize compression stats partition_prune indexing partition_join partition_aggregate tuplesort ok 200 + partition_join 1088 ms not ok 201 + partition_prune 972 ms ok 202 + reloptions 114 ms ok 203 + hash_part 66 ms ok 204 + indexing 1025 ms ok 205 + partition_aggregate 1109 ms ok 206 + partition_info 141 ms ok 207 + tuplesort 1518 ms ok 208 + explain 114 ms ok 209 + compression 209 ms ok 210 + memoize 200 ms ok 211 + stats 959 ms # parallel group (2 tests): event_trigger oidjoins ok 212 + event_trigger 124 ms ok 213 + oidjoins 235 ms ok 214 - fast_default 156 ms ok 215 - tablespace 364 ms 1..215 # 4 of 215 tests failed. # The differences that caused some tests to fail can be viewed in the file "/usr/src/postgres_or/src/test/regress/regression.diffs". # A copy of the test summary that you see above is saved in the file "/usr/src/postgres_or/src/test/regress/regression.out". make[1]: *** [GNUmakefile:118: check] Erro 1 make[1]: Saindo do diretório '/usr/src/postgres_or/src/test/regress' make: *** [GNUmakefile:69: check] Erro 2