From f26a327052b76701c408290423064b46b8660e30 Mon Sep 17 00:00:00 2001 From: Marina Polyakova Date: Thu, 24 May 2018 14:07:13 +0300 Subject: [PATCH v9] Precalculate stable and immutable functions: planner Now in Postgresql only immutable functions are precalculated; stable functions are calculated for every row so in fact they don't differ from volatile functions. In this patch the function / operator / another expression is precalculated (= calculated once for all output rows, but as many times as the expression is mentioned in the query) if: 1) it doesn't return a set, 2) it's not volatile itself, 3) its arguments are also constants or precalculated expressions. Costs are changed to reflect the changed behaviour. Tests and small notes in the documentation are included. Note: caching of domain constraints is not currently supported, as we cannot assume that the planner has access to the same domain constraints that will apply at runtime. --- contrib/postgres_fdw/deparse.c | 11 + doc/src/sgml/ref/create_function.sgml | 14 + doc/src/sgml/xfunc.sgml | 13 +- src/backend/catalog/dependency.c | 7 + src/backend/commands/explain.c | 2 +- src/backend/commands/tablecmds.c | 2 + src/backend/executor/execExpr.c | 5 + src/backend/executor/nodeAgg.c | 5 + src/backend/executor/nodeHashjoin.c | 1 + src/backend/executor/nodeIndexscan.c | 20 +- src/backend/executor/nodeMergejoin.c | 1 + src/backend/executor/nodeSubplan.c | 5 +- src/backend/executor/nodeTidscan.c | 2 +- src/backend/nodes/makefuncs.c | 26 + src/backend/nodes/nodeFuncs.c | 52 +- src/backend/optimizer/path/allpaths.c | 8 + src/backend/optimizer/path/clausesel.c | 23 +- src/backend/optimizer/path/costsize.c | 24 + src/backend/optimizer/path/equivclass.c | 48 +- src/backend/optimizer/path/indxpath.c | 44 +- src/backend/optimizer/path/joinrels.c | 10 +- src/backend/optimizer/path/tidpath.c | 8 +- src/backend/optimizer/plan/analyzejoins.c | 8 +- src/backend/optimizer/plan/createplan.c | 37 +- src/backend/optimizer/plan/initsplan.c | 19 +- src/backend/optimizer/plan/planner.c | 24 + src/backend/optimizer/plan/setrefs.c | 32 +- src/backend/optimizer/plan/subselect.c | 96 +- src/backend/optimizer/prep/prepjointree.c | 13 +- src/backend/optimizer/prep/prepqual.c | 144 +- src/backend/optimizer/prep/prepunion.c | 5 + src/backend/optimizer/util/clauses.c | 1364 ++++- src/backend/optimizer/util/orclauses.c | 23 +- src/backend/optimizer/util/predtest.c | 118 +- src/backend/optimizer/util/relnode.c | 1 + src/backend/optimizer/util/restrictinfo.c | 20 +- src/backend/optimizer/util/tlist.c | 12 +- src/backend/optimizer/util/var.c | 40 + src/backend/parser/parse_coerce.c | 6 + src/backend/partitioning/partprune.c | 71 +- src/backend/rewrite/rewriteManip.c | 9 + src/backend/statistics/dependencies.c | 10 +- src/backend/utils/adt/datetime.c | 1 + src/backend/utils/adt/numeric.c | 1 + src/backend/utils/adt/ruleutils.c | 81 +- src/backend/utils/adt/selfuncs.c | 51 +- src/backend/utils/adt/timestamp.c | 1 + src/backend/utils/adt/varbit.c | 1 + src/backend/utils/adt/varchar.c | 1 + src/backend/utils/fmgr/funcapi.c | 26 +- src/include/nodes/makefuncs.h | 2 + src/include/optimizer/clauses.h | 18 +- src/pl/plpgsql/src/pl_exec.c | 46 +- .../expected/precalculate_stable_functions.out | 6122 ++++++++++++++++++++ .../expected/precalculate_stable_functions_1.out | 5768 ++++++++++++++++++ src/test/regress/parallel_schedule | 2 +- src/test/regress/serial_schedule | 1 + .../regress/sql/precalculate_stable_functions.sql | 1932 ++++++ 58 files changed, 16007 insertions(+), 430 deletions(-) create mode 100644 src/test/regress/expected/precalculate_stable_functions.out create mode 100644 src/test/regress/expected/precalculate_stable_functions_1.out create mode 100644 src/test/regress/sql/precalculate_stable_functions.sql diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c index d272719..aae74f3 100644 --- a/contrib/postgres_fdw/deparse.c +++ b/contrib/postgres_fdw/deparse.c @@ -775,6 +775,14 @@ foreign_expr_walker(Node *node, state = FDW_COLLATE_UNSAFE; } break; + case T_CachedExpr: + { + CachedExpr *cachedexpr = (CachedExpr *) node; + + return foreign_expr_walker((Node *) cachedexpr->subexpr, + glob_cxt, outer_cxt); + } + break; default: /* @@ -2305,6 +2313,9 @@ deparseExpr(Expr *node, deparse_expr_cxt *context) case T_Aggref: deparseAggref((Aggref *) node, context); break; + case T_CachedExpr: + deparseExpr((Expr *) ((CachedExpr *) node)->subexpr, context); + break; default: elog(ERROR, "unsupported expression type for deparse: %d", (int) nodeTag(node)); diff --git a/doc/src/sgml/ref/create_function.sgml b/doc/src/sgml/ref/create_function.sgml index c0adb8c..21e2f5f 100644 --- a/doc/src/sgml/ref/create_function.sgml +++ b/doc/src/sgml/ref/create_function.sgml @@ -336,6 +336,20 @@ CREATE [ OR REPLACE ] FUNCTION setval(). + + + Stable, immutable functions and other nonvolatile expressions are + precalculated (= calculated once for all output rows, but as many times + as expression is mentioned in query), if they don't return a set and + their arguments are constants or recursively precalculated expressions. + + + + Now this feature is not supported for domain constraints (see ). + + + For additional details see . diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml index bbc3766..169513f 100644 --- a/doc/src/sgml/xfunc.sgml +++ b/doc/src/sgml/xfunc.sgml @@ -1533,9 +1533,20 @@ CREATE FUNCTION test(int, int) RETURNS int For best optimization results, you should label your functions with the - strictest volatility category that is valid for them. + strictest volatility category that is valid for them. Stable, immutable + functions and other nonvolatile expressions are precalculated (= calculated + once for all output rows, but as many times as expression is mentioned in + query), if they don't return a set and their arguments are constants or + recursively precalculated expressions. + + + Now this feature is not supported for domain constraints (see ). + + + Any function with side-effects must be labeled VOLATILE, so that calls to it cannot be optimized away. diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 4f1d365..cf3cc91 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -2027,6 +2027,13 @@ find_expr_references_walker(Node *node, context->addrs); /* fall through to examine arguments */ } + else if (IsA(node, CachedExpr)) + { + CachedExpr *cachedexpr = (CachedExpr *) node; + + return find_expr_references_walker((Node *) cachedexpr->subexpr, + context); + } return expression_tree_walker(node, find_expr_references_walker, (void *) context); diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 73d94b7..bdf9a74 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -1589,7 +1589,7 @@ ExplainNode(PlanState *planstate, List *ancestors, List *tidquals = ((TidScan *) plan)->tidquals; if (list_length(tidquals) > 1) - tidquals = list_make1(make_orclause(tidquals)); + tidquals = list_make1(make_orclause(tidquals, false)); show_scan_qual(tidquals, "TID Cond", planstate, ancestors, es); show_scan_qual(plan->qual, "Filter", planstate, ancestors, es); if (plan->qual) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 5cc9cf2..cdd3faa 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -9305,6 +9305,8 @@ ATColumnChangeRequiresRewrite(Node *expr, AttrNumber varattno) return true; expr = (Node *) d->arg; } + else if (IsA(expr, CachedExpr)) + expr = (Node *) ((CachedExpr *) expr)->subexpr; else return true; } diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index 55996ff..6bbf784 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -2432,6 +2432,11 @@ get_last_attnums_walker(Node *node, LastAttnumInfo *info) return false; if (IsA(node, GroupingFunc)) return false; + + /* Don't examine cached expressions since they do not contain vars */ + if (IsA(node, CachedExpr)) + return false; + return expression_tree_walker(node, get_last_attnums_walker, (void *) info); } diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 7781e87..bd56a1b 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -1240,6 +1240,11 @@ find_unaggregated_cols_walker(Node *node, Bitmapset **colnos) /* do not descend into aggregate exprs */ return false; } + if (IsA(node, CachedExpr)) + { + /* do not descend into cached exprs since they do not contain vars */ + return false; + } return expression_tree_walker(node, find_unaggregated_cols_walker, (void *) colnos); } diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index 23215a9..97dfe30 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -729,6 +729,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags) hoperators = NIL; foreach(l, node->hashclauses) { + /* this is not used for pseudoconstants */ OpExpr *hclause = lfirst_node(OpExpr, l); lclauses = lappend(lclauses, ExecInitExpr(linitial(hclause->args), diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 404c61e..97c5830 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -1230,6 +1230,10 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, int indnkeyatts; indnkeyatts = IndexRelationGetNumberOfKeyAttributes(index); + + /* + * do not check for cached expressions because they do not contain vars + */ if (IsA(clause, OpExpr)) { /* indexkey op const or indexkey op expression */ @@ -1276,8 +1280,8 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, */ rightop = (Expr *) get_rightop(clause); - if (rightop && IsA(rightop, RelabelType)) - rightop = ((RelabelType *) rightop)->arg; + if (rightop && IsAIfCached(rightop, RelabelType)) + rightop = castNodeIfCached(RelabelType, rightop)->arg; Assert(rightop != NULL); @@ -1406,8 +1410,12 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, rightop = (Expr *) lfirst(rargs_cell); rargs_cell = lnext(rargs_cell); - if (rightop && IsA(rightop, RelabelType)) - rightop = ((RelabelType *) rightop)->arg; + /* + * Do not check for cached expressions because index expressions + * can only contain immutable functions. + */ + if (rightop && IsAIfCached(rightop, RelabelType)) + rightop = castNodeIfCached(RelabelType, rightop)->arg; Assert(rightop != NULL); @@ -1520,8 +1528,8 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, */ rightop = (Expr *) lsecond(saop->args); - if (rightop && IsA(rightop, RelabelType)) - rightop = ((RelabelType *) rightop)->arg; + if (rightop && IsAIfCached(rightop, RelabelType)) + rightop = castNodeIfCached(RelabelType, rightop)->arg; Assert(rightop != NULL); diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index 93d91ff..cd4dc65 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -201,6 +201,7 @@ MJExamineQuals(List *mergeclauses, Oid op_righttype; Oid sortfunc; + /* This is not used for pseudoconstants */ if (!IsA(qual, OpExpr)) elog(ERROR, "mergejoin clause is not an OpExpr"); diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index 2c0addf..f077796 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -871,13 +871,15 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent) * * We also extract the combining operators themselves to initialize * the equality and hashing functions for the hash tables. + * + * This is not used for pseudoconstants. */ if (IsA(subplan->testexpr, OpExpr)) { /* single combining operator */ oplist = list_make1(subplan->testexpr); } - else if (and_clause((Node *) subplan->testexpr)) + else if (and_clause((Node *) subplan->testexpr, false)) { /* multiple combining operators */ oplist = castNode(BoolExpr, subplan->testexpr)->args; @@ -900,6 +902,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent) i = 1; foreach(l, oplist) { + /* This is not used for pseudoconstants */ OpExpr *opexpr = lfirst_node(OpExpr, l); Expr *expr; TargetEntry *tle; diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c index 8c8c53d..689d0af 100644 --- a/src/backend/executor/nodeTidscan.c +++ b/src/backend/executor/nodeTidscan.c @@ -74,7 +74,7 @@ TidExprListCreate(TidScanState *tidstate) Expr *expr = (Expr *) lfirst(l); TidExpr *tidexpr = (TidExpr *) palloc0(sizeof(TidExpr)); - if (is_opclause(expr)) + if (is_opclause((Node *) expr, false)) { Node *arg1; Node *arg2; diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index 1bd2599..f1add53 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -628,3 +628,29 @@ makeVacuumRelation(RangeVar *relation, Oid oid, List *va_cols) v->va_cols = va_cols; return v; } + +/* + * makeCachedExpr - + * create a CachedExpr node. + * + * This is an auxiliary function for other functions: checking that this + * subexpression can be cached is performed earlier in them. + * + * Pass subexpr as NULL to get a dummy cached expression (for example, cached + * case_val in eval_const_expressions_mutator). + * + * NOTE: the cached ids of all non-internal cached expressions must be set by + * the function set_non_internal_cachedexprs_walker after all mutations. + * Otherwise all the created cached expressions are considered internal and will + * not be cached by themselves. + */ +CachedExpr * +makeCachedExpr(CacheableExpr *subexpr) +{ + CachedExpr *cachedexpr = makeNode(CachedExpr); + + cachedexpr->subexpr = subexpr; + cachedexpr->cached_id = -1; + + return cachedexpr; +} diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 9fdd738..54a3780 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -598,30 +598,55 @@ exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod) * This is primarily intended to be used during planning. Therefore, it * strips any existing RelabelType nodes to maintain the planner's invariant * that there are not adjacent RelabelTypes. + * + * NOTE: if the expression contains cached expressions, it should be processed + * using set_non_internal_cachedexprs_walker to store all non-internal cached + * expressions separatly for the executor's purposes. Otherwise all the created + * cached expressions are considered internal and will not be cached by + * themselves. */ Node * relabel_to_typmod(Node *expr, int32 typmod) { Oid type = exprType(expr); Oid coll = exprCollation(expr); + bool cached = false; + Node *result; - /* Strip any existing RelabelType node(s) */ - while (expr && IsA(expr, RelabelType)) - expr = (Node *) ((RelabelType *) expr)->arg; + /* Strip any existing (and possibly cached) RelabelType node(s) */ + while (expr && IsAIfCached(expr, RelabelType)) + { + cached |= IsA(expr, CachedExpr); + expr = (Node *) castNodeIfCached(RelabelType, expr)->arg; + } /* Apply new typmod, preserving the previous exposed type and collation */ - return (Node *) makeRelabelType((Expr *) expr, type, typmod, coll, - COERCE_EXPLICIT_CAST); + result = (Node *) makeRelabelType((Expr *) expr, type, typmod, coll, + COERCE_EXPLICIT_CAST); + + /* Cache it if it was cached in the original node */ + if (cached) + result = (Node *) makeCachedExpr((CacheableExpr *) result); + + return result; } /* * strip_implicit_coercions: remove implicit coercions at top level of tree * * This doesn't modify or copy the input expression tree, just return a - * pointer to a suitable place within it. + * pointer to a suitable place within it. But if necessary it creates a new + * CachedExpr node since the original node can be used elsewhere as an internal + * cached expression. * * Note: there isn't any useful thing we can do with a RowExpr here, so * just return it unchanged, even if it's marked as an implicit coercion. + * + * NOTE: if the expression contains cached expressions, it should be processed + * using set_non_internal_cachedexprs_walker to store all non-internal cached + * expressions separatly for the executor's purposes. Otherwise all the created + * cached expressions are considered internal and will not be cached by + * themselves. */ Node * strip_implicit_coercions(Node *node) @@ -670,6 +695,21 @@ strip_implicit_coercions(Node *node) if (c->coercionformat == COERCE_IMPLICIT_CAST) return strip_implicit_coercions((Node *) c->arg); } + else if (IsA(node, CachedExpr)) + { + Node *result = strip_implicit_coercions( + (Node *) ((CachedExpr *) node)->subexpr); + + /* + * If necessary, cache the result node. Create a new CachedExpr node + * since the original node can be used elsewhere as an internal cached + * expression. + */ + if (IsA(result, Const) || IsA(result, CachedExpr)) + return result; + else + return (Node *) makeCachedExpr((CacheableExpr *) result); + } return node; } diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 477b9f7..f0b39ad 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -1091,6 +1091,14 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, /* tell createplan.c to check for gating quals */ root->hasPseudoConstantQuals = true; } + + /* + * Store all non-internal cached expressions separatly for the + * executor's purposes. + */ + set_non_internal_cachedexprs_walker(onecq, + &(root->glob->cachedExprs)); + /* reconstitute RestrictInfo with appropriate properties */ childquals = lappend(childquals, make_restrictinfo((Expr *) onecq, diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c index f471794..3b35c93 100644 --- a/src/backend/optimizer/path/clausesel.c +++ b/src/backend/optimizer/path/clausesel.c @@ -192,7 +192,8 @@ clauselist_selectivity(PlannerInfo *root, * the simple way we are expecting.) Most of the tests here can be * done more efficiently with rinfo than without. */ - if (is_opclause(clause) && list_length(((OpExpr *) clause)->args) == 2) + if (is_opclause(clause, false) && + list_length(((OpExpr *) clause)->args) == 2) { OpExpr *expr = (OpExpr *) clause; bool varonleft = true; @@ -688,7 +689,7 @@ clause_selectivity(PlannerInfo *root, /* XXX any way to do better than default? */ } } - else if (not_clause(clause)) + else if (not_clause(clause, false)) { /* inverse of the selectivity of the underlying clause */ s1 = 1.0 - clause_selectivity(root, @@ -697,7 +698,7 @@ clause_selectivity(PlannerInfo *root, jointype, sjinfo); } - else if (and_clause(clause)) + else if (and_clause(clause, false)) { /* share code with clauselist_selectivity() */ s1 = clauselist_selectivity(root, @@ -706,7 +707,7 @@ clause_selectivity(PlannerInfo *root, jointype, sjinfo); } - else if (or_clause(clause)) + else if (or_clause(clause, false)) { /* * Selectivities for an OR clause are computed as s1+s2 - s1*s2 to @@ -728,7 +729,7 @@ clause_selectivity(PlannerInfo *root, s1 = s1 + s2 - s1 * s2; } } - else if (is_opclause(clause) || IsA(clause, DistinctExpr)) + else if (is_opclause(clause, false) || IsA(clause, DistinctExpr)) { OpExpr *opclause = (OpExpr *) clause; Oid opno = opclause->opno; @@ -827,6 +828,18 @@ clause_selectivity(PlannerInfo *root, jointype, sjinfo); } + else if (IsA(clause, CachedExpr)) + { + /* + * Not sure this case is needed, but it can't hurt. + * Calculate selectivity of subexpression. + */ + s1 = clause_selectivity(root, + (Node *) ((CachedExpr *) clause)->subexpr, + varRelid, + jointype, + sjinfo); + } else { /* diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index a2a7e0c..ecd3a25 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -1205,6 +1205,9 @@ cost_tidscan(Path *path, PlannerInfo *root, ntuples = 0; foreach(l, tidquals) { + /* This is not used for pseudoconstants */ + Assert(!IsA(lfirst(l), CachedExpr)); + if (IsA(lfirst(l), ScalarArrayOpExpr)) { /* Each element of the array yields 1 tuple */ @@ -3973,6 +3976,27 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context) */ return false; } + else if (IsA(node, CachedExpr)) + { + /* + * Calculate subexpression cost as usual and add it to startup cost + * (because subexpression will be executed only once for all tuples). + */ + cost_qual_eval_context subexpr_context; + + subexpr_context.root = context->root; + subexpr_context.total.startup = 0; + subexpr_context.total.per_tuple = 0; + + cost_qual_eval_walker((Node *) ((CachedExpr *) node)->subexpr, + &subexpr_context); + + context->total.startup += + (subexpr_context.total.startup + subexpr_context.total.per_tuple); + + /* do NOT recurse into children */ + return false; + } /* recurse into children */ return expression_tree_walker(node, cost_qual_eval_walker, diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index b22b36e..4dc44c9 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -143,7 +143,10 @@ process_equivalence(PlannerInfo *root, return false; /* Extract info from given clause */ - Assert(is_opclause(clause)); + + /* This is not used for pseudoconstants */ + Assert(is_opclause((Node *) clause, false)); + opno = ((OpExpr *) clause)->opno; collation = ((OpExpr *) clause)->inputcollid; item1 = (Expr *) get_leftop(clause); @@ -488,12 +491,19 @@ process_equivalence(PlannerInfo *root, * * Note this code assumes that the expression has already been through * eval_const_expressions, so there are no CollateExprs and no redundant - * RelabelTypes. + * RelabelTypes, but there may be cached expressions. + * + * NOTE: the expression should be processed using + * set_non_internal_cachedexprs_walker to store all non-internal cached + * expressions separatly for the executor's purposes. Otherwise all the created + * cached expressions are considered internal and will not be cached by + * themselves. */ Expr * canonicalize_ec_expression(Expr *expr, Oid req_type, Oid req_collation) { Oid expr_type = exprType((Node *) expr); + bool cached = false; /* * For a polymorphic-input-type opclass, just keep the same exposed type. @@ -509,16 +519,20 @@ canonicalize_ec_expression(Expr *expr, Oid req_type, Oid req_collation) exprCollation((Node *) expr) != req_collation) { /* - * Strip any existing RelabelType, then add a new one if needed. This - * is to preserve the invariant of no redundant RelabelTypes. + * Strip any existing (and possibly cached) RelabelType, then add a new + * one if needed. This is to preserve the invariant of no redundant + * RelabelTypes. * * If we have to change the exposed type of the stripped expression, * set typmod to -1 (since the new type may not have the same typmod * interpretation). If we only have to change collation, preserve the * exposed typmod. */ - while (expr && IsA(expr, RelabelType)) - expr = (Expr *) ((RelabelType *) expr)->arg; + while (expr && IsAIfCached(expr, RelabelType)) + { + cached |= IsA(expr, CachedExpr); + expr = castNodeIfCached(RelabelType, expr)->arg; + } if (exprType((Node *) expr) != req_type) expr = (Expr *) makeRelabelType(expr, @@ -532,6 +546,10 @@ canonicalize_ec_expression(Expr *expr, Oid req_type, Oid req_collation) exprTypmod((Node *) expr), req_collation, COERCE_IMPLICIT_CAST); + + /* Cache the new node if it was cached in the original expression */ + if (cached && !IsA(expr, CachedExpr)) + expr = (Expr *) makeCachedExpr((CacheableExpr *) expr); } return expr; @@ -1205,7 +1223,8 @@ generate_join_implied_equalities_normal(PlannerInfo *root, * choices, we prefer simple Var members (possibly with RelabelType) since * these are (a) cheapest to compute at runtime and (b) most likely to * have useful statistics. Also, prefer operators that are also - * hashjoinable. + * hashjoinable. Ignore cached RelabelTypes because they do not contain + * vars. */ if (outer_members && inner_members) { @@ -1693,7 +1712,9 @@ reconsider_outer_join_clause(PlannerInfo *root, RestrictInfo *rinfo, inner_nullable_relids; ListCell *lc1; - Assert(is_opclause(rinfo->clause)); + /* This is not used for pseudoconstants */ + Assert(is_opclause((Node *) rinfo->clause, false)); + opno = ((OpExpr *) rinfo->clause)->opno; collation = ((OpExpr *) rinfo->clause)->inputcollid; @@ -1823,7 +1844,10 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo) return false; /* Extract needed info from the clause */ - Assert(is_opclause(rinfo->clause)); + + /* This is not used for pseudoconstants */ + Assert(is_opclause((Node *) rinfo->clause, false)); + opno = ((OpExpr *) rinfo->clause)->opno; collation = ((OpExpr *) rinfo->clause)->inputcollid; op_input_types(opno, &left_type, &right_type); @@ -1875,9 +1899,10 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo) { coal_em = (EquivalenceMember *) lfirst(lc2); Assert(!coal_em->em_is_child); /* no children yet */ - if (IsA(coal_em->em_expr, CoalesceExpr)) + if (IsAIfCached(coal_em->em_expr, CoalesceExpr)) { - CoalesceExpr *cexpr = (CoalesceExpr *) coal_em->em_expr; + CoalesceExpr *cexpr = castNodeIfCached(CoalesceExpr, + coal_em->em_expr); Node *cfirst; Node *csecond; @@ -2061,6 +2086,7 @@ match_eclasses_to_foreign_key_col(PlannerInfo *root, continue; /* ignore children here */ /* EM must be a Var, possibly with RelabelType */ + /* Ignore cached RelabelTypes because they do not contain vars */ var = (Var *) em->em_expr; while (var && IsA(var, RelabelType)) var = (Var *) ((RelabelType *) var)->arg; diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index f295558..d72542a 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -928,6 +928,9 @@ build_index_paths(PlannerInfo *root, RelOptInfo *rel, { RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc); + /* This is not used for pseudoconstants */ + Assert(!IsA(rinfo->clause, CachedExpr)); + if (IsA(rinfo->clause, ScalarArrayOpExpr)) { if (!index->amsearcharray) @@ -1284,6 +1287,9 @@ generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel, if (!restriction_is_or_clause(rinfo)) continue; + /* Its leaves are RestrictInfos and they are not cacheable */ + Assert(!IsA(rinfo->orclause, CachedExpr)); + /* * We must be able to match at least one index to each of the arms of * the OR, else we can't use it. @@ -1294,8 +1300,8 @@ generate_bitmap_or_paths(PlannerInfo *root, RelOptInfo *rel, Node *orarg = (Node *) lfirst(j); List *indlist; - /* OR arguments should be ANDs or sub-RestrictInfos */ - if (and_clause(orarg)) + /* OR arguments should be non-cached ANDs or sub-RestrictInfos */ + if (and_clause(orarg, false)) { List *andargs = ((BoolExpr *) orarg)->args; @@ -2344,6 +2350,9 @@ match_clause_to_indexcol(IndexOptInfo *index, opfamily = index->opfamily[indexcol]; idxcollation = index->indexcollations[indexcol]; + /* This is not used for pseudoconstants. */ + Assert(!IsA(clause, CachedExpr)); + /* First check for boolean-index cases. */ if (IsBooleanOpfamily(opfamily)) { @@ -2357,7 +2366,7 @@ match_clause_to_indexcol(IndexOptInfo *index, * RowCompareExpr, which we pass off to match_rowcompare_to_indexcol(). * Or, if the index supports it, we can handle IS NULL/NOT NULL clauses. */ - if (is_opclause(clause)) + if (is_opclause((Node *) clause, false)) { leftop = get_leftop(clause); rightop = get_rightop(clause); @@ -2698,9 +2707,9 @@ match_clause_to_ordering_op(IndexOptInfo *index, idxcollation = index->indexcollations[indexcol]; /* - * Clause must be a binary opclause. + * Clause must be a binary non-cached opclause. */ - if (!is_opclause(clause)) + if (!is_opclause((Node *) clause, false)) return NULL; leftop = get_leftop(clause); rightop = get_rightop(clause); @@ -3215,8 +3224,8 @@ match_index_to_operand(Node *operand, * we can assume there is at most one RelabelType node; * eval_const_expressions() will have simplified if more than one. */ - if (operand && IsA(operand, RelabelType)) - operand = (Node *) ((RelabelType *) operand)->arg; + if (operand && IsAIfCached(operand, RelabelType)) + operand = (Node *) castNodeIfCached(RelabelType, operand)->arg; indkey = index->indexkeys[indexcol]; if (indkey != 0) @@ -3255,6 +3264,11 @@ match_index_to_operand(Node *operand, indexkey = (Node *) lfirst(indexpr_item); /* + * Index expressions can only contain immutable functions. + */ + Assert(!IsA(indexkey, CachedExpr)); + + /* * Does it match the operand? Again, strip any relabeling. */ if (indexkey && IsA(indexkey, RelabelType)) @@ -3333,11 +3347,14 @@ match_boolean_index_clause(Node *clause, int indexcol, IndexOptInfo *index) { + /* This is not used for pseudoconstants. */ + Assert(!IsA(clause, CachedExpr)); + /* Direct match? */ if (match_index_to_operand(clause, indexcol, index)) return true; /* NOT clause? */ - if (not_clause(clause)) + if (not_clause(clause, false)) { if (match_index_to_operand((Node *) get_notclausearg((Expr *) clause), indexcol, index)) @@ -3589,10 +3606,10 @@ expand_indexqual_conditions(IndexOptInfo *index, } /* - * Else it must be an opclause (usual case), ScalarArrayOp, - * RowCompare, or NullTest + * Else it must be an non-cached clause: opclause (usual case), + * ScalarArrayOp, RowCompare, or NullTest */ - if (is_opclause(clause)) + if (is_opclause((Node *) clause, false)) { indexquals = list_concat(indexquals, expand_indexqual_opclause(rinfo, @@ -3643,6 +3660,9 @@ expand_boolean_index_clause(Node *clause, int indexcol, IndexOptInfo *index) { + /* This is not used for pseudoconstants. */ + Assert(!IsA(clause, CachedExpr)); + /* Direct match? */ if (match_index_to_operand(clause, indexcol, index)) { @@ -3653,7 +3673,7 @@ expand_boolean_index_clause(Node *clause, InvalidOid, InvalidOid); } /* NOT clause? */ - if (not_clause(clause)) + if (not_clause(clause, false)) { Node *arg = (Node *) get_notclausearg((Expr *) clause); diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index 7008e13..58328c9 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -1447,7 +1447,10 @@ have_partkey_equi_join(RelOptInfo *joinrel, RINFO_IS_PUSHED_DOWN(rinfo, joinrel->relids)) continue; - /* Skip clauses which can not be used for a join. */ + /* + * Skip clauses which can not be used for a join (including cached + * expressions). + */ if (!rinfo->can_join) continue; @@ -1456,7 +1459,7 @@ have_partkey_equi_join(RelOptInfo *joinrel, continue; opexpr = (OpExpr *) rinfo->clause; - Assert(is_opclause(opexpr)); + Assert(is_opclause((Node *) opexpr, false)); /* * The equi-join between partition keys is strict if equi-join between @@ -1544,6 +1547,9 @@ match_expr_to_partition_keys(Expr *expr, RelOptInfo *rel, bool strict_op) while (IsA(expr, RelabelType)) expr = (Expr *) (castNode(RelabelType, expr))->arg; + /* This is not used for pseudoconstants. */ + Assert(!IsA(expr, CachedExpr)); + for (cnt = 0; cnt < rel->part_scheme->partnatts; cnt++) { ListCell *lc; diff --git a/src/backend/optimizer/path/tidpath.c b/src/backend/optimizer/path/tidpath.c index 3bb5b8d..a8ef71c 100644 --- a/src/backend/optimizer/path/tidpath.c +++ b/src/backend/optimizer/path/tidpath.c @@ -162,6 +162,8 @@ IsTidEqualAnyClause(ScalarArrayOpExpr *node, int varno) * sub-clauses, in which case we could try to pick the most efficient one. * In practice, such usage seems very unlikely, so we don't bother; we * just exit as soon as we find the first candidate. + * + * Do not check for cached expressions because they do not contain vars. */ static List * TidQualFromExpr(Node *expr, int varno) @@ -169,7 +171,7 @@ TidQualFromExpr(Node *expr, int varno) List *rlst = NIL; ListCell *l; - if (is_opclause(expr)) + if (is_opclause(expr, false)) { /* base case: check for tideq opclause */ if (IsTidEqualClause((OpExpr *) expr, varno)) @@ -187,7 +189,7 @@ TidQualFromExpr(Node *expr, int varno) if (((CurrentOfExpr *) expr)->cvarno == varno) rlst = list_make1(expr); } - else if (and_clause(expr)) + else if (and_clause(expr, false)) { foreach(l, ((BoolExpr *) expr)->args) { @@ -196,7 +198,7 @@ TidQualFromExpr(Node *expr, int varno) break; } } - else if (or_clause(expr)) + else if (or_clause(expr, false)) { foreach(l, ((BoolExpr *) expr)->args) { diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c index 0e73f9c..385b1cc 100644 --- a/src/backend/optimizer/plan/analyzejoins.c +++ b/src/backend/optimizer/plan/analyzejoins.c @@ -693,7 +693,7 @@ rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel, List *clause_list) * same operator the subquery would consider; that's all right * since query_is_distinct_for can resolve such cases.) The * caller's mergejoinability test should have selected only - * OpExprs. + * non-cached OpExprs. */ op = castNode(OpExpr, rinfo->clause)->opno; @@ -712,6 +712,12 @@ rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel, List *clause_list) var = (Var *) ((RelabelType *) var)->arg; /* + * Pseudoconstant operands do not pass the caller's mergejoinability + * test. + */ + Assert(!IsA(var, CachedExpr)); + + /* * If inner side isn't a Var referencing a subquery output column, * this clause doesn't help us. */ diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index ca2e052..e711ae9 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -3050,13 +3050,13 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, else if (list_length(subquals) <= 1) *qual = subquals; else - *qual = list_make1(make_orclause(subquals)); + *qual = list_make1(make_orclause(subquals, false)); if (const_true_subindexqual) *indexqual = NIL; else if (list_length(subindexquals) <= 1) *indexqual = subindexquals; else - *indexqual = list_make1(make_orclause(subindexquals)); + *indexqual = list_make1(make_orclause(subindexquals, false)); *indexECs = NIL; } else if (IsA(bitmapqual, IndexPath)) @@ -3160,7 +3160,7 @@ create_tidscan_plan(PlannerInfo *root, TidPath *best_path, */ ortidquals = tidquals; if (list_length(ortidquals) > 1) - ortidquals = list_make1(make_orclause(ortidquals)); + ortidquals = list_make1(make_orclause(ortidquals, false)); scan_clauses = list_difference(scan_clauses, ortidquals); scan_plan = make_tidscan(tlist, @@ -4266,7 +4266,9 @@ create_hashjoin_plan(PlannerInfo *root, OpExpr *clause = (OpExpr *) linitial(hashclauses); Node *node; - Assert(is_opclause(clause)); + /* This is not used for pseudoconstants */ + Assert(is_opclause((Node *) clause, false)); + node = (Node *) linitial(clause->args); if (IsA(node, RelabelType)) node = (Node *) ((RelabelType *) node)->arg; @@ -4449,6 +4451,11 @@ replace_nestloop_params_mutator(Node *node, PlannerInfo *root) /* And return the replacement Param */ return (Node *) param; } + if (IsA(node, CachedExpr)) + { + /* Don't examine cached expressions since they do not contain vars */ + return copyObject(node); + } return expression_tree_mutator(node, replace_nestloop_params_mutator, (void *) root); @@ -4757,8 +4764,8 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index, int indexcol) /* * Remove any binary-compatible relabeling of the indexkey */ - if (IsA(node, RelabelType)) - node = (Node *) ((RelabelType *) node)->arg; + if (IsAIfCached(node, RelabelType)) + node = (Node *) castNodeIfCached(RelabelType, node)->arg; Assert(indexcol >= 0 && indexcol < index->ncolumns); @@ -4791,8 +4798,13 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index, int indexcol) Node *indexkey; indexkey = (Node *) lfirst(indexpr_item); + + /* Index expressions can only contain immutable functions */ + Assert(!IsA(indexkey, CachedExpr)); + if (indexkey && IsA(indexkey, RelabelType)) indexkey = (Node *) ((RelabelType *) indexkey)->arg; + if (equal(node, indexkey)) { result = makeVar(INDEX_VAR, indexcol + 1, @@ -4833,7 +4845,9 @@ get_switched_clauses(List *clauses, Relids outerrelids) RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l); OpExpr *clause = (OpExpr *) restrictinfo->clause; - Assert(is_opclause(clause)); + /* This is not used for pseudoconstants */ + Assert(is_opclause((Node *) clause, false)); + if (bms_is_subset(restrictinfo->right_relids, outerrelids)) { /* @@ -5924,7 +5938,11 @@ find_ec_member_for_tle(EquivalenceClass *ec, Expr *tlexpr; ListCell *lc; - /* We ignore binary-compatible relabeling on both ends */ + /* + * We ignore binary-compatible relabeling on both ends. + * Do not worry about cached expressions because in any case they cannot be + * equal to the non-pseudoconstant member of EquivalenceClass (see below). + */ tlexpr = tle->expr; while (tlexpr && IsA(tlexpr, RelabelType)) tlexpr = ((RelabelType *) tlexpr)->arg; @@ -5936,7 +5954,8 @@ find_ec_member_for_tle(EquivalenceClass *ec, /* * We shouldn't be trying to sort by an equivalence class that - * contains a constant, so no need to consider such cases any further. + * contains a constant (including cached expressions), so no need to + * consider such cases any further. */ if (em->em_is_const) continue; diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 01335db..498ef41 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -1481,7 +1481,7 @@ compute_semijoin_info(SpecialJoinInfo *sjinfo, List *clause) Relids all_varnos; Oid opinputtype; - /* Is it a binary opclause? */ + /* Is it a binary non-cached opclause? */ if (!IsA(op, OpExpr) || list_length(op->args) != 2) { @@ -1503,7 +1503,7 @@ compute_semijoin_info(SpecialJoinInfo *sjinfo, List *clause) return; } - /* Extract data from binary opclause */ + /* Extract data from binary non-cached opclause */ opno = op->opno; left_expr = linitial(op->args); right_expr = lsecond(op->args); @@ -2343,6 +2343,13 @@ process_implied_equality(PlannerInfo *root, { clause = (Expr *) eval_const_expressions(root, (Node *) clause); + /* + * Store all non-internal cached expressions separatly for the + * executor's purposes. + */ + set_non_internal_cachedexprs_walker((Node *) clause, + &(root->glob->cachedExprs)); + /* If we produced const TRUE, just drop the clause */ if (clause && IsA(clause, Const)) { @@ -2517,7 +2524,9 @@ match_foreign_keys_to_quals(PlannerInfo *root) if (rinfo->outerjoin_delayed) continue; - /* Only binary OpExprs are useful for consideration */ + /* + * Only binary non-cached OpExprs are useful for consideration. + */ if (!IsA(clause, OpExpr) || list_length(clause->args) != 2) continue; @@ -2613,7 +2622,7 @@ check_mergejoinable(RestrictInfo *restrictinfo) if (restrictinfo->pseudoconstant) return; - if (!is_opclause(clause)) + if (!is_opclause((Node *) clause, false)) return; if (list_length(((OpExpr *) clause)->args) != 2) return; @@ -2650,7 +2659,7 @@ check_hashjoinable(RestrictInfo *restrictinfo) if (restrictinfo->pseudoconstant) return; - if (!is_opclause(clause)) + if (!is_opclause((Node *) clause, false)) return; if (list_length(((OpExpr *) clause)->args) != 2) return; diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 882a752..1268a67 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -276,6 +276,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) Plan *top_plan; ListCell *lp, *lr; + ListCell *cell; /* * Set up global state for this planner invocation. This data is needed @@ -506,6 +507,15 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) lfirst(lp) = set_plan_references(subroot, subplan); } + /* Add all non-internal cached expressions after all the PARAM_EXEC */ + foreach(cell, glob->cachedExprs) + { + CachedExpr *cachedexpr = lfirst_node(CachedExpr, cell); + + glob->paramExecTypes = lappend_oid(glob->paramExecTypes, + exprType((const Node *) cachedexpr)); + } + /* build the PlannedStmt result */ result = makeNode(PlannedStmt); @@ -532,6 +542,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) result->utilityStmt = parse->utilityStmt; result->stmt_location = parse->stmt_location; result->stmt_len = parse->stmt_len; + result->cachedExprs = glob->cachedExprs; result->jitFlags = PGJIT_NONE; if (jit_enabled && jit_above_cost >= 0 && @@ -1075,6 +1086,12 @@ preprocess_expression(PlannerInfo *root, Node *expr, int kind) if (kind == EXPRKIND_QUAL) expr = (Node *) make_ands_implicit((Expr *) expr); + /* + * Store all non-internal cached expressions separatly for the executor's + * purposes. + */ + set_non_internal_cachedexprs_walker(expr, &(root->glob->cachedExprs)); + return expr; } @@ -5898,6 +5915,13 @@ expression_planner(Expr *expr) */ result->expr = (Expr *) eval_const_expressions(NULL, (Node *) expr); + /* + * Store all non-internal cached expressions separatly for the executor's + * purposes. + */ + set_non_internal_cachedexprs_walker((Node *) result->expr, + &(result->cachedExprs)); + /* Fill in opfuncid values if missing */ fix_opfuncids((Node *) result->expr); diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 69dd327..00cbc08 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -1438,19 +1438,31 @@ fix_expr_common(PlannerInfo *root, Node *node) g->cols = cols; } } + else if (IsA(node, CachedExpr)) + { + CachedExpr *cachedexpr = (CachedExpr *) node; + + fix_expr_common(root, (Node *) cachedexpr->subexpr); + } } /* * fix_param_node - * Do set_plan_references processing on a Param + * Do set_plan_references processing on a (possibly cached) Param * * If it's a PARAM_MULTIEXPR, replace it with the appropriate Param from * root->multiexpr_params; otherwise no change is needed. * Just for paranoia's sake, we make a copy of the node in either case. */ static Node * -fix_param_node(PlannerInfo *root, Param *p) +fix_param_node(PlannerInfo *root, Node *node) { + Param *p = castNodeIfCached(Param, node); + + /* + * Do not worry about the cached expression because PARAM_MULTIEXPR cannot + * be cached. + */ if (p->paramkind == PARAM_MULTIEXPR) { int subqueryid = p->paramid >> 16; @@ -1465,7 +1477,8 @@ fix_param_node(PlannerInfo *root, Param *p) elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid); return copyObject(list_nth(params, colno - 1)); } - return (Node *) copyObject(p); + + return (Node *) copyObject(node); } /* @@ -1533,8 +1546,8 @@ fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context) var->varnoold += context->rtoffset; return (Node *) var; } - if (IsA(node, Param)) - return fix_param_node(context->root, (Param *) node); + if (IsAIfCached(node, Param)) + return fix_param_node(context->root, node); if (IsA(node, Aggref)) { Aggref *aggref = (Aggref *) node; @@ -2324,8 +2337,8 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context) /* If not supplied by input plans, evaluate the contained expr */ return fix_join_expr_mutator((Node *) phv->phexpr, context); } - if (IsA(node, Param)) - return fix_param_node(context->root, (Param *) node); + if (IsAIfCached(node, Param)) + return fix_param_node(context->root, node); /* Try matching more complex expressions too, if tlists have any */ converted_whole_row = is_converted_whole_row_reference(node); @@ -2436,8 +2449,8 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context) /* If not supplied by input plan, evaluate the contained expr */ return fix_upper_expr_mutator((Node *) phv->phexpr, context); } - if (IsA(node, Param)) - return fix_param_node(context->root, (Param *) node); + if (IsAIfCached(node, Param)) + return fix_param_node(context->root, node); if (IsA(node, Aggref)) { Aggref *aggref = (Aggref *) node; @@ -2681,6 +2694,7 @@ is_converted_whole_row_reference(Node *node) { ConvertRowtypeExpr *convexpr; + /* Ignore cached ConvertRowtypeExprs because they do not contain vars. */ if (!node || !IsA(node, ConvertRowtypeExpr)) return false; diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 83008d7..4cb1a54 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -994,6 +994,10 @@ convert_testexpr_mutator(Node *node, { if (node == NULL) return NULL; + + /* + * Do not worry about cached params because PARAM_SUBLINK cannot be cached. + */ if (IsA(node, Param)) { Param *param = (Param *) node; @@ -1068,6 +1072,9 @@ subplan_is_hashable(Plan *plan) static bool testexpr_is_hashable(Node *testexpr) { + /* This is not used for pseudoconstants. */ + Assert(!IsA(testexpr, CachedExpr)); + /* * The testexpr must be a single OpExpr, or an AND-clause containing only * OpExprs. @@ -1084,7 +1091,7 @@ testexpr_is_hashable(Node *testexpr) if (hash_ok_operator((OpExpr *) testexpr)) return true; } - else if (and_clause(testexpr)) + else if (and_clause(testexpr, false)) { ListCell *l; @@ -1092,6 +1099,9 @@ testexpr_is_hashable(Node *testexpr) { Node *andarg = (Node *) lfirst(l); + /* This is not used for pseudoconstants. */ + Assert(!IsA(andarg, CachedExpr)); + if (!IsA(andarg, OpExpr)) return false; if (!hash_ok_operator((OpExpr *) andarg)) @@ -1628,7 +1638,16 @@ simplify_EXISTS_query(PlannerInfo *root, Query *query) query->limitCount = node; if (!IsA(node, Const)) + { + /* + * Store all non-internal cached expressions separatly for the + * executor's purposes. + */ + set_non_internal_cachedexprs_walker(node, + &(root->glob->cachedExprs)); + return false; + } limit = (Const *) node; Assert(limit->consttype == INT8OID); @@ -1755,6 +1774,7 @@ convert_EXISTS_to_ANY(PlannerInfo *root, Query *subselect, { OpExpr *expr = (OpExpr *) lfirst(lc); + /* Ignore cached expressions because they do not contain vars */ if (IsA(expr, OpExpr) && hash_ok_operator(expr)) { @@ -1842,8 +1862,17 @@ convert_EXISTS_to_ANY(PlannerInfo *root, Query *subselect, * Put back any child-level-only WHERE clauses. */ if (newWhere) + { subselect->jointree->quals = (Node *) make_ands_explicit(newWhere); + /* + * Store all non-internal cached expressions separatly for the + * executor's purposes. + */ + set_non_internal_cachedexprs_walker(subselect->jointree->quals, + &(root->glob->cachedExprs)); + } + /* * Build a new targetlist for the child that emits the expressions we * need. Concurrently, build a testexpr for the parent using Params to @@ -1884,6 +1913,15 @@ convert_EXISTS_to_ANY(PlannerInfo *root, Query *subselect, *testexpr = (Node *) make_ands_explicit(testlist); *paramIds = paramids; + /* + * Store all non-internal cached expressions separatly for the executor's + * purposes. + */ + set_non_internal_cachedexprs_walker((Node *) subselect->targetList, + &(root->glob->cachedExprs)); + set_non_internal_cachedexprs_walker(*testexpr, + &(root->glob->cachedExprs)); + return subselect; } @@ -1956,6 +1994,12 @@ replace_correlation_vars_mutator(Node *node, PlannerInfo *root) * The isQual argument tells whether or not this expression is a WHERE/HAVING * qualifier expression. If it is, any sublinks appearing at top level need * not distinguish FALSE from UNKNOWN return values. + * + * NOTE: if the expression contains cached expressions, it should be processed + * using set_non_internal_cachedexprs_walker to store all non-internal cached + * expressions separatly for the executor's purposes. Otherwise all the created + * cached expressions are considered internal and will not be cached by + * themselves. */ Node * SS_process_sublinks(PlannerInfo *root, Node *expr, bool isQual) @@ -2039,46 +2083,72 @@ process_sublinks_mutator(Node *node, process_sublinks_context *context) * propagates down in both cases. (Note that this is unlike the meaning * of "top level qual" used in most other places in Postgres.) */ - if (and_clause(node)) + if (and_clause(node, true)) { List *newargs = NIL; ListCell *l; + Node *result; /* Still at qual top-level */ locContext.isTopQual = context->isTopQual; - foreach(l, ((BoolExpr *) node)->args) + foreach(l, castNodeIfCached(BoolExpr, node)->args) { Node *newarg; newarg = process_sublinks_mutator(lfirst(l), &locContext); - if (and_clause(newarg)) - newargs = list_concat(newargs, ((BoolExpr *) newarg)->args); + if (and_clause(newarg, true)) + { + newargs = list_concat(newargs, + castNodeIfCached(BoolExpr, newarg)->args); + } else + { newargs = lappend(newargs, newarg); + } } - return (Node *) make_andclause(newargs); + + result = (Node *) make_andclause(newargs, false); + + /* Cache it if the original node was cached */ + if (IsA(node, CachedExpr)) + result = (Node *) makeCachedExpr((CacheableExpr *) result); + + return result; } - if (or_clause(node)) + if (or_clause(node, true)) { List *newargs = NIL; ListCell *l; + Node *result; /* Still at qual top-level */ locContext.isTopQual = context->isTopQual; - foreach(l, ((BoolExpr *) node)->args) + foreach(l, castNodeIfCached(BoolExpr, node)->args) { Node *newarg; newarg = process_sublinks_mutator(lfirst(l), &locContext); - if (or_clause(newarg)) - newargs = list_concat(newargs, ((BoolExpr *) newarg)->args); + if (or_clause(newarg, true)) + { + newargs = list_concat(newargs, + castNodeIfCached(BoolExpr, newarg)->args); + } else + { newargs = lappend(newargs, newarg); + } } - return (Node *) make_orclause(newargs); + + result = (Node *) make_orclause(newargs, false); + + /* Cache it if the original node was cached */ + if (IsA(node, CachedExpr)) + result = (Node *) makeCachedExpr((CacheableExpr *) result); + + return result; } /* @@ -2891,6 +2961,10 @@ finalize_primnode(Node *node, finalize_primnode_context *context) { if (node == NULL) return false; + + /* + * Do not worry about cached params because PARAM_EXEC cannot be cached. + */ if (IsA(node, Param)) { if (((Param *) node)->paramkind == PARAM_EXEC) diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index c3f46a2..79aed64 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -334,6 +334,13 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node, { if (node == NULL) return NULL; + + /* + * It is assumed that we have not yet used the function + * eval_const_expressions. + */ + Assert(!IsA(node, CachedExpr)); + if (IsA(node, SubLink)) { SubLink *sublink = (SubLink *) node; @@ -452,7 +459,7 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node, /* Else return it unmodified */ return node; } - if (not_clause(node)) + if (not_clause(node, false)) { /* If the immediate argument of NOT is EXISTS, try to convert */ SubLink *sublink = (SubLink *) get_notclausearg((Expr *) node); @@ -519,7 +526,7 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node, /* Else return it unmodified */ return node; } - if (and_clause(node)) + if (and_clause(node, false)) { /* Recurse into AND clause */ List *newclauses = NIL; @@ -545,7 +552,7 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node, else if (list_length(newclauses) == 1) return (Node *) linitial(newclauses); else - return (Node *) make_andclause(newclauses); + return (Node *) make_andclause(newclauses, false); } /* Stop if not an AND */ return node; diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c index 52f8893..51e62a0 100644 --- a/src/backend/optimizer/prep/prepqual.c +++ b/src/backend/optimizer/prep/prepqual.c @@ -68,6 +68,12 @@ static Expr *process_duplicate_ors(List *orlist); * the motivations for doing this is to ensure that logically equivalent * expressions will be seen as physically equal(), so we should always apply * the same transformations. + * + * NOTE: the expression should be processed using + * set_non_internal_cachedexprs_walker to store all non-internal cached + * expressions separatly for the executor's purposes. Otherwise all the created + * cached expressions are considered internal and will not be cached by + * themselves. */ Node * negate_clause(Node *node) @@ -165,7 +171,7 @@ negate_clause(Node *node) nargs = lappend(nargs, negate_clause(lfirst(lc))); } - return (Node *) make_orclause(nargs); + return (Node *) make_orclause(nargs, false); } break; case OR_EXPR: @@ -178,7 +184,7 @@ negate_clause(Node *node) nargs = lappend(nargs, negate_clause(lfirst(lc))); } - return (Node *) make_andclause(nargs); + return (Node *) make_andclause(nargs, false); } break; case NOT_EXPR: @@ -252,6 +258,36 @@ negate_clause(Node *node) return (Node *) newexpr; } break; + case T_CachedExpr: + { + CachedExpr *expr = (CachedExpr *) node; + CacheableExpr *subexpr = expr->subexpr; + /* Try to simplify its subexpression */ + Node *newsubnode = negate_clause((Node *) subexpr); + + if (IsA(newsubnode, BoolExpr) && + ((BoolExpr *) newsubnode)->boolop == NOT_EXPR) + { + /* + * Simplifying its subexpression did not help so return the + * cached negation of the original node. Make a new + * CachedExpr node for the original subexpression since it + * may used elsewhere else as a non-internal cached + * expression. + */ + return (Node *) makeCachedExpr((CacheableExpr *) + make_notclause((Expr *) makeCachedExpr(subexpr))); + } + else + { + /* + * A simplified subexpression may be non-cacheable, so + * return it by itself. + */ + return newsubnode; + } + } + break; default: /* else fall through */ break; @@ -285,6 +321,12 @@ negate_clause(Node *node) * its own flattening logic, but that requires a useless extra pass over the * tree. * + * NOTE: the expression should be processed using + * set_non_internal_cachedexprs_walker to store all non-internal cached + * expressions separatly for the executor's purposes. Otherwise all the created + * cached expressions are considered internal and will not be cached by + * themselves. + * * Returns the modified qualification. */ Expr * @@ -333,11 +375,26 @@ pull_ands(List *andlist) * built a new arglist not shared with any other expr. Otherwise we'd * need a list_copy here. */ - if (and_clause(subexpr)) - out_list = list_concat(out_list, - pull_ands(((BoolExpr *) subexpr)->args)); + if (and_clause(subexpr, true)) + { + out_list = list_concat( + out_list, + pull_ands(castNodeIfCached(BoolExpr, subexpr)->args)); + } else + { + /* + * Make a new CachedExpr node since the source node can be used + * elsewhere as an internal cached expression. + */ + if (IsA(subexpr, CachedExpr)) + { + subexpr = + (Node *) makeCachedExpr(((CachedExpr *) subexpr)->subexpr); + } + out_list = lappend(out_list, subexpr); + } } return out_list; } @@ -365,11 +422,26 @@ pull_ors(List *orlist) * built a new arglist not shared with any other expr. Otherwise we'd * need a list_copy here. */ - if (or_clause(subexpr)) - out_list = list_concat(out_list, - pull_ors(((BoolExpr *) subexpr)->args)); + if (or_clause(subexpr, true)) + { + out_list = list_concat( + out_list, + pull_ors(castNodeIfCached(BoolExpr, subexpr)->args)); + } else + { + /* + * Make a new CachedExpr node since the source node can be used + * elsewhere as an internal cached expression. + */ + if (IsA(subexpr, CachedExpr)) + { + subexpr = + (Node* ) makeCachedExpr(((CachedExpr *) subexpr)->subexpr); + } + out_list = lappend(out_list, subexpr); + } } return out_list; } @@ -415,13 +487,13 @@ pull_ors(List *orlist) static Expr * find_duplicate_ors(Expr *qual, bool is_check) { - if (or_clause((Node *) qual)) + if (or_clause((Node *) qual, true)) { List *orlist = NIL; ListCell *temp; /* Recurse */ - foreach(temp, ((BoolExpr *) qual)->args) + foreach(temp, castNodeIfCached(BoolExpr, qual)->args) { Expr *arg = (Expr *) lfirst(temp); @@ -459,13 +531,13 @@ find_duplicate_ors(Expr *qual, bool is_check) /* Now we can look for duplicate ORs */ return process_duplicate_ors(orlist); } - else if (and_clause((Node *) qual)) + else if (and_clause((Node *) qual, true)) { List *andlist = NIL; ListCell *temp; /* Recurse */ - foreach(temp, ((BoolExpr *) qual)->args) + foreach(temp, castNodeIfCached(BoolExpr, qual)->args) { Expr *arg = (Expr *) lfirst(temp); @@ -509,7 +581,7 @@ find_duplicate_ors(Expr *qual, bool is_check) return (Expr *) linitial(andlist); /* Else we still need an AND node */ - return make_andclause(andlist); + return make_andclause(andlist, true); } else return qual; @@ -550,9 +622,9 @@ process_duplicate_ors(List *orlist) { Expr *clause = (Expr *) lfirst(temp); - if (and_clause((Node *) clause)) + if (and_clause((Node *) clause, true)) { - List *subclauses = ((BoolExpr *) clause)->args; + List *subclauses = castNodeIfCached(BoolExpr, clause)->args; int nclauses = list_length(subclauses); if (reference == NIL || nclauses < num_subclauses) @@ -588,9 +660,10 @@ process_duplicate_ors(List *orlist) { Expr *clause = (Expr *) lfirst(temp2); - if (and_clause((Node *) clause)) + if (and_clause((Node *) clause, true)) { - if (!list_member(((BoolExpr *) clause)->args, refclause)) + if (!list_member(castNodeIfCached(BoolExpr, clause)->args, + refclause)) { win = false; break; @@ -614,7 +687,7 @@ process_duplicate_ors(List *orlist) * If no winners, we can't transform the OR */ if (winners == NIL) - return make_orclause(orlist); + return make_orclause(orlist, true); /* * Generate new OR list consisting of the remaining sub-clauses. @@ -631,17 +704,22 @@ process_duplicate_ors(List *orlist) { Expr *clause = (Expr *) lfirst(temp); - if (and_clause((Node *) clause)) + if (and_clause((Node *) clause, true)) { - List *subclauses = ((BoolExpr *) clause)->args; + List *subclauses = castNodeIfCached(BoolExpr, clause)->args; subclauses = list_difference(subclauses, winners); if (subclauses != NIL) { if (list_length(subclauses) == 1) + { neworlist = lappend(neworlist, linitial(subclauses)); + } else - neworlist = lappend(neworlist, make_andclause(subclauses)); + { + neworlist = lappend(neworlist, + make_andclause(subclauses, true)); + } } else { @@ -670,9 +748,14 @@ process_duplicate_ors(List *orlist) if (neworlist != NIL) { if (list_length(neworlist) == 1) + { winners = lappend(winners, linitial(neworlist)); + } else - winners = lappend(winners, make_orclause(pull_ors(neworlist))); + { + winners = lappend(winners, + make_orclause(pull_ors(neworlist), true)); + } } /* @@ -680,7 +763,20 @@ process_duplicate_ors(List *orlist) * element and AND/OR flatness. */ if (list_length(winners) == 1) - return (Expr *) linitial(winners); + { + Expr *result = linitial(winners); + + /* + * Make a new CachedExpr node since the source node can be used + * elsewhere as an internal cached expression. + */ + if (IsA(result, CachedExpr)) + result = (Expr *) makeCachedExpr(((CachedExpr *) result)->subexpr); + + return result; + } else - return make_andclause(pull_ands(winners)); + { + return make_andclause(pull_ands(winners), true); + } } diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 0ab4014..c1625e0 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -2261,6 +2261,11 @@ adjust_appendrel_attrs_mutator(Node *node, context->appinfos); return (Node *) phv; } + if (IsA(node, CachedExpr)) + { + /* no vars in cached expressions */ + return copyObject(node); + } /* Shouldn't need to handle planner auxiliary nodes here */ Assert(!IsA(node, SpecialJoinInfo)); Assert(!IsA(node, AppendRelInfo)); diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 17bcdba..883a31a 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -96,6 +96,46 @@ typedef struct List *safe_param_ids; /* PARAM_EXEC Param IDs to treat as safe */ } max_parallel_hazard_context; +/* + * A detailed result of checking that the subnodes/functions of the node are + * safe for evaluation or caching. This is used in the functions + * ece_all_arguments_const (which checks the subnodes) and + * ece_functions_are_safe (which checks the node functions). + * + * When investigating subnodes: + * - SAFE_FOR_EVALUATION indicates that all the children of this node are + * Consts. + * - SAFE_FOR_CACHING_ONLY indicates that all the children of this node are + * Consts or CachedExprs. + * - SAFE_FOR_NOTHING indicates that this node has a non-Const and + * non-CachedExpr child node. + * + * When investigating node functions: + * - SAFE_FOR_EVALUATION that the node contains only immutable functions (or + * also stable functions in the case of estimation). + * - SAFE_FOR_CACHING_ONLY indicates the node contains only immutable or stable + * functions (so in the case of estimation there's no difference between + * SAFE_FOR_EVALUATION and SAFE_FOR_CACHING_ONLY, and the returned value is + * always SAFE_FOR_EVALUATION because it is more strict in general). + * - SAFE_FOR_NOTHING indicates that the node contains a volatile function. + */ +typedef enum ece_check_node_safety_detailed +{ + SAFE_FOR_EVALUATION, + SAFE_FOR_CACHING_ONLY, + SAFE_FOR_NOTHING, +} ece_check_node_safety_detailed; + +#define SAFE_FOR_CACHING(detailed) \ + ((detailed) == SAFE_FOR_EVALUATION || (detailed) == SAFE_FOR_CACHING_ONLY) + +typedef struct +{ + ece_check_node_safety_detailed detailed; /* detailed result */ + bool recurse; /* we should also check the subnodes? */ + bool estimate; /* are stable functions safe for evaluation? */ +} ece_functions_are_safe_context; + static bool contain_agg_clause_walker(Node *node, void *context); static bool get_agg_clause_costs_walker(Node *node, get_agg_clause_costs_context *context); @@ -113,23 +153,31 @@ static bool contain_leaked_vars_walker(Node *node, void *context); static Relids find_nonnullable_rels_walker(Node *node, bool top_level); static List *find_nonnullable_vars_walker(Node *node, bool top_level); static bool is_strict_saop(ScalarArrayOpExpr *expr, bool falseOK); +static ece_check_node_safety_detailed ece_all_arguments_const(Node *node); static Node *eval_const_expressions_mutator(Node *node, eval_const_expressions_context *context); -static bool contain_non_const_walker(Node *node, void *context); -static bool ece_function_is_safe(Oid funcid, - eval_const_expressions_context *context); +static bool contain_non_const_walker(Node *node, + ece_check_node_safety_detailed *detailed); +static ece_check_node_safety_detailed ece_functions_are_safe(Node *node, + bool recurse, bool estimate); +static bool ece_functions_are_safe_walker(Node *node, + ece_functions_are_safe_context *context); static List *simplify_or_arguments(List *args, eval_const_expressions_context *context, - bool *haveNull, bool *forceTrue); + bool *haveNull, bool *forceTrue, + bool *all_consts_or_cached); static List *simplify_and_arguments(List *args, eval_const_expressions_context *context, - bool *haveNull, bool *forceFalse); + bool *haveNull, bool *forceFalse, + bool *all_consts_or_cached); static Node *simplify_boolean_equality(Oid opno, List *args); static Expr *simplify_function(Oid funcid, Oid result_type, int32 result_typmod, Oid result_collid, Oid input_collid, List **args_p, - bool funcvariadic, bool process_args, bool allow_non_const, - eval_const_expressions_context *context); + bool funcvariadic, bool process_args, + bool allow_only_consts_and_simple_caching, + eval_const_expressions_context *context, + CoercionForm funcformat, Oid opno, int location); static List *reorder_function_arguments(List *args, HeapTuple func_tuple); static List *add_function_defaults(List *args, HeapTuple func_tuple); static List *fetch_function_defaults(HeapTuple func_tuple); @@ -157,6 +205,12 @@ static Query *substitute_actual_srf_parameters(Query *expr, static Node *substitute_actual_srf_parameters_mutator(Node *node, substitute_actual_srf_parameters_context *context); static bool tlist_matches_coltypelist(List *tlist, List *coltypelist); +static bool is_const_or_cached(const Node *node); +static Expr *cache_function(Oid funcid, Oid result_type, Oid result_collid, + Oid input_collid, + List *args, bool funcvariadic, HeapTuple func_tuple, + eval_const_expressions_context *context, CoercionForm funcformat, + Oid opno, int location); /***************************************************************************** @@ -201,6 +255,9 @@ get_leftop(const Expr *clause) { const OpExpr *expr = (const OpExpr *) clause; + if (IsA(expr, CachedExpr)) + expr = (const OpExpr *) ((const CachedExpr *) expr)->subexpr; + if (expr->args != NIL) return linitial(expr->args); else @@ -218,6 +275,9 @@ get_rightop(const Expr *clause) { const OpExpr *expr = (const OpExpr *) clause; + if (IsA(expr, CachedExpr)) + expr = (const OpExpr *) ((const CachedExpr *) expr)->subexpr; + if (list_length(expr->args) >= 2) return lsecond(expr->args); else @@ -232,10 +292,14 @@ get_rightop(const Expr *clause) * not_clause * * Returns t iff this is a 'not' clause: (NOT expr). + * Check the subexpression of the cached expression if check_cachedexpr is true. */ bool -not_clause(Node *clause) +not_clause(Node *clause, bool check_cachedexpr) { + if (check_cachedexpr && IsA(clause, CachedExpr)) + clause = (Node *) ((CachedExpr *) clause)->subexpr; + return (clause != NULL && IsA(clause, BoolExpr) && ((BoolExpr *) clause)->boolop == NOT_EXPR); @@ -265,7 +329,7 @@ make_notclause(Expr *notclause) Expr * get_notclausearg(Expr *notclause) { - return linitial(((BoolExpr *) notclause)->args); + return linitial(castNodeIfCached(BoolExpr, notclause)->args); } /***************************************************************************** @@ -276,10 +340,14 @@ get_notclausearg(Expr *notclause) * or_clause * * Returns t iff the clause is an 'or' clause: (OR { expr }). + * Check the subexpression of the cached expression if check_cachedexpr is true. */ bool -or_clause(Node *clause) +or_clause(Node *clause, bool check_cachedexpr) { + if (check_cachedexpr && IsA(clause, CachedExpr)) + clause = (Node *) ((CachedExpr *) clause)->subexpr; + return (clause != NULL && IsA(clause, BoolExpr) && ((BoolExpr *) clause)->boolop == OR_EXPR); @@ -289,15 +357,34 @@ or_clause(Node *clause) * make_orclause * * Creates an 'or' clause given a list of its subclauses. + * + * NOTE: if try_to_cache is true and the subclauses contain cached expressions, + * the returned expression should be processed using + * set_non_internal_cachedexprs_walker to store all non-internal cached + * expressions separatly for the executor's purposes. Otherwise the created + * cached expression is considered internal and will not be cached by itself. */ Expr * -make_orclause(List *orclauses) +make_orclause(List *orclauses, bool try_to_cache) { BoolExpr *expr = makeNode(BoolExpr); expr->boolop = OR_EXPR; expr->args = orclauses; expr->location = -1; + + if (try_to_cache) + { + bool all_consts_or_cached = true; + ListCell *cell; + + foreach(cell, expr->args) + all_consts_or_cached &= is_const_or_cached((Node *) lfirst(cell)); + + if (all_consts_or_cached) + return (Expr *) makeCachedExpr((CacheableExpr *) expr); + } + return (Expr *) expr; } @@ -310,10 +397,14 @@ make_orclause(List *orclauses) * and_clause * * Returns t iff its argument is an 'and' clause: (AND { expr }). + * Check the subexpression of the cached expression if check_cachedexpr is true. */ bool -and_clause(Node *clause) +and_clause(Node *clause, bool check_cachedexpr) { + if (check_cachedexpr && IsA(clause, CachedExpr)) + clause = (Node *) ((CachedExpr *) clause)->subexpr; + return (clause != NULL && IsA(clause, BoolExpr) && ((BoolExpr *) clause)->boolop == AND_EXPR); @@ -323,15 +414,34 @@ and_clause(Node *clause) * make_andclause * * Creates an 'and' clause given a list of its subclauses. + * + * NOTE: if try_to_cache is true and the subclauses contain cached expressions, + * the returned expression should be processed using + * set_non_internal_cachedexprs_walker to store all non-internal cached + * expressions separatly for the executor's purposes. Otherwise the created + * cached expression is considered internal and will not be cached by itself. */ Expr * -make_andclause(List *andclauses) +make_andclause(List *andclauses, bool try_to_cache) { BoolExpr *expr = makeNode(BoolExpr); expr->boolop = AND_EXPR; expr->args = andclauses; expr->location = -1; + + if (try_to_cache) + { + bool all_consts_or_cached = true; + ListCell *cell; + + foreach(cell, expr->args) + all_consts_or_cached &= is_const_or_cached((Node *) lfirst(cell)); + + if (all_consts_or_cached) + return (Expr *) makeCachedExpr((CacheableExpr *) expr); + } + return (Expr *) expr; } @@ -352,7 +462,7 @@ make_and_qual(Node *qual1, Node *qual2) return qual2; if (qual2 == NULL) return qual1; - return (Node *) make_andclause(list_make2(qual1, qual2)); + return (Node *) make_andclause(list_make2(qual1, qual2), false); } /* @@ -372,9 +482,16 @@ make_ands_explicit(List *andclauses) else if (list_length(andclauses) == 1) return (Expr *) linitial(andclauses); else - return make_andclause(andclauses); + return make_andclause(andclauses, false); } +/* + * NOTE: if the input expression contains cached expressions, the returned + * expression should be processed using set_non_internal_cachedexprs_walker to + * store all non-internal cached expressions separatly for the executor's + * purposes. Otherwise all the created cached expressions are considered + * internal and will not be cached by themselves. + */ List * make_ands_implicit(Expr *clause) { @@ -386,8 +503,41 @@ make_ands_implicit(Expr *clause) */ if (clause == NULL) return NIL; /* NULL -> NIL list == TRUE */ - else if (and_clause((Node *) clause)) - return ((BoolExpr *) clause)->args; + else if (and_clause((Node *) clause, true)) + { + List *args_list = castNodeIfCached(BoolExpr, clause)->args; + + if (IsA(clause, CachedExpr)) + { + /* + * Make new CachedExpr nodes for the cached elements of the list + * since the source nodes can be used elsewhere as internal cached + * expressions. + */ + List *result = NIL; + ListCell *cell; + + foreach(cell, args_list) + { + Node *node = lfirst(cell); + + if (IsA(node, CachedExpr)) + { + result = lappend( + result, + makeCachedExpr(((CachedExpr *) node)->subexpr)); + } + else + { + result = lappend(result, node); + } + } + + return result; + } + + return args_list; + } else if (IsA(clause, Const) && !((Const *) clause)->constisnull && DatumGetBool(((Const *) clause)->constvalue)) @@ -435,6 +585,11 @@ contain_agg_clause_walker(Node *node, void *context) Assert(((GroupingFunc *) node)->agglevelsup == 0); return true; /* abort the tree traversal and return true */ } + if (IsA(node, CachedExpr)) + { + /* aggregation clauses are not cacheable */ + return false; + } Assert(!IsA(node, SubLink)); return expression_tree_walker(node, contain_agg_clause_walker, context); } @@ -706,6 +861,11 @@ get_agg_clause_costs_walker(Node *node, get_agg_clause_costs_context *context) */ return false; } + if (IsA(node, CachedExpr)) + { + /* aggregation clauses are not cacheable */ + return false; + } Assert(!IsA(node, SubLink)); return expression_tree_walker(node, get_agg_clause_costs_walker, (void *) context); @@ -778,6 +938,11 @@ find_window_functions_walker(Node *node, WindowFuncLists *lists) */ return false; } + if (IsA(node, CachedExpr)) + { + /* window functions are not cacheable */ + return false; + } Assert(!IsA(node, SubLink)); return expression_tree_walker(node, find_window_functions_walker, (void *) lists); @@ -821,6 +986,12 @@ expression_returns_set_rows(Node *clause) return clamp_row_est(get_func_rows(expr->opfuncid)); } } + if (IsA(clause, CachedExpr)) + { + CachedExpr *cachedexpr = (CachedExpr *) clause; + + return expression_returns_set_rows((Node *) cachedexpr->subexpr); + } return 1.0; } @@ -855,6 +1026,8 @@ contain_subplans_walker(Node *node, void *context) IsA(node, AlternativeSubPlan) || IsA(node, SubLink)) return true; /* abort the tree traversal and return true */ + if (IsA(node, CachedExpr)) + return false; /* subplans are not cacheable */ return expression_tree_walker(node, contain_subplans_walker, context); } @@ -981,6 +1154,11 @@ contain_volatile_functions_walker(Node *node, void *context) /* NextValueExpr is volatile */ return true; } + if (IsA(node, CachedExpr)) + { + /* CachedExpr is not volatile */ + return false; + } /* * See notes in contain_mutable_functions_walker about why we treat @@ -1028,6 +1206,12 @@ contain_volatile_functions_not_nextval_walker(Node *node, void *context) context)) return true; + if (IsA(node, CachedExpr)) + { + /* CachedExpr is not volatile */ + return false; + } + /* * See notes in contain_mutable_functions_walker about why we treat * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while @@ -1288,6 +1472,14 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context) context, 0); } + else if (IsA(node, CachedExpr)) + { + CachedExpr *cachedexpr = (CachedExpr *) node; + + return max_parallel_hazard_walker((Node *) cachedexpr->subexpr, + context); + } + /* Recurse to check arguments */ return expression_tree_walker(node, max_parallel_hazard_walker, @@ -1418,6 +1610,14 @@ contain_nonstrict_functions_walker(Node *node, void *context) if (IsA(node, BooleanTest)) return true; + if (IsA(node, CachedExpr)) + { + CachedExpr *cachedexpr = (CachedExpr *) node; + + return contain_nonstrict_functions_walker((Node *) cachedexpr->subexpr, + context); + } + /* Check other function-containing nodes */ if (check_functions_in_node(node, contain_nonstrict_functions_checker, context)) @@ -1493,6 +1693,14 @@ contain_context_dependent_node_walker(Node *node, int *flags) return res; } } + if (IsA(node, CachedExpr)) + { + CachedExpr *cachedexpr = (CachedExpr *) node; + + return contain_context_dependent_node_walker( + (Node *) cachedexpr->subexpr, + flags); + } return expression_tree_walker(node, contain_context_dependent_node_walker, (void *) flags); } @@ -1613,6 +1821,12 @@ contain_leaked_vars_walker(Node *node, void *context) */ return false; + case T_CachedExpr: + + return contain_leaked_vars_walker( + (Node *) ((CachedExpr *) node)->subexpr, + context); + default: /* @@ -2195,9 +2409,9 @@ is_strict_saop(ScalarArrayOpExpr *expr, bool falseOK) if (nitems > 0) return true; } - else if (rightop && IsA(rightop, ArrayExpr)) + else if (rightop && IsAIfCached(rightop, ArrayExpr)) { - ArrayExpr *arrayexpr = (ArrayExpr *) rightop; + ArrayExpr *arrayexpr = castNodeIfCached(ArrayExpr, rightop); if (arrayexpr->elements != NIL && !arrayexpr->multidims) return true; @@ -2291,7 +2505,7 @@ CommuteOpExpr(OpExpr *clause) Node *temp; /* Sanity checks: caller is at fault if these fail */ - if (!is_opclause(clause) || + if (!is_opclause((Node *) clause, false) || list_length(clause->args) != 2) elog(ERROR, "cannot commute non-binary-operator clause"); @@ -2454,6 +2668,12 @@ rowtype_field_matches(Oid rowtypeid, int fieldnum, * NOTE: another critical effect is that any function calls that require * default arguments will be expanded, and named-argument calls will be * converted to positional notation. The executor won't handle either. + * + * NOTE: the expression should be processed using + * set_non_internal_cachedexprs_walker to store all non-internal cached + * expressions separatly for the executor's purposes. Otherwise all the created + * cached expressions are considered internal and will not be cached by + * themselves. *-------------------- */ Node * @@ -2487,6 +2707,9 @@ eval_const_expressions(PlannerInfo *root, Node *node) * value of the Param. * 2. Fold stable, as well as immutable, functions to constants. * 3. Reduce PlaceHolderVar nodes to their contained expressions. + * + * Unlike eval_const_expressions, the cached expressions are never used for + * estimation. *-------------------- */ Node * @@ -2506,11 +2729,13 @@ estimate_expression_value(PlannerInfo *root, Node *node) /* * The generic case in eval_const_expressions_mutator is to recurse using * expression_tree_mutator, which will copy the given node unchanged but - * const-simplify its arguments (if any) as far as possible. If the node + * simplify its arguments (if any) as far as possible. If the node * itself does immutable processing, and each of its arguments were reduced * to a Const, we can then reduce it to a Const using evaluate_expr. (Some * node types need more complicated logic; for example, a CASE expression - * might be reducible to a constant even if not all its subtrees are.) + * might be reducible to a constant even if not all its subtrees are.) Also if + * the note itself does not volatile processing, and each of its arguments were + * reduced to Const or CachedExpr nodes, we can then reduce it to a CachedExpr. */ #define ece_generic_processing(node) \ expression_tree_mutator((Node *) (node), eval_const_expressions_mutator, \ @@ -2521,8 +2746,13 @@ estimate_expression_value(PlannerInfo *root, Node *node) * By going directly to expression_tree_walker, contain_non_const_walker * is not applied to the node itself, only to its children. */ -#define ece_all_arguments_const(node) \ - (!expression_tree_walker((Node *) (node), contain_non_const_walker, NULL)) +static ece_check_node_safety_detailed +ece_all_arguments_const(Node *node) +{ + ece_check_node_safety_detailed detailed = SAFE_FOR_EVALUATION; + expression_tree_walker(node, contain_non_const_walker, (void *) &detailed); + return detailed; +} /* Generic macro for applying evaluate_expr */ #define ece_evaluate_expr(node) \ @@ -2679,8 +2909,11 @@ eval_const_expressions_mutator(Node *node, &args, expr->funcvariadic, true, - true, - context); + false, + context, + expr->funcformat, + InvalidOid, + expr->location); if (simple) /* successfully simplified it */ return (Node *) simple; @@ -2726,26 +2959,15 @@ eval_const_expressions_mutator(Node *node, &args, false, true, - true, - context); + false, + context, + COERCE_EXPLICIT_CALL, + expr->opno, + expr->location); if (simple) /* successfully simplified it */ return (Node *) simple; /* - * If the operator is boolean equality or inequality, we know - * how to simplify cases involving one constant and one - * non-constant argument. - */ - if (expr->opno == BooleanEqualOperator || - expr->opno == BooleanNotEqualOperator) - { - simple = (Expr *) simplify_boolean_equality(expr->opno, - args); - if (simple) /* successfully simplified it */ - return (Node *) simple; - } - - /* * The expression cannot be simplified any further, so build * and return a replacement OpExpr node using the * possibly-simplified arguments. @@ -2808,31 +3030,38 @@ eval_const_expressions_mutator(Node *node, /* one null? then distinct */ if (has_null_input) return makeBoolConst(true, false); + } - /* otherwise try to evaluate the '=' operator */ - /* (NOT okay to try to inline it, though!) */ + /* otherwise try to evaluate the '=' operator */ + /* (NOT okay to try to inline it, though!) */ - /* - * Need to get OID of underlying function. Okay to - * scribble on input to this extent. - */ - set_opfuncid((OpExpr *) expr); /* rely on struct - * equivalence */ + /* + * Need to get OID of underlying function. Okay to + * scribble on input to this extent. + */ + set_opfuncid((OpExpr *) expr); /* rely on struct + * equivalence */ - /* - * Code for op/func reduction is pretty bulky, so split it - * out as a separate function. - */ - simple = simplify_function(expr->opfuncid, - expr->opresulttype, -1, - expr->opcollid, - expr->inputcollid, - &args, - false, - false, - false, - context); - if (simple) /* successfully simplified it */ + /* + * Code for op/func reduction is pretty bulky, so split it + * out as a separate function. + */ + simple = simplify_function(expr->opfuncid, + expr->opresulttype, -1, + expr->opcollid, + expr->inputcollid, + &args, + false, + false, + true, + context, + COERCE_EXPLICIT_CALL, + expr->opno, + expr->location); + + if (simple) /* successfully simplified it */ + { + if (IsA(simple, Const)) { /* * Since the underlying operator is "=", must negate @@ -2844,6 +3073,29 @@ eval_const_expressions_mutator(Node *node, BoolGetDatum(!DatumGetBool(csimple->constvalue)); return (Node *) csimple; } + else if (IsA(simple, CachedExpr)) + { + /* + * Cache DistinctExpr using information from its cached + * operator. + */ + CachedExpr *csimple = castNode(CachedExpr, simple); + OpExpr *subexpr = castNode(OpExpr, + csimple->subexpr); + DistinctExpr *newsubexpr = makeNode(DistinctExpr); + + newsubexpr->opno = subexpr->opno; + newsubexpr->opfuncid = subexpr->opfuncid; + newsubexpr->opresulttype = subexpr->opresulttype; + newsubexpr->opretset = subexpr->opretset; + newsubexpr->opcollid = subexpr->opcollid; + newsubexpr->inputcollid = subexpr->inputcollid; + newsubexpr->args = subexpr->args; + newsubexpr->location = subexpr->location; + + return (Node *) makeCachedExpr( + (CacheableExpr *) newsubexpr); + } } /* @@ -2862,24 +3114,175 @@ eval_const_expressions_mutator(Node *node, newexpr->location = expr->location; return (Node *) newexpr; } + case T_NullIfExpr: + { + NullIfExpr *expr = (NullIfExpr *) node; + List *args = expr->args; + ListCell *arg; + bool has_null_input = false; + bool has_nonconst_input = false; + Expr *simple; + NullIfExpr *newexpr; + + /* + * Reduce constants in the NullIfExpr's arguments. We know + * args is either NIL or a List node, so we can call + * expression_tree_mutator directly rather than recursing to + * self. + */ + args = (List *) expression_tree_mutator((Node *) expr->args, + eval_const_expressions_mutator, + (void *) context); + + /* + * We must do our own check for NULLs because NullIfExpr has + * different results for NULL input than the underlying + * operator does. + */ + foreach(arg, args) + { + if (IsA(lfirst(arg), Const)) + has_null_input |= ((Const *) lfirst(arg))->constisnull; + else + has_nonconst_input = true; + } + + /* + * All constants and has null? Then const arguments aren't + * equal, so return the first one. + */ + if (!has_nonconst_input && has_null_input) + return linitial(args); + + /* Try to evaluate the '=' operator */ + /* (NOT okay to try to inline it, though!) */ + + /* + * Need to get OID of underlying function. Okay to scribble + * on input to this extent. + */ + set_opfuncid((OpExpr *) expr); /* rely on struct + * equivalence */ + + /* + * Code for op/func reduction is pretty bulky, so split it + * out as a separate function. + */ + simple = simplify_function(expr->opfuncid, + BOOLOID, -1, + InvalidOid, + expr->inputcollid, + &args, + false, + false, + true, + context, + COERCE_EXPLICIT_CALL, + expr->opno, + expr->location); + + if (simple) /* successfully simplified it */ + { + if (IsA(simple, Const)) + { + /* + * Since the underlying operator is "=", return the + * first argument if the arguments are not equal and + * NULL otherwise. + */ + Const *csimple = castNode(Const, simple); + + if (DatumGetBool(csimple->constvalue)) + { + return (Node *) makeNullConst( + expr->opresulttype, + exprTypmod(linitial(args)), + expr->opcollid); + } + else + { + return linitial(args); + } + } + else if (IsA(simple, CachedExpr)) + { + /* + * Cache NullIfExpr using information from its cached + * operator. + */ + CachedExpr *csimple = castNode(CachedExpr, simple); + OpExpr *subexpr = castNode(OpExpr, + csimple->subexpr); + NullIfExpr *newsubexpr = makeNode(NullIfExpr); + + newsubexpr->opno = subexpr->opno; + newsubexpr->opfuncid = subexpr->opfuncid; + newsubexpr->opresulttype = expr->opresulttype; + newsubexpr->opretset = subexpr->opretset; + newsubexpr->opcollid = expr->opcollid; + newsubexpr->inputcollid = subexpr->inputcollid; + newsubexpr->args = subexpr->args; + newsubexpr->location = subexpr->location; + + return (Node *) makeCachedExpr( + (CacheableExpr *) newsubexpr); + } + } + + /* + * The expression cannot be simplified any further, so build + * and return a replacement NullIfExpr node using the + * possibly-simplified arguments. + */ + newexpr = makeNode(NullIfExpr); + newexpr->opno = expr->opno; + newexpr->opfuncid = expr->opfuncid; + newexpr->opresulttype = expr->opresulttype; + newexpr->opretset = expr->opretset; + newexpr->opcollid = expr->opcollid; + newexpr->inputcollid = expr->inputcollid; + newexpr->args = args; + newexpr->location = expr->location; + return (Node *) newexpr; + } case T_ScalarArrayOpExpr: + case T_RowCompareExpr: { - ScalarArrayOpExpr *saop; + /* + * Generic handling for node types whose own processing checks + * that their functions and arguments are safe for evaluation or + * caching. + */ + ece_check_node_safety_detailed args_detailed, + func_detailed; + + /* Copy the node and simplify its arguments */ + node = ece_generic_processing(node); - /* Copy the node and const-simplify its arguments */ - saop = (ScalarArrayOpExpr *) ece_generic_processing(node); + /* Check node args and functions */ + args_detailed = ece_all_arguments_const(node); + func_detailed = ece_functions_are_safe(node, false, + context->estimate); - /* Make sure we know underlying function */ - set_sa_opfuncid(saop); + /* + * If all arguments are Consts, and node functions are safe for + * evaluation, we can fold to a constant + */ + if (args_detailed == SAFE_FOR_EVALUATION && + func_detailed == SAFE_FOR_EVALUATION) + return ece_evaluate_expr(node); /* - * If all arguments are Consts, and it's a safe function, we - * can fold to a constant + * If we do not perform estimation, all arguments are Consts or + * CachedExprs, and node functions are safe for caching, we can + * fold to a CachedExpr */ - if (ece_all_arguments_const(saop) && - ece_function_is_safe(saop->opfuncid, context)) - return ece_evaluate_expr(saop); - return (Node *) saop; + if (!context->estimate && + SAFE_FOR_CACHING(args_detailed) && + SAFE_FOR_CACHING(func_detailed)) + return (Node *) makeCachedExpr((CacheableExpr *) node); + + return node; } case T_BoolExpr: { @@ -2892,11 +3295,14 @@ eval_const_expressions_mutator(Node *node, List *newargs; bool haveNull = false; bool forceTrue = false; - - newargs = simplify_or_arguments(expr->args, - context, - &haveNull, - &forceTrue); + bool all_consts_or_cached = true; + + newargs = simplify_or_arguments( + expr->args, + context, + &haveNull, + &forceTrue, + &all_consts_or_cached); if (forceTrue) return makeBoolConst(true, false); if (haveNull) @@ -2911,20 +3317,37 @@ eval_const_expressions_mutator(Node *node, * result */ if (list_length(newargs) == 1) + { return (Node *) linitial(newargs); - /* Else we still need an OR node */ - return (Node *) make_orclause(newargs); + } + else + { + /* We still need an OR node */ + Expr *newexpr = make_orclause(newargs, + false); + + /* Check if we can cache the new expression */ + if (!context->estimate && all_consts_or_cached) + { + return (Node *) makeCachedExpr( + (CacheableExpr *) newexpr); + } + return (Node *) newexpr; + } } case AND_EXPR: { List *newargs; bool haveNull = false; bool forceFalse = false; - - newargs = simplify_and_arguments(expr->args, - context, - &haveNull, - &forceFalse); + bool all_consts_or_cached = true; + + newargs = simplify_and_arguments( + expr->args, + context, + &haveNull, + &forceFalse, + &all_consts_or_cached); if (forceFalse) return makeBoolConst(false, false); if (haveNull) @@ -2939,13 +3362,28 @@ eval_const_expressions_mutator(Node *node, * result */ if (list_length(newargs) == 1) + { return (Node *) linitial(newargs); - /* Else we still need an AND node */ - return (Node *) make_andclause(newargs); + } + else + { + /* We still need an AND node */ + Expr *newexpr = make_andclause(newargs, + false); + + /* Check if we can cache the new expression */ + if (!context->estimate && all_consts_or_cached) + { + return (Node *) makeCachedExpr( + (CacheableExpr *) newexpr); + } + return (Node *) newexpr; + } } case NOT_EXPR: { Node *arg; + Expr *newexpr; Assert(list_length(expr->args) == 1); arg = eval_const_expressions_mutator(linitial(expr->args), @@ -2955,7 +3393,24 @@ eval_const_expressions_mutator(Node *node, * Use negate_clause() to see if we can simplify * away the NOT. */ - return negate_clause(arg); + newexpr = (Expr *) negate_clause(arg); + + if ((IsA(newexpr, BoolExpr) && + ((BoolExpr *) newexpr)->boolop == NOT_EXPR) || + IsA(newexpr, CachedExpr)) + { + /* + * Simplification did not help and we again got + * the NOT node, or the expression is already + * cached. + */ + return (Node *) newexpr; + } + + /* Try to simplify the whole new expression */ + return eval_const_expressions_mutator( + (Node *) newexpr, + context); } default: elog(ERROR, "unrecognized boolop: %d", @@ -2980,7 +3435,8 @@ eval_const_expressions_mutator(Node *node, * If we can simplify the input to a constant, then we don't * need the RelabelType node anymore: just change the type * field of the Const node. Otherwise, must copy the - * RelabelType node. + * RelabelType node; cache it if its arg is also cached and we + * do not perform estimation. */ RelabelType *relabel = (RelabelType *) node; Node *arg; @@ -2989,11 +3445,11 @@ eval_const_expressions_mutator(Node *node, context); /* - * If we find stacked RelabelTypes (eg, from foo :: int :: - * oid) we can discard all but the top one. + * If we find stacked (and possibly cached) RelabelTypes (eg, + * from foo :: int :: oid) we can discard all but the top one. */ - while (arg && IsA(arg, RelabelType)) - arg = (Node *) ((RelabelType *) arg)->arg; + while (arg && IsAIfCached(arg, RelabelType)) + arg = (Node *) castNodeIfCached(RelabelType, arg)->arg; if (arg && IsA(arg, Const)) { @@ -3014,6 +3470,13 @@ eval_const_expressions_mutator(Node *node, newrelabel->resultcollid = relabel->resultcollid; newrelabel->relabelformat = relabel->relabelformat; newrelabel->location = relabel->location; + + /* Check if we can cache this node */ + if (!context->estimate && arg && IsA(arg, CachedExpr)) + { + return (Node *) makeCachedExpr( + (CacheableExpr *) newrelabel); + } return (Node *) newrelabel; } } @@ -3027,6 +3490,7 @@ eval_const_expressions_mutator(Node *node, Oid intypioparam; Expr *simple; CoerceViaIO *newexpr; + bool cache = false; /* Make a List so we can use simplify_function */ args = list_make1(expr->arg); @@ -3045,6 +3509,7 @@ eval_const_expressions_mutator(Node *node, getTypeInputInfo(expr->resulttype, &infunc, &intypioparam); + /* Try to simplify the source type's output function */ simple = simplify_function(outfunc, CSTRINGOID, -1, InvalidOid, @@ -3052,8 +3517,12 @@ eval_const_expressions_mutator(Node *node, &args, false, true, - true, - context); + false, + context, + COERCE_EXPLICIT_CALL, + InvalidOid, + -1); + if (simple) /* successfully simplified output fn */ { /* @@ -3084,10 +3553,23 @@ eval_const_expressions_mutator(Node *node, &args, false, false, - true, - context); + false, + context, + COERCE_EXPLICIT_CALL, + InvalidOid, + -1); if (simple) /* successfully simplified input fn */ - return (Node *) simple; + { + if (IsA(simple, CachedExpr)) + { + /* return later cached CoerceViaIO node */ + cache = true; + } + else + { + return (Node *) simple; + } + } } /* @@ -3101,27 +3583,49 @@ eval_const_expressions_mutator(Node *node, newexpr->resultcollid = expr->resultcollid; newexpr->coerceformat = expr->coerceformat; newexpr->location = expr->location; + + /* Check if we can cache the new expression */ + if (cache) + return (Node *) makeCachedExpr((CacheableExpr *) newexpr); + return (Node *) newexpr; } case T_ArrayCoerceExpr: { ArrayCoerceExpr *ac; + ece_check_node_safety_detailed func_detailed; - /* Copy the node and const-simplify its arguments */ + /* Copy the node and simplify its arguments */ ac = (ArrayCoerceExpr *) ece_generic_processing(node); + /* Check the functions in the per-element expression */ + func_detailed = ece_functions_are_safe((Node *) ac->elemexpr, + true, false); + /* * If constant argument and the per-element expression is * immutable, we can simplify the whole thing to a constant. - * Exception: although contain_mutable_functions considers + * Exception: although ece_functions_are_safe considers * CoerceToDomain immutable for historical reasons, let's not * do so here; this ensures coercion to an array-over-domain * does not apply the domain's constraints until runtime. */ if (ac->arg && IsA(ac->arg, Const) && ac->elemexpr && !IsA(ac->elemexpr, CoerceToDomain) && - !contain_mutable_functions((Node *) ac->elemexpr)) + func_detailed == SAFE_FOR_EVALUATION) return ece_evaluate_expr(ac); + + /* + * If not estimation mode, constant or cached argument, and the + * per-element expression is immutable or stable, we can cache + * the whole thing. + */ + if (!context->estimate && + is_const_or_cached((Node *) ac->arg) && + ac->elemexpr && !IsA(ac->elemexpr, CoerceToDomain) && + SAFE_FOR_CACHING(func_detailed)) + return (Node *) makeCachedExpr((CacheableExpr *) ac); + return (Node *) ac; } case T_CollateExpr: @@ -3163,11 +3667,13 @@ eval_const_expressions_mutator(Node *node, relabel->location = collate->location; /* Don't create stacked RelabelTypes */ - while (arg && IsA(arg, RelabelType)) - arg = (Node *) ((RelabelType *) arg)->arg; + while (arg && IsAIfCached(arg, RelabelType)) + arg = (Node *) castNodeIfCached(RelabelType, arg)->arg; relabel->arg = (Expr *) arg; - return (Node *) relabel; + /* Try to cache the new expression */ + return eval_const_expressions_mutator((Node *) relabel, + context); } } case T_CaseExpr: @@ -3200,6 +3706,10 @@ eval_const_expressions_mutator(Node *node, * expression when executing the CASE, since any contained * CaseTestExprs that might have referred to it will have been * replaced by the constant. + * + * If we do not perform estimation and all expressions in the + * CASE expression are constant or cached, the CASE expression + * will also be cached. *---------- */ CaseExpr *caseexpr = (CaseExpr *) node; @@ -3210,6 +3720,7 @@ eval_const_expressions_mutator(Node *node, bool const_true_cond; Node *defresult = NULL; ListCell *arg; + bool all_subexpr_const_or_cached = true; /* Simplify the test expression, if any */ newarg = eval_const_expressions_mutator((Node *) caseexpr->arg, @@ -3222,8 +3733,17 @@ eval_const_expressions_mutator(Node *node, context->case_val = newarg; newarg = NULL; /* not needed anymore, see above */ } + else if (newarg && IsA(newarg, CachedExpr)) + { + /* create dummy CachedExpr node */ + context->case_val = (Node *) makeCachedExpr(NULL); + } else + { context->case_val = NULL; + if (newarg) + all_subexpr_const_or_cached = false; + } /* Simplify the WHEN clauses */ newargs = NIL; @@ -3238,26 +3758,43 @@ eval_const_expressions_mutator(Node *node, casecond = eval_const_expressions_mutator((Node *) oldcasewhen->expr, context); - /* - * If the test condition is constant FALSE (or NULL), then - * drop this WHEN clause completely, without processing - * the result. - */ - if (casecond && IsA(casecond, Const)) + if (casecond) { - Const *const_input = (Const *) casecond; - - if (const_input->constisnull || - !DatumGetBool(const_input->constvalue)) - continue; /* drop alternative with FALSE cond */ - /* Else it's constant TRUE */ - const_true_cond = true; + /* + * If the test condition is constant FALSE (or NULL), + * then drop this WHEN clause completely, without + * processing the result. + */ + if (IsA(casecond, Const)) + { + Const *const_input = (Const *) casecond; + + if (const_input->constisnull || + !DatumGetBool(const_input->constvalue)) + { + /* Drop alternative with FALSE cond */ + continue; + } + /* Else it's constant TRUE */ + const_true_cond = true; + } + else if (IsA(casecond, CachedExpr)) + { + /* OK */ + } + else + { + all_subexpr_const_or_cached = false; + } } /* Simplify this alternative's result value */ caseresult = eval_const_expressions_mutator((Node *) oldcasewhen->result, context); + all_subexpr_const_or_cached &= + is_const_or_cached(caseresult); + /* If non-constant test condition, emit a new WHEN node */ if (!const_true_cond) { @@ -3281,9 +3818,14 @@ eval_const_expressions_mutator(Node *node, /* Simplify the default result, unless we replaced it above */ if (!const_true_cond) + { defresult = eval_const_expressions_mutator((Node *) caseexpr->defresult, context); + all_subexpr_const_or_cached &= + is_const_or_cached(defresult); + } + context->case_val = save_case_val; /* @@ -3300,35 +3842,66 @@ eval_const_expressions_mutator(Node *node, newcase->args = newargs; newcase->defresult = (Expr *) defresult; newcase->location = caseexpr->location; + + /* Check if we can cache this node */ + if (!context->estimate && all_subexpr_const_or_cached) + return (Node *) makeCachedExpr((CacheableExpr *) newcase); + return (Node *) newcase; } case T_CaseTestExpr: { + Node *case_val = context->case_val; + /* - * If we know a constant test value for the current CASE + * If we know that the test node for the current CASE is cached, + * return the cached current node. + * Else if we know a constant test value for the current CASE * construct, substitute it for the placeholder. Else just * return the placeholder as-is. */ - if (context->case_val) - return copyObject(context->case_val); - else - return copyObject(node); + if (case_val) + { + if (IsA(case_val, CachedExpr)) + { + return (Node *) makeCachedExpr( + (CacheableExpr *) copyObject(node)); + } + return copyObject(case_val); + } + return copyObject(node); } case T_ArrayRef: case T_ArrayExpr: case T_RowExpr: + case T_ConvertRowtypeExpr: + case T_MinMaxExpr: + case T_XmlExpr: { /* * Generic handling for node types whose own processing is * known to be immutable, and for which we need no smarts - * beyond "simplify if all inputs are constants". + * beyond "simplify if all inputs are constants or cached + * expressions". */ + ece_check_node_safety_detailed args_detailed; - /* Copy the node and const-simplify its arguments */ + /* Copy the node and simplify its arguments */ node = ece_generic_processing(node); + /* If all arguments are Consts, we can fold to a constant */ - if (ece_all_arguments_const(node)) + args_detailed = ece_all_arguments_const(node); + if (args_detailed == SAFE_FOR_EVALUATION) return ece_evaluate_expr(node); + + /* + * If we do not perform estimation, and all arguments are Consts + * or CachedExprs, we can cache the result of this node. + */ + if (!context->estimate && + args_detailed == SAFE_FOR_CACHING_ONLY) + return (Node *) makeCachedExpr((CacheableExpr *) node); + return node; } case T_CoalesceExpr: @@ -3337,6 +3910,7 @@ eval_const_expressions_mutator(Node *node, CoalesceExpr *newcoalesce; List *newargs; ListCell *arg; + bool all_args_are_const_or_cached = true; newargs = NIL; foreach(arg, coalesceexpr->args) @@ -3363,6 +3937,14 @@ eval_const_expressions_mutator(Node *node, newargs = lappend(newargs, e); break; } + else if (IsA(e, CachedExpr)) + { + /* OK */ + } + else + { + all_args_are_const_or_cached = false; + } newargs = lappend(newargs, e); } @@ -3380,6 +3962,12 @@ eval_const_expressions_mutator(Node *node, newcoalesce->coalescecollid = coalesceexpr->coalescecollid; newcoalesce->args = newargs; newcoalesce->location = coalesceexpr->location; + /* Check if we can cache this node */ + if (!context->estimate && all_args_are_const_or_cached) + { + return (Node *) makeCachedExpr( + (CacheableExpr *) newcoalesce); + } return (Node *) newcoalesce; } case T_SQLValueFunction: @@ -3387,7 +3975,7 @@ eval_const_expressions_mutator(Node *node, /* * All variants of SQLValueFunction are stable, so if we are * estimating the expression's value, we should evaluate the - * current function value. Otherwise just copy. + * current function value. Otherwise copy and cache it. */ SQLValueFunction *svf = (SQLValueFunction *) node; @@ -3397,7 +3985,8 @@ eval_const_expressions_mutator(Node *node, svf->typmod, InvalidOid); else - return copyObject((Node *) svf); + return (Node *) makeCachedExpr( + (CacheableExpr *) copyObject(node)); } case T_FieldSelect: { @@ -3447,9 +4036,9 @@ eval_const_expressions_mutator(Node *node, fselect->resultcollid, ((Var *) arg)->varlevelsup); } - if (arg && IsA(arg, RowExpr)) + if (arg && IsAIfCached(arg, RowExpr)) { - RowExpr *rowexpr = (RowExpr *) arg; + RowExpr *rowexpr = castNodeIfCached(RowExpr, arg); if (fselect->fieldnum > 0 && fselect->fieldnum <= list_length(rowexpr->args)) @@ -3485,6 +4074,12 @@ eval_const_expressions_mutator(Node *node, newfselect->resultcollid)) return ece_evaluate_expr(newfselect); } + /* Check if we can cache this node */ + if (!context->estimate && is_const_or_cached(arg)) + { + return (Node *) makeCachedExpr( + (CacheableExpr *) newfselect); + } return (Node *) newfselect; } case T_NullTest: @@ -3495,7 +4090,8 @@ eval_const_expressions_mutator(Node *node, arg = eval_const_expressions_mutator((Node *) ntest->arg, context); - if (ntest->argisrow && arg && IsA(arg, RowExpr)) + + if (ntest->argisrow && arg && IsAIfCached(arg, RowExpr)) { /* * We break ROW(...) IS [NOT] NULL into separate tests on @@ -3503,9 +4099,10 @@ eval_const_expressions_mutator(Node *node, * efficient to evaluate, as well as being more amenable * to optimization. */ - RowExpr *rarg = (RowExpr *) arg; + RowExpr *rarg = castNodeIfCached(RowExpr, arg); List *newargs = NIL; ListCell *l; + bool rarg_cached = IsA(arg, CachedExpr); foreach(l, rarg->args) { @@ -3544,9 +4141,28 @@ eval_const_expressions_mutator(Node *node, return makeBoolConst(true, false); /* If only one nonconst input, it's the result */ if (list_length(newargs) == 1) + { return (Node *) linitial(newargs); - /* Else we need an AND node */ - return (Node *) make_andclause(newargs); + } + else + { + /* We need an AND node */ + Node *newnode = (Node *) make_andclause(newargs, + false); + + /* + * We can cache the result if we do not perform + * estimation, and the input also was cached (since only + * the const args were ommitted and they do + * not change this). + */ + if (!context->estimate && rarg_cached) + { + return (Node *) makeCachedExpr( + (CacheableExpr *) newnode); + } + return newnode; + } } if (!ntest->argisrow && arg && IsA(arg, Const)) { @@ -3576,6 +4192,11 @@ eval_const_expressions_mutator(Node *node, newntest->nulltesttype = ntest->nulltesttype; newntest->argisrow = ntest->argisrow; newntest->location = ntest->location; + + /* Check if we can cache this node */ + if (!context->estimate && is_const_or_cached(arg)) + return (Node *) makeCachedExpr((CacheableExpr *) newntest); + return (Node *) newntest; } case T_BooleanTest: @@ -3636,6 +4257,11 @@ eval_const_expressions_mutator(Node *node, newbtest->arg = (Expr *) arg; newbtest->booltesttype = btest->booltesttype; newbtest->location = btest->location; + + /* Check if we can cache this node */ + if (!context->estimate && is_const_or_cached(arg)) + return (Node *) makeCachedExpr((CacheableExpr *) newbtest); + return (Node *) newbtest; } case T_PlaceHolderVar: @@ -3655,13 +4281,46 @@ eval_const_expressions_mutator(Node *node, context); } break; + case T_CachedExpr: + { + /* + * Process it, because maybe we can get the Const node or we + * perform estimation and there should be no cached expressions. + */ + return eval_const_expressions_mutator( + (Node *) ((CachedExpr *) node)->subexpr, + context); + } + case T_RangeTblFunction: + { + RangeTblFunction *rtfunc; + + /* Copy the node and simplify its arguments */ + rtfunc = (RangeTblFunction *) ece_generic_processing(node); + + /* + * Although SRF expressions are not cached, expressions that + * return RECORD can be cached. If such cached expression is + * executed in FROM (ROWS FROM), this means that it is executed + * only once so we can treat it as a non-cached expression (note + * that cached expressions always are calculated as many times + * as they are mentioned in the query). + */ + if (IsA(rtfunc->funcexpr, CachedExpr)) + { + rtfunc->funcexpr = + (Node *) ((CachedExpr *) rtfunc->funcexpr)->subexpr; + } + + return (Node *) rtfunc; + } default: break; } /* * For any node type not handled above, copy the node unchanged but - * const-simplify its subexpressions. This is the correct thing for node + * simplify its subexpressions. This is the correct thing for node * types whose behavior might change between planning and execution, such * as CoerceToDomain. It's also a safe default for new node types not * known to this routine. @@ -3670,33 +4329,81 @@ eval_const_expressions_mutator(Node *node, } /* - * Subroutine for eval_const_expressions: check for non-Const nodes. + * Subroutine for eval_const_expressions: check for non-Const or non-CachedExpr + * nodes. + * + * We can abort recursion immediately on finding a non-Const and non-CachedExpr + * node. This is critical for performance, else eval_const_expressions_mutator + * would take O(N^2) time on non-simplifiable trees. However, we do need to + * descend into List nodes since expression_tree_walker sometimes invokes the + * walker function directly on List subtrees. * - * We can abort recursion immediately on finding a non-Const node. This is - * critical for performance, else eval_const_expressions_mutator would take - * O(N^2) time on non-simplifiable trees. However, we do need to descend - * into List nodes since expression_tree_walker sometimes invokes the walker - * function directly on List subtrees. + * The output argument *detailed must be initialized SAFE_FOR_EVALUATION by the + * caller. It will be set SAFE_FOR_CACHING_ONLY if only constant and cached + * nodes are detected anywhere in the argument list. It will be set + * SAFE_FOR_NOTHING if a non-constant or non-cached node is detected anywhere in + * the argument list. */ static bool -contain_non_const_walker(Node *node, void *context) +contain_non_const_walker(Node *node, ece_check_node_safety_detailed *detailed) { if (node == NULL) + { + /* this does not affect the value of the detailed result */ return false; + } if (IsA(node, Const)) + { + /* this does not affect the value of the detailed result */ + return false; + } + if (IsA(node, CachedExpr)) + { + *detailed = SAFE_FOR_CACHING_ONLY; return false; + } if (IsA(node, List)) - return expression_tree_walker(node, contain_non_const_walker, context); + { + return expression_tree_walker(node, contain_non_const_walker, + (void *) detailed); + } /* Otherwise, abort the tree traversal and return true */ + *detailed = SAFE_FOR_NOTHING; return true; } /* - * Subroutine for eval_const_expressions: check if a function is OK to evaluate + * ece_functions_are_safe + * Search for noncacheable functions within a clause (possibly recursively). + * + * Returns true if any non-cacheable function found. + * + * The output argument context->detailed must be initialized SAFE_FOR_EVALUATION + * by the caller. It will be set SAFE_FOR_CACHING_ONLY if we do not perform + * estimation and only immutable and stable functions are found (in case of + * estimation there's no difference between SAFE_FOR_EVALUATION and + * SAFE_FOR_CACHING_ONLY, and the returned value is always SAFE_FOR_EVALUATION + * because it is more strict in general). It will be set SAFE_FOR_NOTHING if a + * volatile function is detected anywhere in the subexpressions. */ +static ece_check_node_safety_detailed +ece_functions_are_safe(Node *node, bool recurse, bool estimate) +{ + ece_functions_are_safe_context context; + + context.detailed = SAFE_FOR_EVALUATION; + context.recurse = recurse; + context.estimate = estimate; + + ece_functions_are_safe_walker(node, &context); + return context.detailed; +} + static bool -ece_function_is_safe(Oid funcid, eval_const_expressions_context *context) +ece_functions_are_safe_checker(Oid funcid, void *context) { + ece_functions_are_safe_context *safe_context = + (ece_functions_are_safe_context *) context; char provolatile = func_volatile(funcid); /* @@ -3707,10 +4414,74 @@ ece_function_is_safe(Oid funcid, eval_const_expressions_context *context) * to estimate the value at all. */ if (provolatile == PROVOLATILE_IMMUTABLE) + { + /* this does not affect the value of the detailed result */ + return false; + } + else if (provolatile == PROVOLATILE_STABLE) + { + if (safe_context->estimate) + { + /* this does not affect the value of the detailed result */ + return false; + } + else + { + safe_context->detailed = SAFE_FOR_CACHING_ONLY; + return false; + } + } + else + { + safe_context->detailed = SAFE_FOR_NOTHING; + return true; + } +} + +static bool +ece_functions_are_safe_walker(Node *node, + ece_functions_are_safe_context *context) +{ + if (node == NULL) + return false; + /* Check for functions in node itself */ + if (check_functions_in_node(node, ece_functions_are_safe_checker, + (void *) context)) return true; - if (context->estimate && provolatile == PROVOLATILE_STABLE) + + if (IsA(node, SQLValueFunction)) + { + /* all variants of SQLValueFunction are stable */ + if (!context->estimate) + context->detailed = SAFE_FOR_CACHING_ONLY; + return false; + } + + if (IsA(node, NextValueExpr)) + { + /* NextValueExpr is volatile */ + context->detailed = SAFE_FOR_NOTHING; return true; - return false; + } + + /* + * See notes in contain_mutable_functions_walker about why we treat + * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable. Hence, immutable + * functions do not affect the value of the detailed result. + */ + + if (!context->recurse) + return false; + + /* Recurse to check arguments */ + if (IsA(node, Query)) + { + /* Recurse into subselects */ + return query_tree_walker((Query *) node, ece_functions_are_safe_walker, + (void *) context, 0); + } + return expression_tree_walker(node, ece_functions_are_safe_walker, + (void *) context); } /* @@ -3730,12 +4501,16 @@ ece_function_is_safe(Oid funcid, eval_const_expressions_context *context) * * The output arguments *haveNull and *forceTrue must be initialized false * by the caller. They will be set true if a NULL constant or TRUE constant, - * respectively, is detected anywhere in the argument list. + * respectively, is detected anywhere in the argument list. The output argument + * *all_consts_or_cached must be initialized true by the caller. It will be set + * false if a non-constant or non-cached node is detected anywhere in the + * argument list. */ static List * simplify_or_arguments(List *args, eval_const_expressions_context *context, - bool *haveNull, bool *forceTrue) + bool *haveNull, bool *forceTrue, + bool *all_consts_or_cached) { List *newargs = NIL; List *unprocessed_args; @@ -3759,9 +4534,10 @@ simplify_or_arguments(List *args, unprocessed_args = list_delete_first(unprocessed_args); /* flatten nested ORs as per above comment */ - if (or_clause(arg)) + if (or_clause(arg, true)) { - List *subargs = list_copy(((BoolExpr *) arg)->args); + List *subargs = + list_copy(castNodeIfCached(BoolExpr, arg)->args); /* overly tense code to avoid leaking unused list header */ if (!unprocessed_args) @@ -3785,9 +4561,10 @@ simplify_or_arguments(List *args, * since it's not a mainstream case. In particular we don't worry * about const-simplifying the input twice. */ - if (or_clause(arg)) + if (or_clause(arg, true)) { - List *subargs = list_copy(((BoolExpr *) arg)->args); + List *subargs = + list_copy(castNodeIfCached(BoolExpr, arg)->args); unprocessed_args = list_concat(subargs, unprocessed_args); continue; @@ -3817,6 +4594,14 @@ simplify_or_arguments(List *args, /* otherwise, we can drop the constant-false input */ continue; } + else if (IsA(arg, CachedExpr)) + { + /* OK */ + } + else + { + *all_consts_or_cached = false; + } /* else emit the simplified arg into the result list */ newargs = lappend(newargs, arg); @@ -3842,12 +4627,16 @@ simplify_or_arguments(List *args, * * The output arguments *haveNull and *forceFalse must be initialized false * by the caller. They will be set true if a null constant or false constant, - * respectively, is detected anywhere in the argument list. + * respectively, is detected anywhere in the argument list. The output argument + * *all_consts_or_cached must be initialized true by the caller. It will be set + * false if a non-constant or non-cached node is detected anywhere in the + * argument list. */ static List * simplify_and_arguments(List *args, eval_const_expressions_context *context, - bool *haveNull, bool *forceFalse) + bool *haveNull, bool *forceFalse, + bool *all_consts_or_cached) { List *newargs = NIL; List *unprocessed_args; @@ -3861,9 +4650,10 @@ simplify_and_arguments(List *args, unprocessed_args = list_delete_first(unprocessed_args); /* flatten nested ANDs as per above comment */ - if (and_clause(arg)) + if (and_clause(arg, true)) { - List *subargs = list_copy(((BoolExpr *) arg)->args); + List *subargs = + list_copy(castNodeIfCached(BoolExpr, arg)->args); /* overly tense code to avoid leaking unused list header */ if (!unprocessed_args) @@ -3887,9 +4677,10 @@ simplify_and_arguments(List *args, * since it's not a mainstream case. In particular we don't worry * about const-simplifying the input twice. */ - if (and_clause(arg)) + if (and_clause(arg, true)) { - List *subargs = list_copy(((BoolExpr *) arg)->args); + List *subargs = + list_copy(castNodeIfCached(BoolExpr, arg)->args); unprocessed_args = list_concat(subargs, unprocessed_args); continue; @@ -3919,6 +4710,14 @@ simplify_and_arguments(List *args, /* otherwise, we can drop the constant-true input */ continue; } + else if (IsA(arg, CachedExpr)) + { + /* OK */ + } + else + { + *all_consts_or_cached = false; + } /* else emit the simplified arg into the result list */ newargs = lappend(newargs, arg); @@ -3941,8 +4740,9 @@ simplify_and_arguments(List *args, * ensures that we will recognize these forms as being equivalent in, for * example, partial index matching. * - * We come here only if simplify_function has failed; therefore we cannot - * see two constant inputs, nor a constant-NULL input. + * We come here only if the previous strategies in simplify_function have + * failed; therefore we cannot see two constant inputs, nor a constant-NULL + * input. */ static Node * simplify_boolean_equality(Oid opno, List *args) @@ -3999,8 +4799,10 @@ simplify_boolean_equality(Oid opno, List *args) * Inputs are the function OID, actual result type OID (which is needed for * polymorphic functions), result typmod, result collation, the input * collation to use for the function, the original argument list (not - * const-simplified yet, unless process_args is false), and some flags; - * also the context data for eval_const_expressions. + * simplified yet, unless process_args is false), the coercion form of the + * function output, the operator OID (InvalidOid if the function itself), the + * location (used only for simple caching), and some flags; also the context + * data for eval_const_expressions. * * Returns a simplified expression if successful, or NULL if cannot * simplify the function call. @@ -4009,15 +4811,17 @@ simplify_boolean_equality(Oid opno, List *args) * lists into positional notation and/or adding any needed default argument * expressions; which is a bit grotty, but it avoids extra fetches of the * function's pg_proc tuple. For this reason, the args list is - * pass-by-reference. Conversion and const-simplification of the args list + * pass-by-reference. Conversion and simplification of the args list * will be done even if simplification of the function call itself is not * possible. */ static Expr * simplify_function(Oid funcid, Oid result_type, int32 result_typmod, Oid result_collid, Oid input_collid, List **args_p, - bool funcvariadic, bool process_args, bool allow_non_const, - eval_const_expressions_context *context) + bool funcvariadic, bool process_args, + bool allow_only_consts_and_simple_caching, + eval_const_expressions_context *context, + CoercionForm funcformat, Oid opno, int location) { List *args = *args_p; HeapTuple func_tuple; @@ -4025,16 +4829,19 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod, Expr *newexpr; /* - * We have three strategies for simplification: execute the function to + * We have five strategies for simplification: execute the function to * deliver a constant result, use a transform function to generate a - * substitute node tree, or expand in-line the body of the function + * substitute node tree, expand in-line the body of the function * definition (which only works for simple SQL-language functions, but - * that is a common case). Each case needs access to the function's + * that is a common case), simplify the boolean equality/inequality, or + * cache this function call. Each case needs access to the function's * pg_proc tuple, so fetch it just once. * - * Note: the allow_non_const flag suppresses both the second and third - * strategies; so if !allow_non_const, simplify_function can only return a - * Const or NULL. Argument-list rewriting happens anyway, though. + * Note: the allow_only_consts_and_simple_caching flag suppresses the + * second, third and fourth strategies; so if + * allow_only_consts_and_simple_caching, simplify_function can only return a + * Const, CachedExpr or NULL. Argument-list rewriting happens anyway, + * though. */ func_tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(func_tuple)) @@ -4064,7 +4871,9 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod, args, funcvariadic, func_tuple, context); - if (!newexpr && allow_non_const && OidIsValid(func_form->protransform)) + if (!newexpr && + !allow_only_consts_and_simple_caching && + OidIsValid(func_form->protransform)) { /* * Build a dummy FuncExpr node containing the simplified arg list. We @@ -4087,13 +4896,47 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod, newexpr = (Expr *) DatumGetPointer(OidFunctionCall1(func_form->protransform, PointerGetDatum(&fexpr))); + + if (newexpr && !context->estimate && !IsA(newexpr, CachedExpr)) + { + /* Try to cache the new expression. */ + newexpr = (Expr *) eval_const_expressions_mutator((Node *) newexpr, + context); + } } - if (!newexpr && allow_non_const) + if (!newexpr && !allow_only_consts_and_simple_caching) newexpr = inline_function(funcid, result_type, result_collid, input_collid, args, funcvariadic, func_tuple, context); + /* + * If the operator is boolean equality or inequality, we know + * how to simplify cases involving one constant and one + * non-constant argument. + */ + if (!newexpr && + !allow_only_consts_and_simple_caching && + (opno == BooleanEqualOperator || + opno == BooleanNotEqualOperator)) + { + newexpr = (Expr *) simplify_boolean_equality(opno, args); + + if (newexpr && !context->estimate && !IsA(newexpr, CachedExpr)) + { + /* Try to cache the new expression. */ + newexpr = (Expr *) eval_const_expressions_mutator((Node *) newexpr, + context); + } + } + + if (!newexpr && !context->estimate) + { + newexpr = cache_function(funcid, result_type, result_collid, + input_collid, args, funcvariadic, func_tuple, + context, funcformat, opno, location); + } + ReleaseSysCache(func_tuple); return newexpr; @@ -4809,6 +5652,14 @@ substitute_actual_parameters_mutator(Node *node, /* We don't need to copy at this time (it'll get done later) */ return list_nth(context->args, param->paramid - 1); } + if (IsA(node, CachedExpr)) + { + CachedExpr *cachedexpr = (CachedExpr *) node; + + return substitute_actual_parameters_mutator( + (Node *) cachedexpr->subexpr, + context); + } return expression_tree_mutator(node, substitute_actual_parameters_mutator, (void *) context); } @@ -4969,6 +5820,10 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte) return NULL; rtfunc = (RangeTblFunction *) linitial(rte->functions); + /* + * Do not check whether this is CachedExpr with a FuncExpr subexpression + * because STF are not cached. + */ if (!IsA(rtfunc->funcexpr, FuncExpr)) return NULL; fexpr = (FuncExpr *) rtfunc->funcexpr; @@ -5272,6 +6127,14 @@ substitute_actual_srf_parameters_mutator(Node *node, return result; } } + if (IsA(node, CachedExpr)) + { + CachedExpr *cachedexpr = (CachedExpr *) node; + + return substitute_actual_srf_parameters_mutator( + (Node *) cachedexpr->subexpr, + context); + } return expression_tree_mutator(node, substitute_actual_srf_parameters_mutator, (void *) context); @@ -5319,3 +6182,154 @@ tlist_matches_coltypelist(List *tlist, List *coltypelist) return true; } + +/* + * is_opclause + * + * Returns t iff this is an operator expression. + * Check the subexpression of the cached expression if check_cachedexpr is true. + */ +bool +is_opclause(Node *clause, bool check_cachedexpr) +{ + if (check_cachedexpr && IsA(clause, CachedExpr)) + clause = (Node *) ((CachedExpr *) clause)->subexpr; + + return (clause != NULL && IsA(clause, OpExpr)); +} + +/* + * is_funcclause + * + * Returns t iff this is a function expression. + * Check the subexpression of the cached expression if check_cachedexpr is true. + */ +bool +is_funcclause(Node *clause, bool check_cachedexpr) +{ + if (check_cachedexpr && IsA(clause, CachedExpr)) + clause = (Node *) ((CachedExpr *) clause)->subexpr; + + return (clause != NULL && IsA(clause, FuncExpr)); +} + +/* + * Return true if node is Const or CachedExpr. + */ +static bool +is_const_or_cached(const Node *node) +{ + if (node == NULL) + return false; + + return (IsA(node, Const) || IsA(node, CachedExpr)); +} + +/* + * cache_function: try to cache a result of calling this function + * + * We can do this if the function does not return a set, is not volatile itself, + * and its arguments are constants or recursively cached expressions. Also we do + * not cache during estimation. + * + * Returns a cached expression if successful, or NULL if cannot cache the + * function. Returns an expression for the cached operator if opno is not + * InvalidOid. + */ +static Expr * +cache_function(Oid funcid, Oid result_type, Oid result_collid, Oid input_collid, + List *args, bool funcvariadic, HeapTuple func_tuple, + eval_const_expressions_context *context, CoercionForm funcformat, + Oid opno, int location) +{ + Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple); + Expr *newexpr; + + /* Sanity checks */ + if (context->estimate) + return NULL; + + /* Can't cache the result of the function if it returns a set */ + if (funcform->proretset) + return NULL; + + /* Check for non-constant or non-cached inputs */ + if (!SAFE_FOR_CACHING(ece_all_arguments_const((Node *) args))) + return NULL; + + /* Can't cache volatile functions */ + if (funcform->provolatile == PROVOLATILE_IMMUTABLE) + /* okay */ ; + else if (funcform->provolatile == PROVOLATILE_STABLE) + /* okay */ ; + else + return NULL; + + /* Create an expression for this function/operator call */ + if (opno == InvalidOid) + { + FuncExpr *funcexpr = makeNode(FuncExpr); + + funcexpr->funcid = funcid; + funcexpr->funcresulttype = result_type; + funcexpr->funcretset = false; + funcexpr->funcvariadic = funcvariadic; + funcexpr->funcformat = funcformat; + funcexpr->funccollid = result_collid; + funcexpr->inputcollid = input_collid; + funcexpr->args = args; + funcexpr->location = location; + + newexpr = (Expr *) funcexpr; + } + else + { + OpExpr *opexpr = makeNode(OpExpr); + + opexpr->opno = opno; + opexpr->opfuncid = funcid; + opexpr->opresulttype = result_type; + opexpr->opretset = false; + opexpr->opcollid = result_collid; + opexpr->inputcollid = input_collid; + opexpr->args = args; + opexpr->location = location; + + newexpr = (Expr *) opexpr; + } + + return (Expr *) makeCachedExpr((CacheableExpr *) newexpr); +} + +/* + * set_non_internal_cachedexprs_walker + * + * Add all non-internal cached expressions to cachedexprs and set the cached_ids + * for them. + * + * Caller must initialize the result list to which all found non-internal cached + * expressions will be added. + */ +bool +set_non_internal_cachedexprs_walker(Node *node, List **cachedexprs) +{ + Assert(cachedexprs); + + if (node == NULL) + return false; + + if (IsA(node, CachedExpr)) + { + CachedExpr *cachedexpr = (CachedExpr *) node; + + cachedexpr->cached_id = list_length(*cachedexprs); + *cachedexprs = lappend(*cachedexprs, (void *) cachedexpr); + + /* do NOT recurse into children */ + return false; + } + + /* recurse into children */ + return expression_tree_walker(node, set_non_internal_cachedexprs_walker, + (void *) cachedexprs); +} diff --git a/src/backend/optimizer/util/orclauses.c b/src/backend/optimizer/util/orclauses.c index 1e78028..207cf92 100644 --- a/src/backend/optimizer/util/orclauses.c +++ b/src/backend/optimizer/util/orclauses.c @@ -164,8 +164,8 @@ extract_or_clause(RestrictInfo *or_rinfo, RelOptInfo *rel) /* * Scan each arm of the input OR clause. Notice we descend into * or_rinfo->orclause, which has RestrictInfo nodes embedded below the - * toplevel OR/AND structure. This is useful because we can use the info - * in those nodes to make is_safe_restriction_clause_for()'s checks + * toplevel non-cached OR/AND structure. This is useful because we can use + * the info in those nodes to make is_safe_restriction_clause_for()'s checks * cheaper. We'll strip those nodes from the returned tree, though, * meaning that fresh ones will be built if the clause is accepted as a * restriction clause. This might seem wasteful --- couldn't we re-use @@ -173,15 +173,15 @@ extract_or_clause(RestrictInfo *or_rinfo, RelOptInfo *rel) * selectivity and other cached data is computed exactly the same way for * a restriction clause as for a join clause, which seems undesirable. */ - Assert(or_clause((Node *) or_rinfo->orclause)); + Assert(or_clause((Node *) or_rinfo->orclause, false)); foreach(lc, ((BoolExpr *) or_rinfo->orclause)->args) { Node *orarg = (Node *) lfirst(lc); List *subclauses = NIL; Node *subclause; - /* OR arguments should be ANDs or sub-RestrictInfos */ - if (and_clause(orarg)) + /* OR arguments should be non-cached ANDs or sub-RestrictInfos */ + if (and_clause(orarg, false)) { List *andargs = ((BoolExpr *) orarg)->args; ListCell *lc2; @@ -231,9 +231,14 @@ extract_or_clause(RestrictInfo *or_rinfo, RelOptInfo *rel) * to preserve AND/OR flatness (ie, no OR directly underneath OR). */ subclause = (Node *) make_ands_explicit(subclauses); - if (or_clause(subclause)) - clauselist = list_concat(clauselist, - list_copy(((BoolExpr *) subclause)->args)); + + /* This is not used for pseudoconstants */ + Assert(!IsA(subclause, CachedExpr)); + + if (or_clause(subclause, false)) + clauselist = list_concat( + clauselist, + list_copy(((BoolExpr *) subclause)->args)); else clauselist = lappend(clauselist, subclause); } @@ -244,7 +249,7 @@ extract_or_clause(RestrictInfo *or_rinfo, RelOptInfo *rel) * one arm --- but then the input OR node was also redundant.) */ if (clauselist != NIL) - return make_orclause(clauselist); + return make_orclause(clauselist, false); return NULL; } diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c index 02ce883..8760915 100644 --- a/src/backend/optimizer/util/predtest.c +++ b/src/backend/optimizer/util/predtest.c @@ -839,14 +839,14 @@ predicate_classify(Node *clause, PredIterInfo info) } /* Handle normal AND and OR boolean clauses */ - if (and_clause(clause)) + if (and_clause(clause, true)) { info->startup_fn = boolexpr_startup_fn; info->next_fn = list_next_fn; info->cleanup_fn = list_cleanup_fn; return CLASS_AND; } - if (or_clause(clause)) + if (or_clause(clause, true)) { info->startup_fn = boolexpr_startup_fn; info->next_fn = list_next_fn; @@ -855,9 +855,9 @@ predicate_classify(Node *clause, PredIterInfo info) } /* Handle ScalarArrayOpExpr */ - if (IsA(clause, ScalarArrayOpExpr)) + if (IsAIfCached(clause, ScalarArrayOpExpr)) { - ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause; + ScalarArrayOpExpr *saop = castNodeIfCached(ScalarArrayOpExpr, clause); Node *arraynode = (Node *) lsecond(saop->args); /* @@ -882,9 +882,10 @@ predicate_classify(Node *clause, PredIterInfo info) return saop->useOr ? CLASS_OR : CLASS_AND; } } - else if (arraynode && IsA(arraynode, ArrayExpr) && - !((ArrayExpr *) arraynode)->multidims && - list_length(((ArrayExpr *) arraynode)->elements) <= MAX_SAOP_ARRAY_SIZE) + else if (arraynode && IsAIfCached(arraynode, ArrayExpr) && + !castNodeIfCached(ArrayExpr, arraynode)->multidims && + list_length(castNodeIfCached(ArrayExpr, arraynode)->elements) <= + MAX_SAOP_ARRAY_SIZE) { info->startup_fn = arrayexpr_startup_fn; info->next_fn = arrayexpr_next_fn; @@ -933,7 +934,7 @@ list_cleanup_fn(PredIterInfo info) static void boolexpr_startup_fn(Node *clause, PredIterInfo info) { - info->state = (void *) list_head(((BoolExpr *) clause)->args); + info->state = (void *) list_head(castNodeIfCached(BoolExpr, clause)->args); } /* @@ -953,7 +954,7 @@ typedef struct static void arrayconst_startup_fn(Node *clause, PredIterInfo info) { - ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause; + ScalarArrayOpExpr *saop = castNodeIfCached(ScalarArrayOpExpr, clause); ArrayConstIterState *state; Const *arrayconst; ArrayType *arrayval; @@ -1024,8 +1025,9 @@ arrayconst_cleanup_fn(PredIterInfo info) } /* - * PredIterInfo routines for iterating over a ScalarArrayOpExpr with a - * one-dimensional ArrayExpr array operand. + * PredIterInfo routines for iterating over a (possibly cached) + * ScalarArrayOpExpr with a one-dimensional (possibly cached) ArrayExpr array + * operand. */ typedef struct { @@ -1036,7 +1038,7 @@ typedef struct static void arrayexpr_startup_fn(Node *clause, PredIterInfo info) { - ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause; + ScalarArrayOpExpr *saop = castNodeIfCached(ScalarArrayOpExpr, clause); ArrayExprIterState *state; ArrayExpr *arrayexpr; @@ -1055,7 +1057,7 @@ arrayexpr_startup_fn(Node *clause, PredIterInfo info) state->opexpr.args = list_copy(saop->args); /* Initialize iteration variable to first member of ArrayExpr */ - arrayexpr = (ArrayExpr *) lsecond(saop->args); + arrayexpr = castNodeIfCached(ArrayExpr, lsecond(saop->args)); state->next = list_head(arrayexpr->elements); } @@ -1115,6 +1117,12 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause, /* Allow interrupting long proof attempts */ CHECK_FOR_INTERRUPTS(); + /* + * We assume the predicate has already been checked to contain only + * immutable functions and operators. + */ + Assert(!IsA(predicate, CachedExpr)); + /* First try the equal() test */ if (equal((Node *) predicate, clause)) return true; @@ -1177,6 +1185,12 @@ predicate_refuted_by_simple_clause(Expr *predicate, Node *clause, /* Allow interrupting long proof attempts */ CHECK_FOR_INTERRUPTS(); + /* + * We assume the predicate has already been checked to contain only + * immutable functions and operators. + */ + Assert(!IsA(predicate, CachedExpr)); + /* A simple clause can't refute itself */ /* Worth checking because of relation_excluded_by_constraints() */ if ((Node *) predicate == clause) @@ -1197,31 +1211,42 @@ predicate_refuted_by_simple_clause(Expr *predicate, Node *clause, return true; /* foo IS NOT NULL refutes foo IS NULL */ - if (clause && IsA(clause, NullTest) && - ((NullTest *) clause)->nulltesttype == IS_NOT_NULL && - !((NullTest *) clause)->argisrow && - equal(((NullTest *) clause)->arg, isnullarg)) + if (clause && IsAIfCached(clause, NullTest) && + castNodeIfCached(NullTest, clause)->nulltesttype == IS_NOT_NULL && + !castNodeIfCached(NullTest, clause)->argisrow && + equal(castNodeIfCached(NullTest, clause)->arg, isnullarg)) return true; return false; /* we can't succeed below... */ } /* Try the clause-IS-NULL case */ - if (clause && IsA(clause, NullTest) && - ((NullTest *) clause)->nulltesttype == IS_NULL) + if (clause && IsAIfCached(clause, NullTest) && + castNodeIfCached(NullTest, clause)->nulltesttype == IS_NULL) { - Expr *isnullarg = ((NullTest *) clause)->arg; + Expr *isnullarg = castNodeIfCached(NullTest, clause)->arg; /* row IS NULL does not act in the simple way we have in mind */ - if (((NullTest *) clause)->argisrow) + if (castNodeIfCached(NullTest, clause)->argisrow) return false; /* foo IS NULL refutes foo IS NOT NULL */ - if (predicate && IsA(predicate, NullTest) && - ((NullTest *) predicate)->nulltesttype == IS_NOT_NULL && - !((NullTest *) predicate)->argisrow && - equal(((NullTest *) predicate)->arg, isnullarg)) - return true; + if (predicate && IsA(predicate, NullTest)) + { + NullTest *predicate_isnull = (NullTest *) predicate; + Expr *predicate_isnullarg = predicate_isnull->arg; + + /* + * We assume the predicate has already been checked to contain only + * immutable functions and operators. + */ + Assert(!IsA(predicate_isnullarg, CachedExpr)); + + if (predicate_isnull->nulltesttype == IS_NOT_NULL && + !predicate_isnull->argisrow && + equal(predicate_isnullarg, isnullarg)) + return true; + } /* foo IS NULL weakly refutes any predicate that is strict for foo */ if (weak && @@ -1245,6 +1270,13 @@ extract_not_arg(Node *clause) { if (clause == NULL) return NULL; + + /* + * We assume the predicate has already been checked to contain only + * immutable functions and operators. + */ + Assert(!IsA(clause, CachedExpr)); + if (IsA(clause, BoolExpr)) { BoolExpr *bexpr = (BoolExpr *) clause; @@ -1273,16 +1305,16 @@ extract_strong_not_arg(Node *clause) { if (clause == NULL) return NULL; - if (IsA(clause, BoolExpr)) + if (IsAIfCached(clause, BoolExpr)) { - BoolExpr *bexpr = (BoolExpr *) clause; + BoolExpr *bexpr = castNodeIfCached(BoolExpr, clause); if (bexpr->boolop == NOT_EXPR) return (Node *) linitial(bexpr->args); } - else if (IsA(clause, BooleanTest)) + else if (IsAIfCached(clause, BooleanTest)) { - BooleanTest *btest = (BooleanTest *) clause; + BooleanTest *btest = castNodeIfCached(BooleanTest, clause); if (btest->booltesttype == IS_FALSE) return (Node *) btest->arg; @@ -1316,10 +1348,10 @@ clause_is_strict_for(Node *clause, Node *subexpr) * through any nullness-preserving, immutable operation.) We should not * see stacked RelabelTypes here. */ - if (IsA(clause, RelabelType)) - clause = (Node *) ((RelabelType *) clause)->arg; - if (IsA(subexpr, RelabelType)) - subexpr = (Node *) ((RelabelType *) subexpr)->arg; + if (IsAIfCached(clause, RelabelType)) + clause = (Node *) castNodeIfCached(RelabelType, clause)->arg; + if (IsAIfCached(subexpr, RelabelType)) + subexpr = (Node *) castNodeIfCached(RelabelType, subexpr)->arg; /* Base case */ if (equal(clause, subexpr)) @@ -1330,20 +1362,20 @@ clause_is_strict_for(Node *clause, Node *subexpr) * if any input is forced NULL by subexpr. This is OK even if the op or * func isn't immutable, since it won't even be called on NULL input. */ - if (is_opclause(clause) && - op_strict(((OpExpr *) clause)->opno)) + if (is_opclause(clause, true) && + op_strict(castNodeIfCached(OpExpr, clause)->opno)) { - foreach(lc, ((OpExpr *) clause)->args) + foreach(lc, castNodeIfCached(OpExpr, clause)->args) { if (clause_is_strict_for((Node *) lfirst(lc), subexpr)) return true; } return false; } - if (is_funcclause(clause) && - func_strict(((FuncExpr *) clause)->funcid)) + if (is_funcclause(clause, true) && + func_strict(castNodeIfCached(FuncExpr, clause)->funcid)) { - foreach(lc, ((FuncExpr *) clause)->args) + foreach(lc, castNodeIfCached(FuncExpr, clause)->args) { if (clause_is_strict_for((Node *) lfirst(lc), subexpr)) return true; @@ -1558,14 +1590,14 @@ operator_predicate_proof(Expr *predicate, Node *clause, * about DistinctExpr in general, and this probably isn't the first place * to fix if you want to improve that. */ - if (!is_opclause(predicate)) + if (!is_opclause((Node *) predicate, false)) return false; pred_opexpr = (OpExpr *) predicate; if (list_length(pred_opexpr->args) != 2) return false; - if (!is_opclause(clause)) + if (!is_opclause(clause, true)) return false; - clause_opexpr = (OpExpr *) clause; + clause_opexpr = castNodeIfCached(OpExpr, clause); if (list_length(clause_opexpr->args) != 2) return false; diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 82b7842..c2d63f6 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -886,6 +886,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, * translating whole-row Var of a child to that of the parent. * Children of an inherited table or subquery child rels can not * directly participate in a join, so other kinds of nodes here. + * Do not check for cached expressions because they do not contain vars. */ if (IsA(var, Var)) { diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c index edf5a48..9f7ff65 100644 --- a/src/backend/optimizer/util/restrictinfo.c +++ b/src/backend/optimizer/util/restrictinfo.c @@ -67,7 +67,7 @@ make_restrictinfo(Expr *clause, * If it's an OR clause, build a modified copy with RestrictInfos inserted * above each subclause of the top-level AND/OR structure. */ - if (or_clause((Node *) clause)) + if (or_clause((Node *) clause, true)) return (RestrictInfo *) make_sub_restrictinfos(clause, is_pushed_down, outerjoin_delayed, @@ -78,7 +78,7 @@ make_restrictinfo(Expr *clause, nullable_relids); /* Shouldn't be an AND clause, else AND/OR flattening messed up */ - Assert(!and_clause((Node *) clause)); + Assert(!and_clause((Node *) clause, true)); return make_restrictinfo_internal(clause, NULL, @@ -133,7 +133,8 @@ make_restrictinfo_internal(Expr *clause, * If it's a binary opclause, set up left/right relids info. In any case * set up the total clause relids info. */ - if (is_opclause(clause) && list_length(((OpExpr *) clause)->args) == 2) + if (is_opclause((Node *) clause, true) && + list_length(castNodeIfCached(OpExpr, clause)->args) == 2) { restrictinfo->left_relids = pull_varnos(get_leftop(clause)); restrictinfo->right_relids = pull_varnos(get_rightop(clause)); @@ -232,12 +233,12 @@ make_sub_restrictinfos(Expr *clause, Relids outer_relids, Relids nullable_relids) { - if (or_clause((Node *) clause)) + if (or_clause((Node *) clause, true)) { List *orlist = NIL; ListCell *temp; - foreach(temp, ((BoolExpr *) clause)->args) + foreach(temp, castNodeIfCached(BoolExpr, clause)->args) orlist = lappend(orlist, make_sub_restrictinfos(lfirst(temp), is_pushed_down, @@ -248,7 +249,8 @@ make_sub_restrictinfos(Expr *clause, outer_relids, nullable_relids)); return (Expr *) make_restrictinfo_internal(clause, - make_orclause(orlist), + make_orclause(orlist, + false), is_pushed_down, outerjoin_delayed, pseudoconstant, @@ -257,12 +259,12 @@ make_sub_restrictinfos(Expr *clause, outer_relids, nullable_relids); } - else if (and_clause((Node *) clause)) + else if (and_clause((Node *) clause, true)) { List *andlist = NIL; ListCell *temp; - foreach(temp, ((BoolExpr *) clause)->args) + foreach(temp, castNodeIfCached(BoolExpr, clause)->args) andlist = lappend(andlist, make_sub_restrictinfos(lfirst(temp), is_pushed_down, @@ -272,7 +274,7 @@ make_sub_restrictinfos(Expr *clause, required_relids, outer_relids, nullable_relids)); - return make_andclause(andlist); + return make_andclause(andlist, false); } else return (Expr *) make_restrictinfo_internal(clause, diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c index 32160d5..a8874fe 100644 --- a/src/backend/optimizer/util/tlist.c +++ b/src/backend/optimizer/util/tlist.c @@ -20,7 +20,10 @@ #include "optimizer/tlist.h" -/* Test if an expression node represents a SRF call. Beware multiple eval! */ +/* + * Test if an expression node represents a SRF call. Beware multiple eval! + * Do not check for cached expressions because they do not return a set. + */ #define IS_SRF_CALL(node) \ ((IsA(node, FuncExpr) && ((FuncExpr *) (node))->funcretset) || \ (IsA(node, OpExpr) && ((OpExpr *) (node))->opretset)) @@ -79,11 +82,18 @@ tlist_member_ignore_relabel(Expr *node, List *targetlist) while (node && IsA(node, RelabelType)) node = ((RelabelType *) node)->arg; + /* This is not used for cached expressions */ + Assert(!IsA(node, CachedExpr)); + foreach(temp, targetlist) { TargetEntry *tlentry = (TargetEntry *) lfirst(temp); Expr *tlexpr = tlentry->expr; + /* + * Do not worry about cached expressions because in any case they cannot + * be equal to a non-cached node (see below). + */ while (tlexpr && IsA(tlexpr, RelabelType)) tlexpr = ((RelabelType *) tlexpr)->arg; diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index b16b1e4..c43eda3 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -196,6 +196,11 @@ pull_varnos_walker(Node *node, pull_varnos_context *context) context->sublevels_up--; return result; } + if (IsA(node, CachedExpr)) + { + /* no vars in cached expressions */ + return false; + } return expression_tree_walker(node, pull_varnos_walker, (void *) context); } @@ -243,6 +248,11 @@ pull_varattnos_walker(Node *node, pull_varattnos_context *context) var->varattno - FirstLowInvalidHeapAttributeNumber); return false; } + if (IsA(node, CachedExpr)) + { + /* no vars in cached expressions */ + return false; + } /* Should not find an unplanned subquery */ Assert(!IsA(node, Query)); @@ -312,6 +322,11 @@ pull_vars_walker(Node *node, pull_vars_context *context) context->sublevels_up--; return result; } + if (IsA(node, CachedExpr)) + { + /* no vars in cached expressions */ + return false; + } return expression_tree_walker(node, pull_vars_walker, (void *) context); } @@ -352,6 +367,11 @@ contain_var_clause_walker(Node *node, void *context) return true; /* abort the tree traversal and return true */ /* else fall through to check the contained expr */ } + if (IsA(node, CachedExpr)) + { + /* no vars in cached expressions */ + return false; + } return expression_tree_walker(node, contain_var_clause_walker, context); } @@ -412,6 +432,11 @@ contain_vars_of_level_walker(Node *node, int *sublevels_up) (*sublevels_up)--; return result; } + if (IsA(node, CachedExpr)) + { + /* no vars in cached expressions */ + return false; + } return expression_tree_walker(node, contain_vars_of_level_walker, (void *) sublevels_up); @@ -486,6 +511,11 @@ locate_var_of_level_walker(Node *node, context->sublevels_up--; return result; } + if (IsA(node, CachedExpr)) + { + /* no vars in cached expressions */ + return false; + } return expression_tree_walker(node, locate_var_of_level_walker, (void *) context); @@ -636,6 +666,11 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context) else elog(ERROR, "PlaceHolderVar found where not expected"); } + if (IsA(node, CachedExpr)) + { + /* no vars in cached expressions */ + return false; + } return expression_tree_walker(node, pull_var_clause_walker, (void *) context); } @@ -807,6 +842,11 @@ flatten_join_alias_vars_mutator(Node *node, context->sublevels_up--; return (Node *) newnode; } + if (IsA(node, CachedExpr)) + { + /* no vars in cached expressions */ + return copyObject(node); + } /* Already-planned tree not supported */ Assert(!IsA(node, SubPlan)); /* Shouldn't need to handle these planner auxiliary nodes here */ diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index c31a563..b4f28b6 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -161,6 +161,9 @@ coerce_type(ParseState *pstate, Node *node, CoercionPathType pathtype; Oid funcId; + /* This is used only for parser nodes */ + Assert(!IsA(node, CachedExpr)); + if (targetTypeId == inputTypeId || node == NULL) { @@ -991,6 +994,9 @@ coerce_record_to_complex(ParseState *pstate, Node *node, int ucolno; ListCell *arg; + /* This is used only for parser nodes */ + Assert(!IsA(node, CachedExpr)); + if (node && IsA(node, RowExpr)) { /* diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index d407a89..eb5257c 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -621,7 +621,7 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, } /* Get the BoolExpr's out of the way. */ - if (IsA(clause, BoolExpr)) + if (IsAIfCached(clause, BoolExpr)) { /* * Generate steps for arguments. @@ -631,7 +631,7 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, * independently, collect their step IDs to be stored in the * combine step we'll be creating. */ - if (or_clause((Node *) clause)) + if (or_clause((Node *) clause, true)) { List *arg_stepids = NIL; bool all_args_contradictory = true; @@ -641,7 +641,7 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, * Get pruning step for each arg. If we get contradictory for * all args, it means the OR expression is false as a whole. */ - foreach(lc1, ((BoolExpr *) clause)->args) + foreach(lc1, castNodeIfCached(BoolExpr, clause)->args) { Expr *arg = lfirst(lc1); bool arg_contradictory; @@ -722,9 +722,9 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context, } continue; } - else if (and_clause((Node *) clause)) + else if (and_clause((Node *) clause, true)) { - List *args = ((BoolExpr *) clause)->args; + List *args = castNodeIfCached(BoolExpr, clause)->args; List *argsteps, *arg_stepids = NIL; ListCell *lc1; @@ -1415,10 +1415,10 @@ match_clause_to_partition_key(RelOptInfo *rel, return PARTCLAUSE_MATCH_CLAUSE; } - else if (IsA(clause, OpExpr) && - list_length(((OpExpr *) clause)->args) == 2) + else if (IsAIfCached(clause, OpExpr) && + list_length(castNodeIfCached(OpExpr, clause)->args) == 2) { - OpExpr *opclause = (OpExpr *) clause; + OpExpr *opclause = castNodeIfCached(OpExpr, clause); Expr *leftop, *rightop; Oid op_lefttype, @@ -1431,11 +1431,11 @@ match_clause_to_partition_key(RelOptInfo *rel, PartClauseInfo *partclause; leftop = (Expr *) get_leftop(clause); - if (IsA(leftop, RelabelType)) - leftop = ((RelabelType *) leftop)->arg; + if (IsAIfCached(leftop, RelabelType)) + leftop = castNodeIfCached(RelabelType, leftop)->arg; rightop = (Expr *) get_rightop(clause); - if (IsA(rightop, RelabelType)) - rightop = ((RelabelType *) rightop)->arg; + if (IsAIfCached(rightop, RelabelType)) + rightop = castNodeIfCached(RelabelType, rightop)->arg; /* check if the clause matches this partition key */ if (equal(leftop, partkey)) @@ -1593,9 +1593,9 @@ match_clause_to_partition_key(RelOptInfo *rel, return PARTCLAUSE_MATCH_CLAUSE; } - else if (IsA(clause, ScalarArrayOpExpr)) + else if (IsAIfCached(clause, ScalarArrayOpExpr)) { - ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause; + ScalarArrayOpExpr *saop = castNodeIfCached(ScalarArrayOpExpr, clause); Oid saop_op = saop->opno; Oid saop_coll = saop->inputcollid; Expr *leftop = (Expr *) linitial(saop->args), @@ -1605,8 +1605,8 @@ match_clause_to_partition_key(RelOptInfo *rel, ListCell *lc1; bool contradictory; - if (IsA(leftop, RelabelType)) - leftop = ((RelabelType *) leftop)->arg; + if (IsAIfCached(leftop, RelabelType)) + leftop = castNodeIfCached(RelabelType, leftop)->arg; /* Check it matches this partition key */ if (!equal(leftop, partkey) || @@ -1697,9 +1697,9 @@ match_clause_to_partition_key(RelOptInfo *rel, elem_exprs = lappend(elem_exprs, elem_expr); } } - else if (IsA(rightop, ArrayExpr)) + else if (IsAIfCached(rightop, ArrayExpr)) { - ArrayExpr *arrexpr = castNode(ArrayExpr, rightop); + ArrayExpr *arrexpr = castNodeIfCached(ArrayExpr, rightop); /* * For a nested ArrayExpr, we don't know how to get the actual @@ -1750,13 +1750,13 @@ match_clause_to_partition_key(RelOptInfo *rel, return PARTCLAUSE_UNSUPPORTED; /* step generation failed */ return PARTCLAUSE_MATCH_STEPS; } - else if (IsA(clause, NullTest)) + else if (IsAIfCached(clause, NullTest)) { - NullTest *nulltest = (NullTest *) clause; + NullTest *nulltest = castNodeIfCached(NullTest, clause); Expr *arg = nulltest->arg; - if (IsA(arg, RelabelType)) - arg = ((RelabelType *) arg)->arg; + if (IsAIfCached(arg, RelabelType)) + arg = castNodeIfCached(RelabelType, arg)->arg; /* Does arg match with this partition key column? */ if (!equal(arg, partkey)) @@ -2706,9 +2706,9 @@ pull_partkey_params(PartitionPruneInfo *pinfo, List *steps) { Expr *expr = lfirst(lc2); - if (IsA(expr, Param)) + if (IsAIfCached(expr, Param)) { - Param *param = (Param *) expr; + Param *param = castNodeIfCached(Param, expr); switch (param->paramkind) { @@ -2969,20 +2969,27 @@ match_boolean_partition_clause(Oid partopfamily, Expr *clause, Expr *partkey, { Expr *leftop; + /* Partition expressions can only contain immutable functions */ + Assert(!IsA(partkey, CachedExpr)); + *outconst = NULL; if (!IsBooleanOpfamily(partopfamily)) return false; - if (IsA(clause, BooleanTest)) + if (IsAIfCached(clause, BooleanTest)) { - BooleanTest *btest = (BooleanTest *) clause; + BooleanTest *btest = castNodeIfCached(BooleanTest, clause); /* Only IS [NOT] TRUE/FALSE are any good to us */ if (btest->booltesttype == IS_UNKNOWN || btest->booltesttype == IS_NOT_UNKNOWN) return false; + /* + * Do not worry about cached expressions because in any case they cannot + * be equal to the non-cached partkey (see below). + */ leftop = btest->arg; if (IsA(leftop, RelabelType)) leftop = ((RelabelType *) leftop)->arg; @@ -2998,7 +3005,11 @@ match_boolean_partition_clause(Oid partopfamily, Expr *clause, Expr *partkey, } else { - bool is_not_clause = not_clause((Node *) clause); + /* + * Do not worry about cached expressions because in any case they cannot + * be equal to the non-cached partkey (see below). + */ + bool is_not_clause = not_clause((Node *) clause, false); leftop = is_not_clause ? get_notclausearg(clause) : clause; @@ -3061,6 +3072,12 @@ partkey_datum_from_expr(PartitionPruneContext *context, } break; + case T_CachedExpr: + return partkey_datum_from_expr( + context, + (Expr *) ((CachedExpr *) expr)->subexpr, + stateidx, value); + default: break; } diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c index f1f4212..c6f277e 100644 --- a/src/backend/rewrite/rewriteManip.c +++ b/src/backend/rewrite/rewriteManip.c @@ -307,6 +307,10 @@ contains_multiexpr_param(Node *node, void *context) { if (node == NULL) return false; + + /* + * Do not check the cached params because PARAM_MULTIEXPR cannot be cached. + */ if (IsA(node, Param)) { if (((Param *) node)->paramkind == PARAM_MULTIEXPR) @@ -1343,6 +1347,11 @@ map_variable_attnos_mutator(Node *node, context->sublevels_up--; return (Node *) newnode; } + else if (IsA(node, CachedExpr)) + { + /* no vars in cached expressions */ + return copyObject(node); + } return expression_tree_mutator(node, map_variable_attnos_mutator, (void *) context); } diff --git a/src/backend/statistics/dependencies.c b/src/backend/statistics/dependencies.c index 3b4a09b..c7f9b5b 100644 --- a/src/backend/statistics/dependencies.c +++ b/src/backend/statistics/dependencies.c @@ -757,7 +757,10 @@ dependency_is_compatible_clause(Node *clause, Index relid, AttrNumber *attnum) if (!IsA(rinfo, RestrictInfo)) return false; - /* Pseudoconstants are not interesting (they couldn't contain a Var) */ + /* + * Pseudoconstants (including cached expressions) are not interesting (they + * couldn't contain a Var) + */ if (rinfo->pseudoconstant) return false; @@ -765,7 +768,7 @@ dependency_is_compatible_clause(Node *clause, Index relid, AttrNumber *attnum) if (bms_membership(rinfo->clause_relids) != BMS_SINGLETON) return false; - if (is_opclause(rinfo->clause)) + if (is_opclause((Node *) rinfo->clause, false)) { /* If it's an opclause, check for Var = Const or Const = Var. */ OpExpr *expr = (OpExpr *) rinfo->clause; @@ -799,7 +802,7 @@ dependency_is_compatible_clause(Node *clause, Index relid, AttrNumber *attnum) /* OK to proceed with checking "var" */ } - else if (not_clause((Node *) rinfo->clause)) + else if (not_clause((Node *) rinfo->clause, false)) { /* * "NOT x" can be interpreted as "x = false", so get the argument and @@ -819,6 +822,7 @@ dependency_is_compatible_clause(Node *clause, Index relid, AttrNumber *attnum) /* * We may ignore any RelabelType node above the operand. (There won't be * more than one, since eval_const_expressions has been applied already.) + * Do not check for cached expressions because they do not contain vars. */ if (IsA(var, RelabelType)) var = (Var *) ((RelabelType *) var)->arg; diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 979f6fd..48659fd 100644 --- a/src/backend/utils/adt/datetime.c +++ b/src/backend/utils/adt/datetime.c @@ -4474,6 +4474,7 @@ CheckDateTokenTables(void) Node * TemporalTransform(int32 max_precis, Node *node) { + /* this is not used for cached expressions */ FuncExpr *expr = castNode(FuncExpr, node); Node *ret = NULL; Node *typmod; diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 8dfdffc..d3c5956 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -900,6 +900,7 @@ numeric_send(PG_FUNCTION_ARGS) Datum numeric_transform(PG_FUNCTION_ARGS) { + /* this is not used for cached expressions */ FuncExpr *expr = castNode(FuncExpr, PG_GETARG_POINTER(0)); Node *ret = NULL; Node *typmod; diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 065238b..95d0f7e 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -5722,7 +5722,7 @@ get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno, * itself. (We can't skip the parens.) */ bool need_paren = (PRETTY_PAREN(context) - || IsA(expr, FuncExpr) + || IsAIfCached(expr, FuncExpr) ||IsA(expr, Aggref) ||IsA(expr, WindowFunc)); @@ -6333,7 +6333,8 @@ get_update_query_targetlist_def(Query *query, List *targetList, * those there could be an implicit type coercion. Because we * would ignore implicit type coercions anyway, we don't need to * be as careful as processIndirection() is about descending past - * implicit CoerceToDomains. + * implicit CoerceToDomains. Do not check if there're cached + * expressions because PARAM_MULTIEXPR cannot be cached. */ expr = (Node *) tle->expr; while (expr) @@ -6797,9 +6798,9 @@ get_name_for_var_field(Var *var, int fieldno, * If it's a RowExpr that was expanded from a whole-row Var, use the * column names attached to it. */ - if (IsA(var, RowExpr)) + if (IsAIfCached(var, RowExpr)) { - RowExpr *r = (RowExpr *) var; + RowExpr *r = castNodeIfCached(RowExpr, var); if (fieldno > 0 && fieldno <= list_length(r->colnames)) return strVal(list_nth(r->colnames, fieldno - 1)); @@ -6807,6 +6808,9 @@ get_name_for_var_field(Var *var, int fieldno, /* * If it's a Param of type RECORD, try to find what the Param refers to. + * + * Do not check if this is a cached param as we only check PARAM_EXEC and + * they cannot be cached. */ if (IsA(var, Param)) { @@ -7312,7 +7316,7 @@ get_parameter(Param *param, deparse_context *context) */ need_paren = !(IsA(expr, Var) || IsA(expr, Aggref) || - IsA(expr, Param)); + IsAIfCached(expr, Param)); if (need_paren) appendStringInfoChar(context->buf, '('); @@ -7445,6 +7449,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags) bool is_hipriop; bool is_lopriparent; bool is_hipriparent; + Node *first_parent_arg; op = get_simple_binary_op_name((OpExpr *) node); if (!op) @@ -7473,9 +7478,18 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags) /* * Operators are same priority --- can skip parens only if - * we have (a - b) - c, not a - (b - c). + * we have (a - b) - c, not a - (b - c). Note that the + * arguments can be cached. */ - if (node == (Node *) linitial(((OpExpr *) parentNode)->args)) + first_parent_arg = + (Node *) linitial(((OpExpr *) parentNode)->args); + if (IsA(first_parent_arg, CachedExpr)) + { + first_parent_arg = + (Node *) ((CachedExpr *) first_parent_arg)->subexpr; + } + + if (node == first_parent_arg) return true; return false; @@ -7566,6 +7580,16 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags) return false; } + case T_CachedExpr: + + /* + * Since the cached expression is created only for internal use, + * forget about it and process its subexpression. + */ + return isSimpleNode((Node *) ((CachedExpr *) node)->subexpr, + parentNode, + prettyFlags); + default: break; } @@ -7737,6 +7761,19 @@ get_rule_expr(Node *node, deparse_context *context, get_windowfunc_expr((WindowFunc *) node, context); break; + case T_CachedExpr: + { + CachedExpr *cachedexpr = (CachedExpr *) node; + + /* + * Since the cached expression is created only for internal use, + * forget about it and deparse its subexpression. + */ + get_rule_expr((Node *) cachedexpr->subexpr, context, + showimplicit); + } + break; + case T_ArrayRef: { ArrayRef *aref = (ArrayRef *) node; @@ -7748,8 +7785,9 @@ get_rule_expr(Node *node, deparse_context *context, * within a composite column. Since we already punted on * displaying the FieldStore's target information, just punt * here too, and display only the assignment source - * expression. + * expression. Such cases are not cached. */ + Assert(!IsACached(aref->refexpr, CaseTestExpr)); if (IsA(aref->refexpr, CaseTestExpr)) { Assert(aref->refassgnexpr); @@ -7764,7 +7802,7 @@ get_rule_expr(Node *node, deparse_context *context, * *must* parenthesize to avoid confusion.) */ need_parens = !IsA(aref->refexpr, Var) && - !IsA(aref->refexpr, FieldSelect); + !IsAIfCached(aref->refexpr, FieldSelect); if (need_parens) appendStringInfoChar(buf, '('); get_rule_expr((Node *) aref->refexpr, context, showimplicit); @@ -8000,7 +8038,8 @@ get_rule_expr(Node *node, deparse_context *context, * WRONG to not parenthesize a Var argument; simplicity is not * the issue here, having the right number of names is. */ - need_parens = !IsA(arg, ArrayRef) &&!IsA(arg, FieldSelect); + need_parens = !IsAIfCached(arg, ArrayRef) && + !IsAIfCached(arg, FieldSelect); if (need_parens) appendStringInfoChar(buf, '('); get_rule_expr(arg, context, true); @@ -8178,12 +8217,14 @@ get_rule_expr(Node *node, deparse_context *context, * inline function). If we don't recognize the form * of the WHEN clause, just punt and display it as-is. */ - if (IsA(w, OpExpr)) + if (IsAIfCached(w, OpExpr)) { - List *args = ((OpExpr *) w)->args; + List *args = + castNodeIfCached(OpExpr, w)->args; if (list_length(args) == 2 && - IsA(strip_implicit_coercions(linitial(args)), + IsAIfCached( + strip_implicit_coercions(linitial(args)), CaseTestExpr)) w = (Node *) lsecond(args); } @@ -8749,6 +8790,9 @@ get_rule_expr(Node *node, deparse_context *context, save_varprefix = context->varprefix; context->varprefix = false; + /* Index expressions can only contain immutable functions */ + Assert(!IsA(iexpr->expr, CachedExpr)); + /* * Parenthesize the element unless it's a simple Var or a bare * function call. Follows pg_get_indexdef_worker(). @@ -8940,6 +8984,8 @@ looks_like_function(Node *node) case T_XmlExpr: /* these are all accepted by func_expr_common_subexpr */ return true; + case T_CachedExpr: + return looks_like_function((Node *) ((CachedExpr *) node)->subexpr); default: break; } @@ -9575,6 +9621,7 @@ get_sublink_expr(SubLink *sublink, deparse_context *context) sep = ""; foreach(l, ((BoolExpr *) sublink->testexpr)->args) { + /* this is not used for pseudoconstants */ OpExpr *opexpr = lfirst_node(OpExpr, l); appendStringInfoString(buf, sep); @@ -10415,12 +10462,16 @@ processIndirection(Node *node, deparse_context *context) */ node = (Node *) linitial(fstore->newvals); } - else if (IsA(node, ArrayRef)) + else if (IsAIfCached(node, ArrayRef)) { - ArrayRef *aref = (ArrayRef *) node; + ArrayRef *aref = castNodeIfCached(ArrayRef, node); if (aref->refassgnexpr == NULL) break; + + /* Such cases are not cached */ + Assert(!IsA(node, CachedExpr)); + printSubscripts(aref, context); /* diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 4b08cdb..7c2b8c2 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -1566,7 +1566,7 @@ boolvarsel(PlannerInfo *root, Node *arg, int varRelid) selec = var_eq_const(&vardata, BooleanEqualOperator, BoolGetDatum(true), false, true, false); } - else if (is_funcclause(arg)) + else if (is_funcclause(arg, true)) { /* * If we have no stats and it's a function call, estimate 0.3333333. @@ -1828,24 +1828,28 @@ strip_array_coercion(Node *node) { for (;;) { - if (node && IsA(node, ArrayCoerceExpr)) + if (node && IsAIfCached(node, ArrayCoerceExpr)) { - ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; + ArrayCoerceExpr *acoerce = castNodeIfCached(ArrayCoerceExpr, node); /* * If the per-element expression is just a RelabelType on top of * CaseTestExpr, then we know it's a binary-compatible relabeling. + * Such cases are not cached. */ + Assert(!(IsAIfCached(acoerce->elemexpr, RelabelType) && + IsACached(castNodeIfCached(RelabelType, acoerce->elemexpr)->arg, + CaseTestExpr))); if (IsA(acoerce->elemexpr, RelabelType) && IsA(((RelabelType *) acoerce->elemexpr)->arg, CaseTestExpr)) node = (Node *) acoerce->arg; else break; } - else if (node && IsA(node, RelabelType)) + else if (node && IsAIfCached(node, RelabelType)) { /* We don't really expect this case, but may as well cope */ - node = (Node *) ((RelabelType *) node)->arg; + node = (Node *) castNodeIfCached(RelabelType, node)->arg; } else break; @@ -1950,6 +1954,9 @@ scalararraysel(PlannerInfo *root, else if (oprsel == F_NEQSEL || oprsel == F_NEQJOINSEL) isInequality = true; + /* Cached expressions are not used during estimation */ + Assert(!IsA(rightop, CachedExpr)); + /* * We consider three cases: * @@ -2192,10 +2199,10 @@ estimate_array_length(Node *arrayexpr) arrayval = DatumGetArrayTypeP(arraydatum); return ArrayGetNItems(ARR_NDIM(arrayval), ARR_DIMS(arrayval)); } - else if (arrayexpr && IsA(arrayexpr, ArrayExpr) && - !((ArrayExpr *) arrayexpr)->multidims) + else if (arrayexpr && IsAIfCached(arrayexpr, ArrayExpr) && + !castNodeIfCached(ArrayExpr, arrayexpr)->multidims) { - return list_length(((ArrayExpr *) arrayexpr)->elements); + return list_length(castNodeIfCached(ArrayExpr, arrayexpr)->elements); } else { @@ -3026,7 +3033,7 @@ mergejoinscansel(PlannerInfo *root, Node *clause, *leftend = *rightend = 1.0; /* Deconstruct the merge clause */ - if (!is_opclause(clause)) + if (!is_opclause(clause, false)) return; /* shouldn't happen */ opno = ((OpExpr *) clause)->opno; left = get_leftop((Expr *) clause); @@ -4787,7 +4794,7 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid, vardata->vartype = exprType(node); /* Look inside any binary-compatible relabeling */ - + /* Do not check for cached expressions because they do not contain vars */ if (IsA(node, RelabelType)) basenode = (Node *) ((RelabelType *) node)->arg; else @@ -4893,6 +4900,10 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid, if (indexpr_item == NULL) elog(ERROR, "too few entries in indexprs list"); indexkey = (Node *) lfirst(indexpr_item); + + /* Index expressions can only contain immutable functions */ + Assert(!IsA(indexkey, CachedExpr)); + if (indexkey && IsA(indexkey, RelabelType)) indexkey = (Node *) ((RelabelType *) indexkey)->arg; if (equal(node, indexkey)) @@ -6571,6 +6582,9 @@ deconstruct_indexquals(IndexPath *path) qinfo->rinfo = rinfo; qinfo->indexcol = indexcol; + /* This is not used for pseudoconstants */ + Assert(!IsA(clause, CachedExpr)); + if (IsA(clause, OpExpr)) { qinfo->clause_op = ((OpExpr *) clause)->opno; @@ -6738,6 +6752,9 @@ genericcostestimate(PlannerInfo *root, { RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); + /* This is not used for pseudoconstants */ + Assert(!IsA(rinfo->clause, CachedExpr)); + if (IsA(rinfo->clause, ScalarArrayOpExpr)) { ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) rinfo->clause; @@ -7005,6 +7022,9 @@ btcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, break; /* no quals at all for indexcol */ } + /* This is not used for pseudoconstants */ + Assert(!IsA(clause, CachedExpr)); + if (IsA(clause, ScalarArrayOpExpr)) { int alength = estimate_array_length(qinfo->other_operand); @@ -7543,6 +7563,9 @@ gincost_opexpr(PlannerInfo *root, /* aggressively reduce to a constant, and look through relabeling */ operand = estimate_expression_value(root, operand); + /* cached expressions are not used during estimation */ + Assert(!IsA(operand, CachedExpr)); + if (IsA(operand, RelabelType)) operand = (Node *) ((RelabelType *) operand)->arg; @@ -7606,6 +7629,9 @@ gincost_scalararrayopexpr(PlannerInfo *root, /* aggressively reduce to a constant, and look through relabeling */ rightop = estimate_expression_value(root, rightop); + /* cached expressions are not used during estimation */ + Assert(!IsA(rightop, CachedExpr)); + if (IsA(rightop, RelabelType)) rightop = (Node *) ((RelabelType *) rightop)->arg; @@ -7875,7 +7901,10 @@ gincostestimate(PlannerInfo *root, IndexPath *path, double loop_count, } else { - /* shouldn't be anything else for a GIN index */ + /* + * Shouldn't be anything else (including cached expressions) for a + * GIN index + */ elog(ERROR, "unsupported GIN indexqual type: %d", (int) nodeTag(clause)); } diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index 265b1db..55b7edc 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -1243,6 +1243,7 @@ intervaltypmodleastfield(int32 typmod) Datum interval_transform(PG_FUNCTION_ARGS) { + /* this is not used for cached expressions */ FuncExpr *expr = castNode(FuncExpr, PG_GETARG_POINTER(0)); Node *ret = NULL; Node *typmod; diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c index 6ba400b..6b04700 100644 --- a/src/backend/utils/adt/varbit.c +++ b/src/backend/utils/adt/varbit.c @@ -680,6 +680,7 @@ varbit_send(PG_FUNCTION_ARGS) Datum varbit_transform(PG_FUNCTION_ARGS) { + /* this is not used for cached expressions */ FuncExpr *expr = castNode(FuncExpr, PG_GETARG_POINTER(0)); Node *ret = NULL; Node *typmod; diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c index 8f07b1e..6c3524f 100644 --- a/src/backend/utils/adt/varchar.c +++ b/src/backend/utils/adt/varchar.c @@ -554,6 +554,7 @@ varcharsend(PG_FUNCTION_ARGS) Datum varchar_transform(PG_FUNCTION_ARGS) { + /* this is not used for cached expressions */ FuncExpr *expr = castNode(FuncExpr, PG_GETARG_POINTER(0)); Node *ret = NULL; Node *typmod; diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c index d5984b4..09a9810 100644 --- a/src/backend/utils/fmgr/funcapi.c +++ b/src/backend/utils/fmgr/funcapi.c @@ -230,18 +230,20 @@ get_expr_result_type(Node *expr, { TypeFuncClass result; - if (expr && IsA(expr, FuncExpr)) - result = internal_get_result_type(((FuncExpr *) expr)->funcid, - expr, - NULL, - resultTypeId, - resultTupleDesc); - else if (expr && IsA(expr, OpExpr)) - result = internal_get_result_type(get_opcode(((OpExpr *) expr)->opno), - expr, - NULL, - resultTypeId, - resultTupleDesc); + if (expr && IsAIfCached(expr, FuncExpr)) + result = internal_get_result_type( + castNodeIfCached(FuncExpr, expr)->funcid, + expr, + NULL, + resultTypeId, + resultTupleDesc); + else if (expr && IsAIfCached(expr, OpExpr)) + result = internal_get_result_type( + get_opcode(castNodeIfCached(OpExpr, expr)->opno), + expr, + NULL, + resultTypeId, + resultTupleDesc); else { /* handle as a generic expression; no chance to resolve RECORD */ diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h index 57bd52f..a34b3b9 100644 --- a/src/include/nodes/makefuncs.h +++ b/src/include/nodes/makefuncs.h @@ -88,4 +88,6 @@ extern GroupingSet *makeGroupingSet(GroupingSetKind kind, List *content, int loc extern VacuumRelation *makeVacuumRelation(RangeVar *relation, Oid oid, List *va_cols); +extern CachedExpr *makeCachedExpr(CacheableExpr *subexpr); + #endif /* MAKEFUNC_H */ diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h index ed854fd..a4f2600 100644 --- a/src/include/optimizer/clauses.h +++ b/src/include/optimizer/clauses.h @@ -17,9 +17,6 @@ #include "access/htup.h" #include "nodes/relation.h" -#define is_opclause(clause) ((clause) != NULL && IsA(clause, OpExpr)) -#define is_funcclause(clause) ((clause) != NULL && IsA(clause, FuncExpr)) - typedef struct { int numWindowFuncs; /* total number of WindowFuncs found */ @@ -27,21 +24,24 @@ typedef struct List **windowFuncs; /* lists of WindowFuncs for each winref */ } WindowFuncLists; +extern bool is_opclause(Node *clause, bool check_cachedexpr); +extern bool is_funcclause(Node *clause, bool check_cachedexpr); + extern Expr *make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid); extern Node *get_leftop(const Expr *clause); extern Node *get_rightop(const Expr *clause); -extern bool not_clause(Node *clause); +extern bool not_clause(Node *clause, bool check_cachedexpr); extern Expr *make_notclause(Expr *notclause); extern Expr *get_notclausearg(Expr *notclause); -extern bool or_clause(Node *clause); -extern Expr *make_orclause(List *orclauses); +extern bool or_clause(Node *clause, bool check_cachedexpr); +extern Expr *make_orclause(List *orclauses, bool try_to_cache); -extern bool and_clause(Node *clause); -extern Expr *make_andclause(List *andclauses); +extern bool and_clause(Node *clause, bool check_cachedexpr); +extern Expr *make_andclause(List *andclauses, bool try_to_cache); extern Node *make_and_qual(Node *qual1, Node *qual2); extern Expr *make_ands_explicit(List *andclauses); extern List *make_ands_implicit(Expr *clause); @@ -88,4 +88,6 @@ extern Query *inline_set_returning_function(PlannerInfo *root, extern List *expand_function_arguments(List *args, Oid result_type, HeapTuple func_tuple); +extern bool set_non_internal_cachedexprs_walker(Node *node, List **cachedexprs); + #endif /* CLAUSES_H */ diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index f963e0b..55b4751 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -2194,6 +2194,12 @@ exec_stmt_call(PLpgSQL_execstate *estate, PLpgSQL_stmt_call *stmt) if (argmodes && argmodes[i] == PROARGMODE_INOUT) { + /* + * Do not worry about cached params because they are only + * used in prepared statements, PL/pgSQL inline code blocks + * cannot be used here and PL/pgSQL functions cannot be + * inlined. + */ if (IsA(n, Param)) { Param *param = castNode(Param, n); @@ -6064,6 +6070,7 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, ExecInitExprWithParams(expr->expr_simple_expr, econtext->ecxt_param_list_info, expr->expr_simple_cachedexprs); + expr->expr_simple_in_use = false; expr->expr_simple_lxid = curlxid; MemoryContextSwitchTo(oldcontext); @@ -7579,7 +7586,12 @@ get_cast_hashentry(PLpgSQL_execstate *estate, /* Note: we don't bother labeling the expression tree with collation */ - /* Detect whether we have a no-op (RelabelType) coercion */ + /* + * Detect whether we have a no-op (RelabelType) coercion. + * Do not check for cached expressions because the parser does not use + * them. + */ + Assert(!IsA(cast_expr, CachedExpr)); if (IsA(cast_expr, RelabelType) && ((RelabelType *) cast_expr)->arg == (Expr *) placeholder) cast_expr = NULL; @@ -7801,7 +7813,13 @@ exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan) /* If setrefs.c copied up a Const, no need to look further */ if (IsA(tle_expr, Const)) break; - /* Otherwise, it had better be a Param or an outer Var */ + /* + * Otherwise, it had better be a Param or an outer Var + * + * Do not worry about cached params because they are only used in + * prepared statements, PL/pgSQL inline code blocks cannot be used + * here and PL/pgSQL functions cannot be inlined. + */ Assert(IsA(tle_expr, Param) ||(IsA(tle_expr, Var) && ((Var *) tle_expr)->varno == OUTER_VAR)); /* Descend to the child node */ @@ -7867,6 +7885,7 @@ exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno) /* * Top level of expression must be a simple FuncExpr or OpExpr. */ + Assert(!IsA(expr->expr_simple_expr, CachedExpr)); if (IsA(expr->expr_simple_expr, FuncExpr)) { FuncExpr *fexpr = (FuncExpr *) expr->expr_simple_expr; @@ -7901,9 +7920,19 @@ exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno) { Node *arg = (Node *) lfirst(lc); - /* A Param is OK, whether it's the target variable or not */ - if (arg && IsA(arg, Param)) - continue; + if (arg) + { + /* + * Cached params are only used in prepared statements, PL/pgSQL + * inline code blocks cannot be used here and PL/pgSQL functions + * cannot be inlined. + */ + Assert(!IsACached(arg, Param)); + + /* A Param is OK, whether it's the target variable or not */ + if (IsA(arg, Param)) + continue; + } /* Otherwise, argument expression must not reference target */ if (contains_target_param(arg, &target_dno)) return; @@ -7921,6 +7950,13 @@ contains_target_param(Node *node, int *target_dno) { if (node == NULL) return false; + + /* + * Cached params are only used in prepared statements, PL/pgSQL inline code + * blocks cannot be used here and PL/pgSQL functions cannot be inlined. + */ + Assert(!IsACached(node, Param)); + if (IsA(node, Param)) { Param *param = (Param *) node; diff --git a/src/test/regress/expected/precalculate_stable_functions.out b/src/test/regress/expected/precalculate_stable_functions.out new file mode 100644 index 0000000..6a81993 --- /dev/null +++ b/src/test/regress/expected/precalculate_stable_functions.out @@ -0,0 +1,6122 @@ +-- +-- PRECALCULATE STABLE FUNCTIONS +-- +-- Create types and tables for testing +CREATE TYPE my_integer AS (value integer); +CREATE TYPE composite_type AS (first integer, second integer[], third boolean); +CREATE TABLE x (x integer); +INSERT INTO x SELECT generate_series(1, 4) x; +CREATE TABLE wxyz (w integer, x integer[], y boolean, z integer); +CREATE TABLE wxyz_child () INHERITS (wxyz); +CREATE TABLE wxyz_child2 (a integer, b integer) INHERITS (wxyz); +CREATE TABLE no_columns (); +CREATE TABLE no_columns_child () INHERITS (no_columns); +CREATE TABLE no_columns_child2 (a integer, b integer) INHERITS (no_columns); +-- Create volatile functions for testing +CREATE OR REPLACE FUNCTION public.x_vlt ( +) +RETURNS integer VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v'; + RETURN 1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_my_integer ( +) +RETURNS my_integer VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v my_integer'; + RETURN '(1)'::my_integer; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_array_integer ( +) +RETURNS int[] VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v array_integer'; + RETURN '{2, 3}'::integer[]; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_boolean ( +) +RETURNS boolean VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v boolean'; + RETURN TRUE; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_wxyz ( +) +RETURNS wxyz VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v wxyz'; + RETURN '(1, {2}, TRUE, 3)'::wxyz; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_wxyz_child ( +) +RETURNS wxyz_child VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v wxyz_child'; + RETURN '(1, {2}, TRUE, 3)'::wxyz_child; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_wxyz_child2 ( +) +RETURNS wxyz_child2 VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v wxyz_child2'; + RETURN '(1, {2}, TRUE, 3, 4, 5)'::wxyz_child2; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_oid ( +) +RETURNS oid VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v oid'; + RETURN 1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_text_integer ( +) +RETURNS text VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v text integer'; + RETURN 1::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_text_my_integer ( +) +RETURNS text VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v text my_integer'; + RETURN '(1)'::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_text_xml ( +) +RETURNS text VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v text xml'; + RETURN 'Manual'::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_text_xml_content ( +) +RETURNS text VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v text xml content'; + RETURN 'abcbarfoo'::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_text_xml_instruction_content ( +) +RETURNS text VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v text xml instruction content'; + RETURN 'echo "hello world";'::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_xml ( +) +RETURNS xml VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v xml'; + RETURN 'foo'::xml; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_xml_content ( +) +RETURNS xml VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v xml content'; + RETURN 'abcbarfoo'::xml; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt2 ( + integer +) +RETURNS integer VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v2'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.equal_integers_vlt ( + integer, + integer +) +RETURNS boolean VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'equal integers volatile'; + RETURN $1 = $2; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.equal_my_integer_vlt ( + my_integer, + my_integer +) +RETURNS boolean VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'equal my_integer volatile'; + RETURN $1.value = $2.value; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.cast_integer_as_my_integer_vlt ( + integer +) +RETURNS my_integer VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'cast integer as my_integer volatile'; + RETURN ROW($1)::my_integer; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.cast_my_integer_as_integer_vlt ( + my_integer +) +RETURNS integer VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'cast my_integer as integer volatile'; + RETURN $1.value; +END; +$body$ +LANGUAGE 'plpgsql'; +-- Create stable functions for testing +CREATE OR REPLACE FUNCTION public.x_stl ( +) +RETURNS integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 's'; + RETURN 1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_my_integer ( +) +RETURNS my_integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 's my_integer'; + RETURN '(1)'::my_integer; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_array_integer ( +) +RETURNS int[] STABLE AS +$body$ +BEGIN + RAISE NOTICE 's array_integer'; + RETURN '{2, 3}'::integer[]; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_wxyz ( +) +RETURNS wxyz STABLE AS +$body$ +BEGIN + RAISE NOTICE 's wxyz'; + RETURN '(1, {2}, TRUE, 3)'::wxyz; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_wxyz_child ( +) +RETURNS wxyz_child STABLE AS +$body$ +BEGIN + RAISE NOTICE 's wxyz_child'; + RETURN '(1, {2}, TRUE, 3)'::wxyz_child; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_wxyz_child2 ( +) +RETURNS wxyz_child2 STABLE AS +$body$ +BEGIN + RAISE NOTICE 's wxyz_child2'; + RETURN '(1, {2}, TRUE, 3, 4, 5)'::wxyz_child2; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_oid ( +) +RETURNS oid STABLE AS +$body$ +BEGIN + RAISE NOTICE 's oid'; + RETURN 1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_text_integer ( +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's text integer'; + RETURN 1::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_text_my_integer ( +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's text my_integer'; + RETURN '(1)'::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_text_xml ( +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's text xml'; + RETURN 'Manual'::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_text_xml_content ( +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's xml content'; + RETURN 'abcbarfoo'::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_text_xml_instruction_content ( +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's text xml instruction content'; + RETURN 'echo "hello world";'::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_xml ( +) +RETURNS xml STABLE AS +$body$ +BEGIN + RAISE NOTICE 's xml'; + RETURN 'foo'::xml; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_xml_content ( +) +RETURNS xml STABLE AS +$body$ +BEGIN + RAISE NOTICE 's xml content'; + RETURN 'abcbarfoo'::xml; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2 ( + integer +) +RETURNS integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_strict ( + integer +) +RETURNS integer STABLE STRICT AS +$body$ +BEGIN + RAISE NOTICE 's2 strict'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_boolean ( + boolean +) +RETURNS boolean STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 boolean'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_array_integer ( + integer[] +) +RETURNS integer[] STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 array_integer'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_array_oid ( + oid[] +) +RETURNS oid[] STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 array_oid'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_wxyz ( + wxyz +) +RETURNS wxyz STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 wxyz'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_composite_type ( + composite_type +) +RETURNS composite_type STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 composite_type'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_my_integer ( + my_integer +) +RETURNS my_integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 my_integer'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_no_columns ( + no_columns +) +RETURNS no_columns STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 no_columns'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_name ( + name +) +RETURNS name STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 name'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_xml ( + xml +) +RETURNS xml STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 xml'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_text ( + text +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 text'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.equal_integers_stl ( + integer, + integer +) +RETURNS boolean STABLE AS +$body$ +BEGIN + RAISE NOTICE 'equal integers stable'; + RETURN $1 = $2; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.equal_booleans_stl_strict ( + boolean, + boolean +) +RETURNS boolean STABLE STRICT AS +$body$ +BEGIN + RAISE NOTICE 'equal booleans stable strict'; + RETURN $1 = $2; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.equal_my_integer_stl ( + my_integer, + my_integer +) +RETURNS boolean STABLE AS +$body$ +BEGIN + RAISE NOTICE 'equal my_integer stable'; + RETURN $1.value = $2.value; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.cast_integer_as_my_integer_stl ( + integer +) +RETURNS my_integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 'cast integer as my_integer stable'; + RETURN ROW($1)::my_integer; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.cast_my_integer_as_integer_stl ( + my_integer +) +RETURNS integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 'cast my_integer as integer stable'; + RETURN $1.value; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.stable_max( +) +RETURNS integer STABLE AS +$body$ +BEGIN + RETURN (SELECT max(x) from x); +END +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.simple( +) +RETURNS integer STABLE AS +$body$ +BEGIN + RETURN stable_max(); +END +$body$ +LANGUAGE 'plpgsql'; +-- Create immutable functions for testing +CREATE OR REPLACE FUNCTION public.x_imm2 ( + integer +) +RETURNS integer IMMUTABLE AS +$body$ +BEGIN + RAISE NOTICE 'i2'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_imm2_strict ( + integer +) +RETURNS integer IMMUTABLE STRICT AS +$body$ +BEGIN + RAISE NOTICE 'i2 strict'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_imm2_my_integer ( + my_integer +) +RETURNS my_integer IMMUTABLE AS +$body$ +BEGIN + RAISE NOTICE 'i2 my_integer'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.equal_integers_imm ( + integer, + integer +) +RETURNS boolean IMMUTABLE AS +$body$ +BEGIN + RAISE NOTICE 'equal integers immutable'; + RETURN $1 = $2; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.equal_booleans_imm ( + boolean, + boolean +) +RETURNS boolean IMMUTABLE AS +$body$ +BEGIN + RAISE NOTICE 'equal booleans immutable'; + RETURN $1 = $2; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.equal_my_integer_imm ( + my_integer, + my_integer +) +RETURNS boolean IMMUTABLE AS +$body$ +BEGIN + RAISE NOTICE 'equal my_integer immutable'; + RETURN $1.value = $2.value; +END; +$body$ +LANGUAGE 'plpgsql'; +-- Create operators for testing +CREATE OPERATOR === ( + PROCEDURE = equal_integers_vlt, + LEFTARG = integer, + RIGHTARG = integer +); +CREATE OPERATOR ==== ( + PROCEDURE = equal_integers_stl, + LEFTARG = integer, + RIGHTARG = integer +); +CREATE OPERATOR ===== ( + PROCEDURE = equal_integers_imm, + LEFTARG = integer, + RIGHTARG = integer +); +CREATE OPERATOR ==== ( + PROCEDURE = equal_booleans_stl_strict, + LEFTARG = boolean, + RIGHTARG = boolean +); +CREATE OPERATOR ===== ( + PROCEDURE = equal_booleans_imm, + LEFTARG = boolean, + RIGHTARG = boolean +); +-- Functions testing +-- Simple functions testing +SELECT x_vlt() FROM x; -- should not be precalculated +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v + x_vlt +------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl() FROM x; +NOTICE: s + x_stl +------- + 1 + 1 + 1 + 1 +(4 rows) + +-- WHERE clause testing +SELECT x_vlt() FROM x WHERE x_vlt() < x; -- should not be precalculated +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v + x_vlt +------- + 1 + 1 + 1 +(3 rows) + +SELECT x_stl() FROM x WHERE x_stl() < x; +NOTICE: s +NOTICE: s +NOTICE: s + x_stl +------- + 1 + 1 + 1 +(3 rows) + +-- JOIN/ON clause testing +-- should not be precalculated +SELECT * FROM x JOIN generate_series(1, 2) y ON x_vlt() < x; +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v + x | y +---+--- + 2 | 1 + 3 | 1 + 4 | 1 + 2 | 2 + 3 | 2 + 4 | 2 +(6 rows) + +SELECT * FROM x JOIN generate_series(1, 2) y ON x_stl() < x; +NOTICE: s +NOTICE: s + x | y +---+--- + 2 | 1 + 3 | 1 + 4 | 1 + 2 | 2 + 3 | 2 + 4 | 2 +(6 rows) + +-- Functions with constant arguments testing +SELECT x_vlt2(1) FROM x; -- should not be precalculated +NOTICE: v2 +NOTICE: v2 +NOTICE: v2 +NOTICE: v2 + x_vlt2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(1) FROM x; +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Nested functions testing +SELECT x_stl2(x_vlt()) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_imm2(x_vlt()) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: i2 +NOTICE: v +NOTICE: i2 +NOTICE: v +NOTICE: i2 +NOTICE: v +NOTICE: i2 + x_imm2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(x_stl()) FROM x; +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_imm2(x_stl()) FROM x; +NOTICE: s +NOTICE: i2 + x_imm2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Strict functions testing +SELECT x_stl2_strict(x_vlt()) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: s2 strict +NOTICE: v +NOTICE: s2 strict +NOTICE: v +NOTICE: s2 strict +NOTICE: v +NOTICE: s2 strict + x_stl2_strict +--------------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_imm2_strict(x_vlt()) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: i2 strict +NOTICE: v +NOTICE: i2 strict +NOTICE: v +NOTICE: i2 strict +NOTICE: v +NOTICE: i2 strict + x_imm2_strict +--------------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2_strict(x_stl2_strict(1)) FROM x; +NOTICE: s2 strict +NOTICE: s2 strict + x_stl2_strict +--------------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_imm2_strict(x_stl2_strict(1)) FROM x; +NOTICE: s2 strict +NOTICE: i2 strict + x_imm2_strict +--------------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Strict functions with null arguments testing +SELECT x_stl2_strict(x_stl2(NULL)) FROM x; +NOTICE: s2 + x_stl2_strict +--------------- + + + + +(4 rows) + +SELECT x_imm2_strict(x_stl2(NULL)) FROM x; +NOTICE: s2 + x_imm2_strict +--------------- + + + + +(4 rows) + +-- Operators testing +SELECT 1 === 2 FROM x; -- should not be precalculated +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== 2 FROM x; +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- Strict operators testing +SELECT x_stl2_boolean(NULL) ==== TRUE FROM x; +NOTICE: s2 boolean + ?column? +---------- + + + + +(4 rows) + +SELECT x_stl2_boolean(NULL) ===== TRUE FROM x; +NOTICE: s2 boolean +NOTICE: equal booleans immutable + ?column? +---------- + + + + +(4 rows) + +-- Mixed functions and operators testing +SELECT x_stl2_boolean(1 === 2) FROM x; -- should not be precalculated +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(1 ==== 2) FROM x; +NOTICE: equal integers stable +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_vlt() ==== 1 FROM x; -- should not be precalculated +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable + ?column? +---------- + t + t + t + t +(4 rows) + +SELECT x_stl() ==== 1 FROM x; +NOTICE: s +NOTICE: equal integers stable + ?column? +---------- + t + t + t + t +(4 rows) + +-- IS (NOT) DISTINCT FROM expression testing +-- create operator here because we will drop and reuse it several times +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT '(1)'::my_integer IS DISTINCT FROM '(2)'::my_integer FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile + ?column? +---------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT '(1)'::my_integer IS NOT DISTINCT FROM '(2)'::my_integer FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile + ?column? +---------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT '(1)'::my_integer IS DISTINCT FROM '(2)'::my_integer FROM x; +NOTICE: equal my_integer stable + ?column? +---------- + t + t + t + t +(4 rows) + +SELECT '(1)'::my_integer IS NOT DISTINCT FROM '(2)'::my_integer FROM x; +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- IS (NOT) DISTINCT FROM expressions with null arguments testing +SELECT x_stl2_boolean(x_stl2(NULL) IS DISTINCT FROM 1) FROM x; +NOTICE: s2 +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2(NULL) IS NOT DISTINCT FROM 1) FROM x; +NOTICE: s2 +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl2(NULL) IS DISTINCT FROM x_stl2(NULL)) FROM x; +NOTICE: s2 +NOTICE: s2 +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl2(NULL) IS NOT DISTINCT FROM x_stl2(NULL)) FROM x; +NOTICE: s2 +NOTICE: s2 +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- Mixed functions and IS (NOT) DISTINCT FROM expressions testing +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT equal_booleans_stl_strict( + ('(1)'::my_integer IS DISTINCT FROM '(1)'::my_integer), + ('(1)'::my_integer IS NOT DISTINCT FROM '(1)'::my_integer) +) +FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal booleans stable strict +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal booleans stable strict +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal booleans stable strict +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal booleans stable strict + equal_booleans_stl_strict +--------------------------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT equal_booleans_stl_strict( + ('(1)'::my_integer IS DISTINCT FROM '(1)'::my_integer), + ('(1)'::my_integer IS NOT DISTINCT FROM '(1)'::my_integer) +) +FROM x; +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: equal booleans stable strict + equal_booleans_stl_strict +--------------------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT (x_vlt_my_integer() IS DISTINCT FROM '(1)'::my_integer) FROM x; +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT (x_vlt_my_integer() IS NOT DISTINCT FROM '(1)'::my_integer) FROM x; +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable + ?column? +---------- + t + t + t + t +(4 rows) + +SELECT (x_stl_my_integer() IS DISTINCT FROM '(1)'::my_integer) FROM x; +NOTICE: s my_integer +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT (x_stl_my_integer() IS NOT DISTINCT FROM '(1)'::my_integer) FROM x; +NOTICE: s my_integer +NOTICE: equal my_integer stable + ?column? +---------- + t + t + t + t +(4 rows) + +-- NULLIF expressions testing +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT NULLIF('(1)'::my_integer, '(2)'::my_integer) FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile + nullif +-------- + (1) + (1) + (1) + (1) +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT NULLIF('(1)'::my_integer, '(2)'::my_integer) FROM x; +NOTICE: equal my_integer stable + nullif +-------- + (1) + (1) + (1) + (1) +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_imm, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT NULLIF('(1)'::my_integer, '(2)'::my_integer) FROM x; +NOTICE: equal my_integer immutable + nullif +-------- + (1) + (1) + (1) + (1) +(4 rows) + +-- NULLIF expressions with null arguments testing +SELECT x_stl2(NULLIF(1, NULL)) FROM x; +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(NULLIF(NULL::integer, NULL)) FROM x; +NOTICE: s2 + x_stl2 +-------- + + + + +(4 rows) + +-- Mixed functions and NULLIF expressions testing +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT equal_my_integer_stl( + NULLIF('(1)'::my_integer, '(2)'::my_integer), + NULLIF('(2)'::my_integer, '(2)'::my_integer) +) +FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer stable +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer stable +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer stable +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer stable + equal_my_integer_stl +---------------------- + + + + +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT equal_my_integer_stl( + NULLIF('(1)'::my_integer, '(2)'::my_integer), + NULLIF('(2)'::my_integer, '(2)'::my_integer) +) +FROM x; +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable + equal_my_integer_stl +---------------------- + + + + +(4 rows) + +-- should not be precalculated +SELECT NULLIF(x_vlt_my_integer(), '(2)'::my_integer) FROM x; +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable + nullif +-------- + (1) + (1) + (1) + (1) +(4 rows) + +SELECT NULLIF(x_stl_my_integer(), '(2)'::my_integer) FROM x; +NOTICE: s my_integer +NOTICE: equal my_integer stable + nullif +-------- + (1) + (1) + (1) + (1) +(4 rows) + +-- "scalar op ANY/ALL (array)" / "scalar IN (2 or more values)" expressions +-- testing +SELECT 1 === ANY ('{2, 3}') FROM x; -- should not be precalculated +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 === ALL ('{2, 3}') FROM x; -- should not be precalculated +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile + ?column? +---------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== ANY ('{2, 3}') FROM x; +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== ALL ('{2, 3}') FROM x; +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ===== ANY ('{2, 3}') FROM x; +NOTICE: equal integers immutable +NOTICE: equal integers immutable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ===== ALL ('{2, 3}') FROM x; +NOTICE: equal integers immutable + ?column? +---------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_imm, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; +NOTICE: equal my_integer immutable +NOTICE: equal my_integer immutable + ?column? +---------- + f + f + f + f +(4 rows) + +-- "scalar op ANY/ALL (array)" / "scalar IN (2 or more values)" expressions with +-- null arguments testing +SELECT 1 ==== ANY ('{2, NULL}') FROM x; +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + + + + +(4 rows) + +SELECT x_stl2_boolean(1 ==== ANY (NULL)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + + + + +(4 rows) + +SELECT NULL ==== ANY ('{2, 3}'::integer[]) FROM x; +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + + + + +(4 rows) + +SELECT NULL ==== ANY ('{2, NULL}'::integer[]) FROM x; +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + + + + +(4 rows) + +SELECT x_stl2_boolean(NULL::integer ==== ANY (NULL)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + + + + +(4 rows) + +SELECT 1 ==== ALL ('{2, NULL}') FROM x; +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(1 ==== ALL (NULL)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + + + + +(4 rows) + +SELECT NULL ==== ALL ('{2, 3}'::integer[]) FROM x; +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + + + + +(4 rows) + +SELECT NULL ==== ALL ('{2, NULL}'::integer[]) FROM x; +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + + + + +(4 rows) + +SELECT x_stl2_boolean(NULL::integer ==== ALL (NULL)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + + + + +(4 rows) + +SELECT x_stl2_boolean(1 IN (2, NULL)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + + + + +(4 rows) + +SELECT x_stl2_boolean(NULL IN (2, 3)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + + + + +(4 rows) + +SELECT x_stl2_boolean(NULL IN (2, NULL)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + + + + +(4 rows) + +-- Mixed functions and "scalar op ANY/ALL (array)" / "scalar IN (2 or more +-- values)" expressions testing +-- should not be precalculated +SELECT x_stl2_boolean(1 === ANY ('{2, 3}')) FROM x; +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(1 === ALL ('{2, 3}')) FROM x; +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT x_stl2_boolean( + '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) +) +FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: s2 boolean +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: s2 boolean +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: s2 boolean +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(1 ==== ANY ('{2, 3}')) FROM x; +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(1 ==== ALL ('{2, 3}')) FROM x; +NOTICE: equal integers stable +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT x_stl2_boolean( + '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) +) +FROM x; +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_vlt() ==== ANY ('{2, 3}') FROM x; +NOTICE: v +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_vlt() ==== ALL ('{2, 3}') FROM x; +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT 1 ==== ANY (x_vlt_array_integer()) FROM x; +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT 1 ==== ALL (x_vlt_array_integer()) FROM x; +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_vlt_my_integer() IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT x_stl() ==== ANY ('{2, 3}') FROM x; +NOTICE: s +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT x_stl() ==== ALL ('{2, 3}') FROM x; +NOTICE: s +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== ANY (x_stl_array_integer()) FROM x; +NOTICE: s array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== ALL (x_stl_array_integer()) FROM x; +NOTICE: s array_integer +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT x_stl_my_integer() IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; +NOTICE: s my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- Boolean expressions testing +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() AND x_stl2_boolean(TRUE)) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() OR x_stl2_boolean(TRUE)) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(NOT x_vlt_boolean()) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) AND x_stl2_boolean(TRUE)) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) OR x_stl2_boolean(TRUE)) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(NOT x_stl2_boolean(TRUE)) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- ARRAY[] expressions testing +-- should not be precalculated +SELECT x_stl2_array_integer(ARRAY[x_vlt(), 2]) FROM x; +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1,2} + {1,2} + {1,2} + {1,2} +(4 rows) + +SELECT x_stl2_array_integer(ARRAY[x_stl(), 2]) FROM x; +NOTICE: s +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1,2} + {1,2} + {1,2} + {1,2} +(4 rows) + +-- Multidimensional ARRAY[] expressions testing +-- should not be precalculated +SELECT x_stl2_array_integer(ARRAY[[x_vlt(), 2], [3, 4]]) FROM x; +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {{1,2},{3,4}} + {{1,2},{3,4}} + {{1,2},{3,4}} + {{1,2},{3,4}} +(4 rows) + +SELECT x_stl2_array_integer(ARRAY[[x_stl(), 2], [3, 4]]) FROM x; +NOTICE: s +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {{1,2},{3,4}} + {{1,2},{3,4}} + {{1,2},{3,4}} + {{1,2},{3,4}} +(4 rows) + +-- Array subscripting operations testing +SELECT x_stl2(('{1, 2}'::integer[])[1]) FROM x; +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2_array_integer(('{1, 2}'::integer[])[:]) FROM x; +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1,2} + {1,2} + {1,2} + {1,2} +(4 rows) + +-- Mixed functions and array subscripting operations testing +-- should not be precalculated +SELECT x_stl2((x_vlt_array_integer())[x_vlt()]) FROM x; +NOTICE: v array_integer +NOTICE: v +NOTICE: s2 +NOTICE: v array_integer +NOTICE: v +NOTICE: s2 +NOTICE: v array_integer +NOTICE: v +NOTICE: s2 +NOTICE: v array_integer +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +-- should not be precalculated +SELECT x_stl2((x_vlt_array_integer())[1]) FROM x; +NOTICE: v array_integer +NOTICE: s2 +NOTICE: v array_integer +NOTICE: s2 +NOTICE: v array_integer +NOTICE: s2 +NOTICE: v array_integer +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +-- should not be precalculated +SELECT x_stl2_array_integer((x_vlt_array_integer())[:]) FROM x; +NOTICE: v array_integer +NOTICE: s2 array_integer +NOTICE: v array_integer +NOTICE: s2 array_integer +NOTICE: v array_integer +NOTICE: s2 array_integer +NOTICE: v array_integer +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {2,3} + {2,3} + {2,3} + {2,3} +(4 rows) + +-- should not be precalculated +SELECT x_stl2(('{1, 2}'::integer[])[x_vlt()]) FROM x; +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2((x_stl_array_integer())[x_stl()]) FROM x; +NOTICE: s array_integer +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +SELECT x_stl2((x_stl_array_integer())[1]) FROM x; +NOTICE: s array_integer +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +SELECT x_stl2_array_integer((x_stl_array_integer())[:]) FROM x; +NOTICE: s array_integer +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {2,3} + {2,3} + {2,3} + {2,3} +(4 rows) + +SELECT x_stl2(('{1, 2}'::integer[])[x_stl()]) FROM x; +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- FieldSelect expressions testing +SELECT x_stl2(('(1, {2}, TRUE, 3)'::wxyz).w) FROM x; +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(('(1)'::my_integer).value) FROM x; +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Mixed functions and FieldSelect expressions testing +SELECT x_stl2((x_vlt_wxyz()).w) FROM x; -- should not be precalculated +NOTICE: v wxyz +NOTICE: s2 +NOTICE: v wxyz +NOTICE: s2 +NOTICE: v wxyz +NOTICE: s2 +NOTICE: v wxyz +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2((x_vlt_my_integer()).value) FROM x; -- should not be precalculated +NOTICE: v my_integer +NOTICE: s2 +NOTICE: v my_integer +NOTICE: s2 +NOTICE: v my_integer +NOTICE: s2 +NOTICE: v my_integer +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2((x_stl_wxyz()).w) FROM x; +NOTICE: s wxyz +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2((x_stl_my_integer()).value) FROM x; +NOTICE: s my_integer +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- ROW() expressions testing +SELECT x_stl2_wxyz((1, '{2}', TRUE, 3)) FROM x; +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz(ROW(1, '{2}', TRUE, 3)) FROM x; +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz((1, '{2}', TRUE, 3)::wxyz) FROM x; +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_composite_type((1, '{2}', TRUE)) FROM x; +NOTICE: s2 composite_type + x_stl2_composite_type +----------------------- + (1,{2},t) + (1,{2},t) + (1,{2},t) + (1,{2},t) +(4 rows) + +SELECT x_stl2_composite_type(ROW(1, '{2}', TRUE)) FROM x; +NOTICE: s2 composite_type + x_stl2_composite_type +----------------------- + (1,{2},t) + (1,{2},t) + (1,{2},t) + (1,{2},t) +(4 rows) + +SELECT x_stl2_composite_type((1, '{2}', TRUE)::composite_type) FROM x; +NOTICE: s2 composite_type + x_stl2_composite_type +----------------------- + (1,{2},t) + (1,{2},t) + (1,{2},t) + (1,{2},t) +(4 rows) + +-- Mixed functions and ROW() expressions testing +-- should not be precalculated +SELECT x_stl2_wxyz((x_vlt(), '{2}', TRUE, 3)) FROM x; +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz((x_stl(), '{2}', TRUE, 3)) FROM x; +NOTICE: s +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +-- RelabelType expressions testing +-- should not be precalculated +SELECT x_stl2(x_vlt_oid()::integer) FROM x; +NOTICE: v oid +NOTICE: s2 +NOTICE: v oid +NOTICE: s2 +NOTICE: v oid +NOTICE: s2 +NOTICE: v oid +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(x_stl_oid()::integer) FROM x; +NOTICE: s oid +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- CoerceViaIO expressions testing +SELECT x_stl2_my_integer('(1)'::text::my_integer) FROM x; +NOTICE: s2 my_integer + x_stl2_my_integer +------------------- + (1) + (1) + (1) + (1) +(4 rows) + +-- should not be precalculated +SELECT x_stl2(x_vlt_text_integer()::integer) FROM x; +NOTICE: v text integer +NOTICE: s2 +NOTICE: v text integer +NOTICE: s2 +NOTICE: v text integer +NOTICE: s2 +NOTICE: v text integer +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(x_stl_text_integer()::integer) FROM x; +NOTICE: s text integer +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Mixed functions and CoerceViaIO expressions testing +-- should not be precalculated +SELECT x_stl2_my_integer(x_vlt_text_my_integer()::my_integer) FROM x; +NOTICE: v text my_integer +NOTICE: s2 my_integer +NOTICE: v text my_integer +NOTICE: s2 my_integer +NOTICE: v text my_integer +NOTICE: s2 my_integer +NOTICE: v text my_integer +NOTICE: s2 my_integer + x_stl2_my_integer +------------------- + (1) + (1) + (1) + (1) +(4 rows) + +SELECT x_stl2_my_integer(x_stl_text_my_integer()::my_integer) FROM x; +NOTICE: s text my_integer +NOTICE: s2 my_integer + x_stl2_my_integer +------------------- + (1) + (1) + (1) + (1) +(4 rows) + +-- ArrayCoerce expressions testing +-- Binary-coercible types: +-- should not be precalculated +SELECT x_stl2_array_oid(x_vlt_array_integer()::oid[]) FROM x; +NOTICE: v array_integer +NOTICE: s2 array_oid +NOTICE: v array_integer +NOTICE: s2 array_oid +NOTICE: v array_integer +NOTICE: s2 array_oid +NOTICE: v array_integer +NOTICE: s2 array_oid + x_stl2_array_oid +------------------ + {2,3} + {2,3} + {2,3} + {2,3} +(4 rows) + +SELECT x_stl2_array_oid(x_stl_array_integer()::oid[]) FROM x; +NOTICE: s array_integer +NOTICE: s2 array_oid + x_stl2_array_oid +------------------ + {2,3} + {2,3} + {2,3} + {2,3} +(4 rows) + +-- Not binary-coercible types: +-- create cast here because we will drop and reuse it several times +CREATE CAST (integer AS my_integer) + WITH FUNCTION cast_integer_as_my_integer_vlt; +SELECT '{1, 2}'::integer[]::my_integer[] FROM x; -- should not be precalculated +NOTICE: cast integer as my_integer volatile +NOTICE: cast integer as my_integer volatile +NOTICE: cast integer as my_integer volatile +NOTICE: cast integer as my_integer volatile +NOTICE: cast integer as my_integer volatile +NOTICE: cast integer as my_integer volatile +NOTICE: cast integer as my_integer volatile +NOTICE: cast integer as my_integer volatile + my_integer +------------ + {(1),(2)} + {(1),(2)} + {(1),(2)} + {(1),(2)} +(4 rows) + +DROP CAST (integer AS my_integer); +CREATE CAST (integer AS my_integer) + WITH FUNCTION cast_integer_as_my_integer_stl; +SELECT '{1, 2}'::integer[]::my_integer[] FROM x; +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable + my_integer +------------ + {(1),(2)} + {(1),(2)} + {(1),(2)} + {(1),(2)} +(4 rows) + +-- Mixed functions and ArrayCoerce expressions testing +-- Not binary-coercible types: +-- create cast here because we will drop and reuse it several times +CREATE CAST (my_integer AS integer) + WITH FUNCTION cast_my_integer_as_integer_vlt; +-- should not be precalculated +SELECT x_stl2_array_integer('{(1), (2)}'::my_integer[]::integer[]) FROM x; +NOTICE: cast my_integer as integer volatile +NOTICE: cast my_integer as integer volatile +NOTICE: s2 array_integer +NOTICE: cast my_integer as integer volatile +NOTICE: cast my_integer as integer volatile +NOTICE: s2 array_integer +NOTICE: cast my_integer as integer volatile +NOTICE: cast my_integer as integer volatile +NOTICE: s2 array_integer +NOTICE: cast my_integer as integer volatile +NOTICE: cast my_integer as integer volatile +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1,2} + {1,2} + {1,2} + {1,2} +(4 rows) + +DROP CAST (my_integer AS integer); +CREATE CAST (my_integer AS integer) + WITH FUNCTION cast_my_integer_as_integer_stl; +SELECT x_stl2_array_integer('{(1), (2)}'::my_integer[]::integer[]) FROM x; +NOTICE: cast my_integer as integer stable +NOTICE: cast my_integer as integer stable +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1,2} + {1,2} + {1,2} + {1,2} +(4 rows) + +DROP CAST (integer AS my_integer); +CREATE CAST (integer AS my_integer) + WITH FUNCTION cast_integer_as_my_integer_stl; +-- should not be precalculated +SELECT x_vlt_array_integer()::my_integer[] FROM x; +NOTICE: v array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable +NOTICE: v array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable +NOTICE: v array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable +NOTICE: v array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable + x_vlt_array_integer +--------------------- + {(2),(3)} + {(2),(3)} + {(2),(3)} + {(2),(3)} +(4 rows) + +SELECT x_stl_array_integer()::my_integer[] FROM x; +NOTICE: s array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable + x_stl_array_integer +--------------------- + {(2),(3)} + {(2),(3)} + {(2),(3)} + {(2),(3)} +(4 rows) + +-- ConvertRowtypeExpr testing +SELECT x_stl2_wxyz('(1, {2}, TRUE, 3)'::wxyz_child::wxyz) FROM x; +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz('(1, {2}, TRUE, 3, 4, 5)'::wxyz_child2::wxyz) FROM x; +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_no_columns('()'::no_columns_child::no_columns) FROM x; +NOTICE: s2 no_columns + x_stl2_no_columns +------------------- + () + () + () + () +(4 rows) + +SELECT x_stl2_no_columns('(1, 2)'::no_columns_child2::no_columns) FROM x; +NOTICE: s2 no_columns + x_stl2_no_columns +------------------- + () + () + () + () +(4 rows) + +-- Mixed functions and ConvertRowtypeExpr testing +-- should not be precalculated +SELECT x_stl2_wxyz(x_vlt_wxyz_child()::wxyz_child::wxyz) FROM x; +NOTICE: v wxyz_child +NOTICE: s2 wxyz +NOTICE: v wxyz_child +NOTICE: s2 wxyz +NOTICE: v wxyz_child +NOTICE: s2 wxyz +NOTICE: v wxyz_child +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +-- should not be precalculated +SELECT x_stl2_wxyz(x_vlt_wxyz_child2()::wxyz_child2::wxyz) FROM x; +NOTICE: v wxyz_child2 +NOTICE: s2 wxyz +NOTICE: v wxyz_child2 +NOTICE: s2 wxyz +NOTICE: v wxyz_child2 +NOTICE: s2 wxyz +NOTICE: v wxyz_child2 +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz(x_stl_wxyz_child()::wxyz_child::wxyz) FROM x; +NOTICE: s wxyz_child +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz(x_stl_wxyz_child2()::wxyz_child2::wxyz) FROM x; +NOTICE: s wxyz_child2 +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +-- CASE expressions testing +-- should not be precalculated +SELECT x_stl2(CASE WHEN x_vlt_boolean() THEN x_vlt() ELSE x_vlt() END) FROM x; +NOTICE: v boolean +NOTICE: v +NOTICE: s2 +NOTICE: v boolean +NOTICE: v +NOTICE: s2 +NOTICE: v boolean +NOTICE: v +NOTICE: s2 +NOTICE: v boolean +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- should not be precalculated +SELECT x_stl2(CASE x_vlt() WHEN x_vlt() THEN x_vlt() ELSE x_vlt() END) FROM x; +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(CASE WHEN x_stl2_boolean(TRUE) THEN x_stl() ELSE x_stl() END) +FROM x; +NOTICE: s2 boolean +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(CASE x_stl() WHEN x_stl() THEN x_stl() ELSE x_stl() END) FROM x; +NOTICE: s +NOTICE: s +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- RowCompareExpr testing +SELECT x_stl2_boolean((1, 2) < (1, 3)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- Mixed functions and RowCompareExpr testing +-- should not be precalculated +SELECT x_stl2_boolean((x_vlt(), 2) < (1, 3)) FROM x; +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean((x_stl(), 2) < (1, 3)) FROM x; +NOTICE: s +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- COALESCE expressions testing +-- should not be precalculated +SELECT x_stl2(COALESCE(NULL, x_vlt2(NULL), 2)) FROM x; +NOTICE: v2 +NOTICE: s2 +NOTICE: v2 +NOTICE: s2 +NOTICE: v2 +NOTICE: s2 +NOTICE: v2 +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +SELECT x_stl2(COALESCE(NULL, x_stl2(NULL), 2)) FROM x; +NOTICE: s2 +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +-- GREATEST and LEAST functions testing +SELECT x_stl2(GREATEST(2, 1, 3)) FROM x; +NOTICE: s2 + x_stl2 +-------- + 3 + 3 + 3 + 3 +(4 rows) + +SELECT x_stl2(LEAST(2, 1, 3)) FROM x; +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Mixed functions and GREATEST and LEAST functions testing +-- should not be precalculated +SELECT x_stl2(GREATEST(2, x_vlt(), 3)) FROM x; +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 3 + 3 + 3 + 3 +(4 rows) + +-- should not be precalculated +SELECT x_stl2(LEAST(2, x_vlt(), 3)) FROM x; +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(GREATEST(2, x_stl(), 3)) FROM x; +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 3 + 3 + 3 + 3 +(4 rows) + +SELECT x_stl2(LEAST(2, x_stl(), 3)) FROM x; +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- SQLValueFunction testing +CREATE ROLE regress_testrol2 SUPERUSER; +CREATE ROLE regress_testrol1 SUPERUSER LOGIN IN ROLE regress_testrol2; +\c - +SET SESSION AUTHORIZATION regress_testrol1; +SET ROLE regress_testrol2; +SELECT x_stl2_boolean(date(now()) = current_date) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(now()::timetz = current_time) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(now()::timetz(2) = current_time(2)) FROM x; -- precision +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(now() = current_timestamp) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- precision +SELECT x_stl2_boolean( + length(current_timestamp::text) >= length(current_timestamp(0)::text) +) +FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(now()::time = localtime) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(now()::time(2) = localtime(2)) FROM x; -- precision +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(now()::timestamp = localtimestamp) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- precision +SELECT x_stl2_boolean(now()::timestamp(2) = localtimestamp(2)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_name(current_role) FROM x; +NOTICE: s2 name + x_stl2_name +------------------ + regress_testrol2 + regress_testrol2 + regress_testrol2 + regress_testrol2 +(4 rows) + +SELECT x_stl2_name(current_user) FROM x; +NOTICE: s2 name + x_stl2_name +------------------ + regress_testrol2 + regress_testrol2 + regress_testrol2 + regress_testrol2 +(4 rows) + +SELECT x_stl2_name(user) FROM x; +NOTICE: s2 name + x_stl2_name +------------------ + regress_testrol2 + regress_testrol2 + regress_testrol2 + regress_testrol2 +(4 rows) + +SELECT x_stl2_name(session_user) FROM x; +NOTICE: s2 name + x_stl2_name +------------------ + regress_testrol1 + regress_testrol1 + regress_testrol1 + regress_testrol1 +(4 rows) + +SELECT x_stl2_name(current_catalog) FROM x; +NOTICE: s2 name + x_stl2_name +------------- + regression + regression + regression + regression +(4 rows) + +SELECT x_stl2_name(current_schema) FROM x; +NOTICE: s2 name + x_stl2_name +------------- + public + public + public + public +(4 rows) + +\c +DROP ROLE regress_testrol1, regress_testrol2; +-- Xml expressions testing +SELECT x_stl2_xml(XMLCONCAT('', 'foo')) FROM x; +NOTICE: s2 xml + x_stl2_xml +---------------------- + foo + foo + foo + foo +(4 rows) + +SELECT x_stl2_xml( + XMLELEMENT(name foo, xmlattributes('bar' as bar), 'cont', 'ent') +) +FROM x; +NOTICE: s2 xml + x_stl2_xml +------------------------------ + content + content + content + content +(4 rows) + +SELECT x_stl2_xml(XMLFOREST('abc' AS foo, 123 AS bar)) FROM x; +NOTICE: s2 xml + x_stl2_xml +------------------------------ + abc123 + abc123 + abc123 + abc123 +(4 rows) + +SELECT x_stl2_xml(XMLPARSE( + DOCUMENT 'Manual' +)) +FROM x; +NOTICE: s2 xml + x_stl2_xml +------------------------------------ + Manual + Manual + Manual + Manual +(4 rows) + +SELECT x_stl2_xml(XMLPARSE(CONTENT 'abcbarfoo')) FROM x; +NOTICE: s2 xml + x_stl2_xml +--------------------------------- + abcbarfoo + abcbarfoo + abcbarfoo + abcbarfoo +(4 rows) + +SELECT x_stl2_xml(XMLPI(name php, 'echo "hello world";')) FROM x; +NOTICE: s2 xml + x_stl2_xml +----------------------------- + + + + +(4 rows) + +SELECT x_stl2_xml(XMLROOT( + 'abc', + version '1.0', + standalone yes +)) +FROM x; +NOTICE: s2 xml + x_stl2_xml +-------------------------------------------------------------- + abc + abc + abc + abc +(4 rows) + +SELECT x_stl2_text(XMLSERIALIZE( + DOCUMENT 'Manual' AS text +)) +FROM x; +NOTICE: s2 text + x_stl2_text +--------------------------------------------------------- + Manual + Manual + Manual + Manual +(4 rows) + +SELECT x_stl2_text(XMLSERIALIZE( + CONTENT 'abcbarfoo' AS text +)) +FROM x; +NOTICE: s2 text + x_stl2_text +--------------------------------- + abcbarfoo + abcbarfoo + abcbarfoo + abcbarfoo +(4 rows) + +SELECT x_stl2_boolean('abcbarfoo' IS DOCUMENT) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- Mixed functions and Xml expressions testing +-- should not be precalculated +SELECT x_stl2_xml(XMLCONCAT('', x_vlt_xml())) FROM x; +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml + x_stl2_xml +---------------------- + foo + foo + foo + foo +(4 rows) + +-- should not be precalculated +SELECT x_stl2_xml( + XMLELEMENT(name foo, xmlattributes('bar' as bar), x_vlt_xml()) +) +FROM x; +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml + x_stl2_xml +------------------------------------- + foo + foo + foo + foo +(4 rows) + +-- should not be precalculated +SELECT x_stl2_xml(XMLFOREST('abc' AS foo, x_vlt_xml() AS bar)) FROM x; +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml + x_stl2_xml +----------------------------------------- + abcfoo + abcfoo + abcfoo + abcfoo +(4 rows) + +-- should not be precalculated +SELECT x_stl2_xml(XMLPARSE(DOCUMENT x_vlt_text_xml())) FROM x; +NOTICE: v text xml +NOTICE: s2 xml +NOTICE: v text xml +NOTICE: s2 xml +NOTICE: v text xml +NOTICE: s2 xml +NOTICE: v text xml +NOTICE: s2 xml + x_stl2_xml +------------------------------------ + Manual + Manual + Manual + Manual +(4 rows) + +-- should not be precalculated +SELECT x_stl2_xml(XMLPARSE(CONTENT x_vlt_text_xml_content())) FROM x; +NOTICE: v text xml content +NOTICE: s2 xml +NOTICE: v text xml content +NOTICE: s2 xml +NOTICE: v text xml content +NOTICE: s2 xml +NOTICE: v text xml content +NOTICE: s2 xml + x_stl2_xml +--------------------------------- + abcbarfoo + abcbarfoo + abcbarfoo + abcbarfoo +(4 rows) + +-- should not be precalculated +SELECT x_stl2_xml(XMLPI(name php, x_vlt_text_xml_instruction_content())) FROM x; +NOTICE: v text xml instruction content +NOTICE: s2 xml +NOTICE: v text xml instruction content +NOTICE: s2 xml +NOTICE: v text xml instruction content +NOTICE: s2 xml +NOTICE: v text xml instruction content +NOTICE: s2 xml + x_stl2_xml +----------------------------- + + + + +(4 rows) + +-- should not be precalculated +SELECT x_stl2_xml(XMLROOT(x_vlt_xml(), version '1.0', standalone yes)) FROM x; +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml + x_stl2_xml +------------------------------------------------------ + foo + foo + foo + foo +(4 rows) + +-- should not be precalculated +SELECT x_stl2_text(XMLSERIALIZE(DOCUMENT x_vlt_xml() AS text)) FROM x; +NOTICE: v xml +NOTICE: s2 text +NOTICE: v xml +NOTICE: s2 text +NOTICE: v xml +NOTICE: s2 text +NOTICE: v xml +NOTICE: s2 text + x_stl2_text +---------------- + foo + foo + foo + foo +(4 rows) + +-- should not be precalculated +SELECT x_stl2_text(XMLSERIALIZE(CONTENT x_vlt_xml_content() AS text)) FROM x; +NOTICE: v xml content +NOTICE: s2 text +NOTICE: v xml content +NOTICE: s2 text +NOTICE: v xml content +NOTICE: s2 text +NOTICE: v xml content +NOTICE: s2 text + x_stl2_text +--------------------------------- + abcbarfoo + abcbarfoo + abcbarfoo + abcbarfoo +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_xml_content() IS DOCUMENT) FROM x; +NOTICE: v xml content +NOTICE: s2 boolean +NOTICE: v xml content +NOTICE: s2 boolean +NOTICE: v xml content +NOTICE: s2 boolean +NOTICE: v xml content +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_xml(XMLCONCAT('', x_stl_xml())) FROM x; +NOTICE: s xml +NOTICE: s2 xml + x_stl2_xml +---------------------- + foo + foo + foo + foo +(4 rows) + +SELECT x_stl2_xml( + XMLELEMENT(name foo, xmlattributes('bar' as bar), x_stl_xml()) +) +FROM x; +NOTICE: s xml +NOTICE: s2 xml + x_stl2_xml +------------------------------------- + foo + foo + foo + foo +(4 rows) + +SELECT x_stl2_xml(XMLFOREST('abc' AS foo, x_stl_xml() AS bar)) FROM x; +NOTICE: s xml +NOTICE: s2 xml + x_stl2_xml +----------------------------------------- + abcfoo + abcfoo + abcfoo + abcfoo +(4 rows) + +SELECT x_stl2_xml(XMLPARSE(DOCUMENT x_stl_text_xml())) FROM x; +NOTICE: s text xml +NOTICE: s2 xml + x_stl2_xml +------------------------------------ + Manual + Manual + Manual + Manual +(4 rows) + +SELECT x_stl2_xml(XMLPARSE(CONTENT x_stl_text_xml_content())) FROM x; +NOTICE: s xml content +NOTICE: s2 xml + x_stl2_xml +--------------------------------- + abcbarfoo + abcbarfoo + abcbarfoo + abcbarfoo +(4 rows) + +SELECT x_stl2_xml(XMLPI(name php, x_stl_text_xml_instruction_content())) FROM x; +NOTICE: s text xml instruction content +NOTICE: s2 xml + x_stl2_xml +----------------------------- + + + + +(4 rows) + +SELECT x_stl2_xml(XMLROOT(x_stl_xml(), version '1.0', standalone yes)) FROM x; +NOTICE: s xml +NOTICE: s2 xml + x_stl2_xml +------------------------------------------------------ + foo + foo + foo + foo +(4 rows) + +SELECT x_stl2_text(XMLSERIALIZE(DOCUMENT x_stl_xml() AS text)) FROM x; +NOTICE: s xml +NOTICE: s2 text + x_stl2_text +---------------- + foo + foo + foo + foo +(4 rows) + +SELECT x_stl2_text(XMLSERIALIZE(CONTENT x_stl_xml_content() AS text)) FROM x; +NOTICE: s xml content +NOTICE: s2 text + x_stl2_text +--------------------------------- + abcbarfoo + abcbarfoo + abcbarfoo + abcbarfoo +(4 rows) + +SELECT x_stl2_boolean(x_stl_xml_content() IS DOCUMENT) FROM x; +NOTICE: s xml content +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- NullTest expressions testing +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt() IS NULL) FROM x; +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt() IS NOT NULL) FROM x; +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_wxyz() IS NULL) FROM x; +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_wxyz() IS NOT NULL) FROM x; +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl() IS NULL) FROM x; +NOTICE: s +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl() IS NOT NULL) FROM x; +NOTICE: s +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl_wxyz() IS NULL) FROM x; +NOTICE: s wxyz +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl_wxyz() IS NOT NULL) FROM x; +NOTICE: s wxyz +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- BooleanTest expressions testing +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS TRUE) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT TRUE) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS FALSE) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT FALSE) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS UNKNOWN) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT UNKNOWN) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS TRUE) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS NOT TRUE) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS FALSE) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS NOT FALSE) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(NULL) IS UNKNOWN) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(NULL) IS NOT UNKNOWN) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- Tracking functions testing +SET track_functions TO 'all'; +-- Simple functions testing +SELECT x_vlt() FROM x; -- should not be precalculated +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v + x_vlt +------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl() FROM x; +NOTICE: s + x_stl +------- + 1 + 1 + 1 + 1 +(4 rows) + +-- WHERE clause testing +SELECT x_vlt() FROM x WHERE x_vlt() < x; -- should not be precalculated +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v + x_vlt +------- + 1 + 1 + 1 +(3 rows) + +SELECT x_stl() FROM x WHERE x_stl() < x; +NOTICE: s +NOTICE: s +NOTICE: s + x_stl +------- + 1 + 1 + 1 +(3 rows) + +-- JOIN/ON clause testing +-- should not be precalculated +SELECT * FROM x JOIN generate_series(1, 2) y ON x_vlt() < x; +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v + x | y +---+--- + 2 | 1 + 3 | 1 + 4 | 1 + 2 | 2 + 3 | 2 + 4 | 2 +(6 rows) + +SELECT * FROM x JOIN generate_series(1, 2) y ON x_stl() < x; +NOTICE: s +NOTICE: s + x | y +---+--- + 2 | 1 + 3 | 1 + 4 | 1 + 2 | 2 + 3 | 2 + 4 | 2 +(6 rows) + +-- Functions with constant arguments testing +SELECT x_vlt2(1) FROM x; -- should not be precalculated +NOTICE: v2 +NOTICE: v2 +NOTICE: v2 +NOTICE: v2 + x_vlt2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(1) FROM x; +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Nested functions testing +SELECT x_stl2(x_vlt()) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_imm2(x_vlt()) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: i2 +NOTICE: v +NOTICE: i2 +NOTICE: v +NOTICE: i2 +NOTICE: v +NOTICE: i2 + x_imm2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(x_stl()) FROM x; +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_imm2(x_stl()) FROM x; +NOTICE: s +NOTICE: i2 + x_imm2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Strict functions testing +SELECT x_stl2_strict(x_vlt()) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: s2 strict +NOTICE: v +NOTICE: s2 strict +NOTICE: v +NOTICE: s2 strict +NOTICE: v +NOTICE: s2 strict + x_stl2_strict +--------------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_imm2_strict(x_vlt()) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: i2 strict +NOTICE: v +NOTICE: i2 strict +NOTICE: v +NOTICE: i2 strict +NOTICE: v +NOTICE: i2 strict + x_imm2_strict +--------------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2_strict(x_stl2_strict(1)) FROM x; +NOTICE: s2 strict +NOTICE: s2 strict + x_stl2_strict +--------------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_imm2_strict(x_stl2_strict(1)) FROM x; +NOTICE: s2 strict +NOTICE: i2 strict + x_imm2_strict +--------------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Strict functions with null arguments testing +SELECT x_stl2_strict(x_stl2(NULL)) FROM x; +NOTICE: s2 + x_stl2_strict +--------------- + + + + +(4 rows) + +SELECT x_imm2_strict(x_stl2(NULL)) FROM x; +NOTICE: s2 + x_imm2_strict +--------------- + + + + +(4 rows) + +-- Operators testing +SELECT 1 === 2 FROM x; -- should not be precalculated +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== 2 FROM x; +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- Strict operators testing +SELECT x_stl2_boolean(NULL) ==== TRUE FROM x; +NOTICE: s2 boolean + ?column? +---------- + + + + +(4 rows) + +SELECT x_stl2_boolean(NULL) ===== TRUE FROM x; +NOTICE: s2 boolean +NOTICE: equal booleans immutable + ?column? +---------- + + + + +(4 rows) + +-- Mixed functions and operators testing +SELECT x_stl2_boolean(1 === 2) FROM x; -- should not be precalculated +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(1 ==== 2) FROM x; +NOTICE: equal integers stable +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_vlt() ==== 1 FROM x; -- should not be precalculated +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable + ?column? +---------- + t + t + t + t +(4 rows) + +SELECT x_stl() ==== 1 FROM x; +NOTICE: s +NOTICE: equal integers stable + ?column? +---------- + t + t + t + t +(4 rows) + +-- Mixed functions and IS (NOT) DISTINCT FROM expressions testing +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT equal_booleans_stl_strict( + ('(1)'::my_integer IS DISTINCT FROM '(1)'::my_integer), + ('(1)'::my_integer IS NOT DISTINCT FROM '(1)'::my_integer) +) +FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal booleans stable strict +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal booleans stable strict +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal booleans stable strict +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal booleans stable strict + equal_booleans_stl_strict +--------------------------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT equal_booleans_stl_strict( + ('(1)'::my_integer IS DISTINCT FROM '(1)'::my_integer), + ('(1)'::my_integer IS NOT DISTINCT FROM '(1)'::my_integer) +) +FROM x; +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: equal booleans stable strict + equal_booleans_stl_strict +--------------------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT (x_vlt_my_integer() IS DISTINCT FROM '(1)'::my_integer) FROM x; +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT (x_vlt_my_integer() IS NOT DISTINCT FROM '(1)'::my_integer) FROM x; +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable + ?column? +---------- + t + t + t + t +(4 rows) + +SELECT (x_stl_my_integer() IS DISTINCT FROM '(1)'::my_integer) FROM x; +NOTICE: s my_integer +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT (x_stl_my_integer() IS NOT DISTINCT FROM '(1)'::my_integer) FROM x; +NOTICE: s my_integer +NOTICE: equal my_integer stable + ?column? +---------- + t + t + t + t +(4 rows) + +-- Mixed functions and NULLIF expressions testing +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT equal_my_integer_stl( + NULLIF('(1)'::my_integer, '(2)'::my_integer), + NULLIF('(2)'::my_integer, '(2)'::my_integer) +) +FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer stable +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer stable +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer stable +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer stable + equal_my_integer_stl +---------------------- + + + + +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT equal_my_integer_stl( + NULLIF('(1)'::my_integer, '(2)'::my_integer), + NULLIF('(2)'::my_integer, '(2)'::my_integer) +) +FROM x; +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable + equal_my_integer_stl +---------------------- + + + + +(4 rows) + +-- should not be precalculated +SELECT NULLIF(x_vlt_my_integer(), '(2)'::my_integer) FROM x; +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable + nullif +-------- + (1) + (1) + (1) + (1) +(4 rows) + +SELECT NULLIF(x_stl_my_integer(), '(2)'::my_integer) FROM x; +NOTICE: s my_integer +NOTICE: equal my_integer stable + nullif +-------- + (1) + (1) + (1) + (1) +(4 rows) + +-- Mixed functions and "scalar op ANY/ALL (array)" / "scalar IN (2 or more +-- values)" expressions testing +-- should not be precalculated +SELECT x_stl2_boolean(1 === ANY ('{2, 3}')) FROM x; +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(1 === ALL ('{2, 3}')) FROM x; +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT x_stl2_boolean( + '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) +) +FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: s2 boolean +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: s2 boolean +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: s2 boolean +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(1 ==== ANY ('{2, 3}')) FROM x; +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(1 ==== ALL ('{2, 3}')) FROM x; +NOTICE: equal integers stable +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT x_stl2_boolean( + '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) +) +FROM x; +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_vlt() ==== ANY ('{2, 3}') FROM x; -- should not be precalculated +NOTICE: v +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT x_vlt() ==== ALL ('{2, 3}') FROM x; -- should not be precalculated +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== ANY (x_vlt_array_integer()) FROM x; -- should not be precalculated +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== ALL (x_vlt_array_integer()) FROM x; -- should not be precalculated +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_vlt_my_integer() IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT x_stl() ==== ANY ('{2, 3}') FROM x; +NOTICE: s +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT x_stl() ==== ALL ('{2, 3}') FROM x; +NOTICE: s +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== ANY (x_stl_array_integer()) FROM x; +NOTICE: s array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== ALL (x_stl_array_integer()) FROM x; +NOTICE: s array_integer +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT x_stl_my_integer() IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; +NOTICE: s my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- Mixed functions and boolean expressions testing +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() AND x_stl2_boolean(TRUE)) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() OR x_stl2_boolean(TRUE)) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(NOT x_vlt_boolean()) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) AND x_stl2_boolean(TRUE)) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) OR x_stl2_boolean(TRUE)) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(NOT x_stl2_boolean(TRUE)) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- Mixed functions and ARRAY[] expressions testing +-- should not be precalculated +SELECT x_stl2_array_integer(ARRAY[x_vlt()]) FROM x; +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1} + {1} + {1} + {1} +(4 rows) + +SELECT x_stl2_array_integer(ARRAY[x_stl()]) FROM x; +NOTICE: s +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1} + {1} + {1} + {1} +(4 rows) + +-- Mixed functions and array subscripting operations testing +-- should not be precalculated +SELECT x_stl2((x_vlt_array_integer())[x_vlt()]) FROM x; +NOTICE: v array_integer +NOTICE: v +NOTICE: s2 +NOTICE: v array_integer +NOTICE: v +NOTICE: s2 +NOTICE: v array_integer +NOTICE: v +NOTICE: s2 +NOTICE: v array_integer +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +-- should not be precalculated +SELECT x_stl2((x_vlt_array_integer())[1]) FROM x; +NOTICE: v array_integer +NOTICE: s2 +NOTICE: v array_integer +NOTICE: s2 +NOTICE: v array_integer +NOTICE: s2 +NOTICE: v array_integer +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +-- should not be precalculated +SELECT x_stl2_array_integer((x_vlt_array_integer())[:]) FROM x; +NOTICE: v array_integer +NOTICE: s2 array_integer +NOTICE: v array_integer +NOTICE: s2 array_integer +NOTICE: v array_integer +NOTICE: s2 array_integer +NOTICE: v array_integer +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {2,3} + {2,3} + {2,3} + {2,3} +(4 rows) + +-- should not be precalculated +SELECT x_stl2(('{1, 2}'::integer[])[x_vlt()]) FROM x; +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2((x_stl_array_integer())[x_stl()]) FROM x; +NOTICE: s array_integer +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +SELECT x_stl2((x_stl_array_integer())[1]) FROM x; +NOTICE: s array_integer +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +SELECT x_stl2_array_integer((x_stl_array_integer())[:]) FROM x; +NOTICE: s array_integer +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {2,3} + {2,3} + {2,3} + {2,3} +(4 rows) + +SELECT x_stl2(('{1, 2}'::integer[])[x_stl()]) FROM x; +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Mixed functions and FieldSelect expressions testing +SELECT x_stl2((x_vlt_wxyz()).w) FROM x; -- should not be precalculated +NOTICE: v wxyz +NOTICE: s2 +NOTICE: v wxyz +NOTICE: s2 +NOTICE: v wxyz +NOTICE: s2 +NOTICE: v wxyz +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2((x_vlt_my_integer()).value) FROM x; -- should not be precalculated +NOTICE: v my_integer +NOTICE: s2 +NOTICE: v my_integer +NOTICE: s2 +NOTICE: v my_integer +NOTICE: s2 +NOTICE: v my_integer +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2((x_stl_wxyz()).w) FROM x; +NOTICE: s wxyz +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2((x_stl_my_integer()).value) FROM x; +NOTICE: s my_integer +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Mixed functions and ROW() expressions testing +-- should not be precalculated +SELECT x_stl2_wxyz((x_vlt(), '{2}', TRUE, 3)) FROM x; +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz((x_stl(), '{2}', TRUE, 3)) FROM x; +NOTICE: s +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +-- Mixed functions and RelabelType expressions testing +SELECT x_stl2(x_vlt_oid()::integer) FROM x; -- should not be precalculated +NOTICE: v oid +NOTICE: s2 +NOTICE: v oid +NOTICE: s2 +NOTICE: v oid +NOTICE: s2 +NOTICE: v oid +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(x_stl_oid()::integer) FROM x; +NOTICE: s oid +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Mixed functions and CoerceViaIO expressions testing +-- should not be precalculated +SELECT x_stl2(x_vlt_text_integer()::integer) FROM x; +NOTICE: v text integer +NOTICE: s2 +NOTICE: v text integer +NOTICE: s2 +NOTICE: v text integer +NOTICE: s2 +NOTICE: v text integer +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(x_stl_text_integer()::integer) FROM x; +NOTICE: s text integer +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- should not be precalculated +SELECT x_stl2_my_integer(x_vlt_text_my_integer()::my_integer) FROM x; +NOTICE: v text my_integer +NOTICE: s2 my_integer +NOTICE: v text my_integer +NOTICE: s2 my_integer +NOTICE: v text my_integer +NOTICE: s2 my_integer +NOTICE: v text my_integer +NOTICE: s2 my_integer + x_stl2_my_integer +------------------- + (1) + (1) + (1) + (1) +(4 rows) + +SELECT x_stl2_my_integer(x_stl_text_my_integer()::my_integer) FROM x; +NOTICE: s text my_integer +NOTICE: s2 my_integer + x_stl2_my_integer +------------------- + (1) + (1) + (1) + (1) +(4 rows) + +-- Mixed functions and ArrayCoerce expressions testing +-- Binary-coercible types: +-- should not be precalculated +SELECT x_stl2_array_oid(x_vlt_array_integer()::oid[]) FROM x; +NOTICE: v array_integer +NOTICE: s2 array_oid +NOTICE: v array_integer +NOTICE: s2 array_oid +NOTICE: v array_integer +NOTICE: s2 array_oid +NOTICE: v array_integer +NOTICE: s2 array_oid + x_stl2_array_oid +------------------ + {2,3} + {2,3} + {2,3} + {2,3} +(4 rows) + +SELECT x_stl2_array_oid(x_stl_array_integer()::oid[]) FROM x; +NOTICE: s array_integer +NOTICE: s2 array_oid + x_stl2_array_oid +------------------ + {2,3} + {2,3} + {2,3} + {2,3} +(4 rows) + +-- Not binary-coercible types: +DROP CAST (my_integer AS integer); +CREATE CAST (my_integer AS integer) + WITH FUNCTION cast_my_integer_as_integer_vlt; +-- should not be precalculated +SELECT x_stl2_array_integer('{(1), (2)}'::my_integer[]::integer[]) FROM x; +NOTICE: cast my_integer as integer volatile +NOTICE: cast my_integer as integer volatile +NOTICE: s2 array_integer +NOTICE: cast my_integer as integer volatile +NOTICE: cast my_integer as integer volatile +NOTICE: s2 array_integer +NOTICE: cast my_integer as integer volatile +NOTICE: cast my_integer as integer volatile +NOTICE: s2 array_integer +NOTICE: cast my_integer as integer volatile +NOTICE: cast my_integer as integer volatile +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1,2} + {1,2} + {1,2} + {1,2} +(4 rows) + +DROP CAST (my_integer AS integer); +CREATE CAST (my_integer AS integer) + WITH FUNCTION cast_my_integer_as_integer_stl; +SELECT x_stl2_array_integer('{(1), (2)}'::my_integer[]::integer[]) FROM x; +NOTICE: cast my_integer as integer stable +NOTICE: cast my_integer as integer stable +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1,2} + {1,2} + {1,2} + {1,2} +(4 rows) + +DROP CAST (integer AS my_integer); +CREATE CAST (integer AS my_integer) + WITH FUNCTION cast_integer_as_my_integer_stl; +-- should not be precalculated +SELECT x_vlt_array_integer()::my_integer[] FROM x; +NOTICE: v array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable +NOTICE: v array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable +NOTICE: v array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable +NOTICE: v array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable + x_vlt_array_integer +--------------------- + {(2),(3)} + {(2),(3)} + {(2),(3)} + {(2),(3)} +(4 rows) + +SELECT x_stl_array_integer()::my_integer[] FROM x; +NOTICE: s array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable + x_stl_array_integer +--------------------- + {(2),(3)} + {(2),(3)} + {(2),(3)} + {(2),(3)} +(4 rows) + +-- Mixed functions and ConvertRowtypeExpr testing +-- should not be precalculated +SELECT x_stl2_wxyz(x_vlt_wxyz_child()::wxyz_child::wxyz) FROM x; +NOTICE: v wxyz_child +NOTICE: s2 wxyz +NOTICE: v wxyz_child +NOTICE: s2 wxyz +NOTICE: v wxyz_child +NOTICE: s2 wxyz +NOTICE: v wxyz_child +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +-- should not be precalculated +SELECT x_stl2_wxyz(x_vlt_wxyz_child2()::wxyz_child2::wxyz) FROM x; +NOTICE: v wxyz_child2 +NOTICE: s2 wxyz +NOTICE: v wxyz_child2 +NOTICE: s2 wxyz +NOTICE: v wxyz_child2 +NOTICE: s2 wxyz +NOTICE: v wxyz_child2 +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz(x_stl_wxyz_child()::wxyz_child::wxyz) FROM x; +NOTICE: s wxyz_child +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz(x_stl_wxyz_child2()::wxyz_child2::wxyz) FROM x; +NOTICE: s wxyz_child2 +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +-- Mixed functions and CASE expressions testing +-- should not be precalculated +SELECT x_stl2(CASE WHEN x_vlt_boolean() THEN x_vlt() ELSE x_vlt() END) FROM x; +NOTICE: v boolean +NOTICE: v +NOTICE: s2 +NOTICE: v boolean +NOTICE: v +NOTICE: s2 +NOTICE: v boolean +NOTICE: v +NOTICE: s2 +NOTICE: v boolean +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- should not be precalculated +SELECT x_stl2(CASE x_vlt() WHEN x_vlt() THEN x_vlt() ELSE x_vlt() END) FROM x; +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(CASE WHEN x_stl2_boolean(TRUE) THEN x_stl() ELSE x_stl() END) +FROM x; +NOTICE: s2 boolean +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(CASE x_stl() WHEN x_stl() THEN x_stl() ELSE x_stl() END) FROM x; +NOTICE: s +NOTICE: s +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Mixed functions and RowCompareExpr testing +-- should not be precalculated +SELECT x_stl2_boolean((x_vlt(), 2) < (1, 3)) FROM x; +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean((x_stl(), 2) < (1, 3)) FROM x; +NOTICE: s +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- Mixed functions and COALESCE expressions testing +-- should not be precalculated +SELECT x_stl2(COALESCE(NULL, x_vlt2(NULL), 2)) FROM x; +NOTICE: v2 +NOTICE: s2 +NOTICE: v2 +NOTICE: s2 +NOTICE: v2 +NOTICE: s2 +NOTICE: v2 +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +SELECT x_stl2(COALESCE(NULL, x_stl2(NULL), 2)) FROM x; +NOTICE: s2 +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +-- Mixed functions and GREATEST and LEAST functions testing +SELECT x_stl2(GREATEST(2, x_vlt(), 3)) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 3 + 3 + 3 + 3 +(4 rows) + +SELECT x_stl2(LEAST(2, x_vlt(), 3)) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(GREATEST(2, x_stl(), 3)) FROM x; +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 3 + 3 + 3 + 3 +(4 rows) + +SELECT x_stl2(LEAST(2, x_stl(), 3)) FROM x; +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Mixed functions and Xml expressions testing +-- should not be precalculated +SELECT x_stl2_xml(XMLCONCAT('', x_vlt_xml())) FROM x; +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml + x_stl2_xml +---------------------- + foo + foo + foo + foo +(4 rows) + +-- should not be precalculated +SELECT x_stl2_xml( + XMLELEMENT(name foo, xmlattributes('bar' as bar), x_vlt_xml()) +) +FROM x; +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml + x_stl2_xml +------------------------------------- + foo + foo + foo + foo +(4 rows) + +-- should not be precalculated +SELECT x_stl2_xml(XMLFOREST('abc' AS foo, x_vlt_xml() AS bar)) FROM x; +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml + x_stl2_xml +----------------------------------------- + abcfoo + abcfoo + abcfoo + abcfoo +(4 rows) + +-- should not be precalculated +SELECT x_stl2_xml(XMLPARSE(DOCUMENT x_vlt_text_xml())) FROM x; +NOTICE: v text xml +NOTICE: s2 xml +NOTICE: v text xml +NOTICE: s2 xml +NOTICE: v text xml +NOTICE: s2 xml +NOTICE: v text xml +NOTICE: s2 xml + x_stl2_xml +------------------------------------ + Manual + Manual + Manual + Manual +(4 rows) + +-- should not be precalculated +SELECT x_stl2_xml(XMLPARSE(CONTENT x_vlt_text_xml_content())) FROM x; +NOTICE: v text xml content +NOTICE: s2 xml +NOTICE: v text xml content +NOTICE: s2 xml +NOTICE: v text xml content +NOTICE: s2 xml +NOTICE: v text xml content +NOTICE: s2 xml + x_stl2_xml +--------------------------------- + abcbarfoo + abcbarfoo + abcbarfoo + abcbarfoo +(4 rows) + +-- should not be precalculated +SELECT x_stl2_xml(XMLPI(name php, x_vlt_text_xml_instruction_content())) FROM x; +NOTICE: v text xml instruction content +NOTICE: s2 xml +NOTICE: v text xml instruction content +NOTICE: s2 xml +NOTICE: v text xml instruction content +NOTICE: s2 xml +NOTICE: v text xml instruction content +NOTICE: s2 xml + x_stl2_xml +----------------------------- + + + + +(4 rows) + +-- should not be precalculated +SELECT x_stl2_xml(XMLROOT(x_vlt_xml(), version '1.0', standalone yes)) FROM x; +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml +NOTICE: v xml +NOTICE: s2 xml + x_stl2_xml +------------------------------------------------------ + foo + foo + foo + foo +(4 rows) + +-- should not be precalculated +SELECT x_stl2_text(XMLSERIALIZE(DOCUMENT x_vlt_xml() AS text)) FROM x; +NOTICE: v xml +NOTICE: s2 text +NOTICE: v xml +NOTICE: s2 text +NOTICE: v xml +NOTICE: s2 text +NOTICE: v xml +NOTICE: s2 text + x_stl2_text +---------------- + foo + foo + foo + foo +(4 rows) + +-- should not be precalculated +SELECT x_stl2_text(XMLSERIALIZE(CONTENT x_vlt_xml_content() AS text)) FROM x; +NOTICE: v xml content +NOTICE: s2 text +NOTICE: v xml content +NOTICE: s2 text +NOTICE: v xml content +NOTICE: s2 text +NOTICE: v xml content +NOTICE: s2 text + x_stl2_text +--------------------------------- + abcbarfoo + abcbarfoo + abcbarfoo + abcbarfoo +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_xml_content() IS DOCUMENT) FROM x; +NOTICE: v xml content +NOTICE: s2 boolean +NOTICE: v xml content +NOTICE: s2 boolean +NOTICE: v xml content +NOTICE: s2 boolean +NOTICE: v xml content +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_xml(XMLCONCAT('', x_stl_xml())) FROM x; +NOTICE: s xml +NOTICE: s2 xml + x_stl2_xml +---------------------- + foo + foo + foo + foo +(4 rows) + +SELECT x_stl2_xml( + XMLELEMENT(name foo, xmlattributes('bar' as bar), x_stl_xml()) +) +FROM x; +NOTICE: s xml +NOTICE: s2 xml + x_stl2_xml +------------------------------------- + foo + foo + foo + foo +(4 rows) + +SELECT x_stl2_xml(XMLFOREST('abc' AS foo, x_stl_xml() AS bar)) FROM x; +NOTICE: s xml +NOTICE: s2 xml + x_stl2_xml +----------------------------------------- + abcfoo + abcfoo + abcfoo + abcfoo +(4 rows) + +SELECT x_stl2_xml(XMLPARSE(DOCUMENT x_stl_text_xml())) FROM x; +NOTICE: s text xml +NOTICE: s2 xml + x_stl2_xml +------------------------------------ + Manual + Manual + Manual + Manual +(4 rows) + +SELECT x_stl2_xml(XMLPARSE(CONTENT x_stl_text_xml_content())) FROM x; +NOTICE: s xml content +NOTICE: s2 xml + x_stl2_xml +--------------------------------- + abcbarfoo + abcbarfoo + abcbarfoo + abcbarfoo +(4 rows) + +SELECT x_stl2_xml(XMLPI(name php, x_stl_text_xml_instruction_content())) FROM x; +NOTICE: s text xml instruction content +NOTICE: s2 xml + x_stl2_xml +----------------------------- + + + + +(4 rows) + +SELECT x_stl2_xml(XMLROOT(x_stl_xml(), version '1.0', standalone yes)) FROM x; +NOTICE: s xml +NOTICE: s2 xml + x_stl2_xml +------------------------------------------------------ + foo + foo + foo + foo +(4 rows) + +SELECT x_stl2_text(XMLSERIALIZE(DOCUMENT x_stl_xml() AS text)) FROM x; +NOTICE: s xml +NOTICE: s2 text + x_stl2_text +---------------- + foo + foo + foo + foo +(4 rows) + +SELECT x_stl2_text(XMLSERIALIZE(CONTENT x_stl_xml_content() AS text)) FROM x; +NOTICE: s xml content +NOTICE: s2 text + x_stl2_text +--------------------------------- + abcbarfoo + abcbarfoo + abcbarfoo + abcbarfoo +(4 rows) + +SELECT x_stl2_boolean(x_stl_xml_content() IS DOCUMENT) FROM x; +NOTICE: s xml content +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- Mixed functions and NullTest expressions testing +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt() IS NULL) FROM x; +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt() IS NOT NULL) FROM x; +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_wxyz() IS NULL) FROM x; +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_wxyz() IS NOT NULL) FROM x; +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl() IS NULL) FROM x; +NOTICE: s +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl() IS NOT NULL) FROM x; +NOTICE: s +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl_wxyz() IS NULL) FROM x; +NOTICE: s wxyz +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl_wxyz() IS NOT NULL) FROM x; +NOTICE: s wxyz +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- Mixed functions and BooleanTest expressions testing +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS TRUE) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT TRUE) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS FALSE) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT FALSE) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS UNKNOWN) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT UNKNOWN) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS TRUE) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS NOT TRUE) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS FALSE) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS NOT FALSE) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(NULL) IS UNKNOWN) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(NULL) IS NOT UNKNOWN) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SET track_functions TO DEFAULT; +-- ROW() expressions with dropped columns testing +ALTER TABLE wxyz DROP COLUMN z; +-- Update some functions +CREATE OR REPLACE FUNCTION public.x_stl2_wxyz ( + wxyz +) +RETURNS wxyz STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 wxyz'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +-- ROW() expressions testing +SELECT x_stl2_wxyz((1, '{2}', TRUE)) FROM x; +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t) + (1,{2},t) + (1,{2},t) + (1,{2},t) +(4 rows) + +SELECT x_stl2_wxyz(ROW(1, '{2}', TRUE)) FROM x; +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t) + (1,{2},t) + (1,{2},t) + (1,{2},t) +(4 rows) + +SELECT x_stl2_wxyz((1, '{2}', TRUE)::wxyz) FROM x; +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t) + (1,{2},t) + (1,{2},t) + (1,{2},t) +(4 rows) + +-- Mixed functions and ROW() expressions testing +-- should not be precalculated +SELECT x_stl2_wxyz((x_vlt(), '{2}', TRUE)) FROM x; +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t) + (1,{2},t) + (1,{2},t) + (1,{2},t) +(4 rows) + +SELECT x_stl2_wxyz((x_stl(), '{2}', TRUE)) FROM x; +NOTICE: s +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t) + (1,{2},t) + (1,{2},t) + (1,{2},t) +(4 rows) + +-- PL/pgSQL Simple expressions +-- Make sure precalculated stable functions can't be simple expressions: these +-- expressions are only initialized once per transaction and then executed +-- multiple times. +BEGIN; +SELECT simple(); + simple +-------- + 4 +(1 row) + +INSERT INTO x VALUES (5); +SELECT simple(); + simple +-------- + 5 +(1 row) + +ROLLBACK; +-- Drop tables for testing +DROP TABLE x; +DROP FUNCTION x_vlt_wxyz, x_vlt_wxyz_child, x_vlt_wxyz_child2; +DROP FUNCTION x_stl_wxyz, x_stl_wxyz_child, x_stl_wxyz_child2, x_stl2_wxyz; +DROP TABLE wxyz, wxyz_child, wxyz_child2; +DROP FUNCTION x_stl2_no_columns; +DROP TABLE no_columns, no_columns_child, no_columns_child2; diff --git a/src/test/regress/expected/precalculate_stable_functions_1.out b/src/test/regress/expected/precalculate_stable_functions_1.out new file mode 100644 index 0000000..10f66d4 --- /dev/null +++ b/src/test/regress/expected/precalculate_stable_functions_1.out @@ -0,0 +1,5768 @@ +-- +-- PRECALCULATE STABLE FUNCTIONS +-- +-- Create types and tables for testing +CREATE TYPE my_integer AS (value integer); +CREATE TYPE composite_type AS (first integer, second integer[], third boolean); +CREATE TABLE x (x integer); +INSERT INTO x SELECT generate_series(1, 4) x; +CREATE TABLE wxyz (w integer, x integer[], y boolean, z integer); +CREATE TABLE wxyz_child () INHERITS (wxyz); +CREATE TABLE wxyz_child2 (a integer, b integer) INHERITS (wxyz); +CREATE TABLE no_columns (); +CREATE TABLE no_columns_child () INHERITS (no_columns); +CREATE TABLE no_columns_child2 (a integer, b integer) INHERITS (no_columns); +-- Create volatile functions for testing +CREATE OR REPLACE FUNCTION public.x_vlt ( +) +RETURNS integer VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v'; + RETURN 1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_my_integer ( +) +RETURNS my_integer VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v my_integer'; + RETURN '(1)'::my_integer; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_array_integer ( +) +RETURNS int[] VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v array_integer'; + RETURN '{2, 3}'::integer[]; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_boolean ( +) +RETURNS boolean VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v boolean'; + RETURN TRUE; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_wxyz ( +) +RETURNS wxyz VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v wxyz'; + RETURN '(1, {2}, TRUE, 3)'::wxyz; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_wxyz_child ( +) +RETURNS wxyz_child VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v wxyz_child'; + RETURN '(1, {2}, TRUE, 3)'::wxyz_child; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_wxyz_child2 ( +) +RETURNS wxyz_child2 VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v wxyz_child2'; + RETURN '(1, {2}, TRUE, 3, 4, 5)'::wxyz_child2; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_oid ( +) +RETURNS oid VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v oid'; + RETURN 1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_text_integer ( +) +RETURNS text VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v text integer'; + RETURN 1::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_text_my_integer ( +) +RETURNS text VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v text my_integer'; + RETURN '(1)'::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_text_xml ( +) +RETURNS text VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v text xml'; + RETURN 'Manual'::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_text_xml_content ( +) +RETURNS text VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v text xml content'; + RETURN 'abcbarfoo'::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_text_xml_instruction_content ( +) +RETURNS text VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v text xml instruction content'; + RETURN 'echo "hello world";'::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_xml ( +) +RETURNS xml VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v xml'; + RETURN 'foo'::xml; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt_xml_content ( +) +RETURNS xml VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v xml content'; + RETURN 'abcbarfoo'::xml; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_vlt2 ( + integer +) +RETURNS integer VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v2'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.equal_integers_vlt ( + integer, + integer +) +RETURNS boolean VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'equal integers volatile'; + RETURN $1 = $2; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.equal_my_integer_vlt ( + my_integer, + my_integer +) +RETURNS boolean VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'equal my_integer volatile'; + RETURN $1.value = $2.value; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.cast_integer_as_my_integer_vlt ( + integer +) +RETURNS my_integer VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'cast integer as my_integer volatile'; + RETURN ROW($1)::my_integer; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.cast_my_integer_as_integer_vlt ( + my_integer +) +RETURNS integer VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'cast my_integer as integer volatile'; + RETURN $1.value; +END; +$body$ +LANGUAGE 'plpgsql'; +-- Create stable functions for testing +CREATE OR REPLACE FUNCTION public.x_stl ( +) +RETURNS integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 's'; + RETURN 1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_my_integer ( +) +RETURNS my_integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 's my_integer'; + RETURN '(1)'::my_integer; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_array_integer ( +) +RETURNS int[] STABLE AS +$body$ +BEGIN + RAISE NOTICE 's array_integer'; + RETURN '{2, 3}'::integer[]; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_wxyz ( +) +RETURNS wxyz STABLE AS +$body$ +BEGIN + RAISE NOTICE 's wxyz'; + RETURN '(1, {2}, TRUE, 3)'::wxyz; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_wxyz_child ( +) +RETURNS wxyz_child STABLE AS +$body$ +BEGIN + RAISE NOTICE 's wxyz_child'; + RETURN '(1, {2}, TRUE, 3)'::wxyz_child; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_wxyz_child2 ( +) +RETURNS wxyz_child2 STABLE AS +$body$ +BEGIN + RAISE NOTICE 's wxyz_child2'; + RETURN '(1, {2}, TRUE, 3, 4, 5)'::wxyz_child2; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_oid ( +) +RETURNS oid STABLE AS +$body$ +BEGIN + RAISE NOTICE 's oid'; + RETURN 1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_text_integer ( +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's text integer'; + RETURN 1::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_text_my_integer ( +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's text my_integer'; + RETURN '(1)'::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_text_xml ( +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's text xml'; + RETURN 'Manual'::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_text_xml_content ( +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's xml content'; + RETURN 'abcbarfoo'::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_text_xml_instruction_content ( +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's text xml instruction content'; + RETURN 'echo "hello world";'::text; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_xml ( +) +RETURNS xml STABLE AS +$body$ +BEGIN + RAISE NOTICE 's xml'; + RETURN 'foo'::xml; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl_xml_content ( +) +RETURNS xml STABLE AS +$body$ +BEGIN + RAISE NOTICE 's xml content'; + RETURN 'abcbarfoo'::xml; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2 ( + integer +) +RETURNS integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_strict ( + integer +) +RETURNS integer STABLE STRICT AS +$body$ +BEGIN + RAISE NOTICE 's2 strict'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_boolean ( + boolean +) +RETURNS boolean STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 boolean'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_array_integer ( + integer[] +) +RETURNS integer[] STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 array_integer'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_array_oid ( + oid[] +) +RETURNS oid[] STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 array_oid'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_wxyz ( + wxyz +) +RETURNS wxyz STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 wxyz'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_composite_type ( + composite_type +) +RETURNS composite_type STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 composite_type'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_my_integer ( + my_integer +) +RETURNS my_integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 my_integer'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_no_columns ( + no_columns +) +RETURNS no_columns STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 no_columns'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_name ( + name +) +RETURNS name STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 name'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_xml ( + xml +) +RETURNS xml STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 xml'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_stl2_text ( + text +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 text'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.equal_integers_stl ( + integer, + integer +) +RETURNS boolean STABLE AS +$body$ +BEGIN + RAISE NOTICE 'equal integers stable'; + RETURN $1 = $2; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.equal_booleans_stl_strict ( + boolean, + boolean +) +RETURNS boolean STABLE STRICT AS +$body$ +BEGIN + RAISE NOTICE 'equal booleans stable strict'; + RETURN $1 = $2; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.equal_my_integer_stl ( + my_integer, + my_integer +) +RETURNS boolean STABLE AS +$body$ +BEGIN + RAISE NOTICE 'equal my_integer stable'; + RETURN $1.value = $2.value; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.cast_integer_as_my_integer_stl ( + integer +) +RETURNS my_integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 'cast integer as my_integer stable'; + RETURN ROW($1)::my_integer; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.cast_my_integer_as_integer_stl ( + my_integer +) +RETURNS integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 'cast my_integer as integer stable'; + RETURN $1.value; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.stable_max( +) +RETURNS integer STABLE AS +$body$ +BEGIN + RETURN (SELECT max(x) from x); +END +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.simple( +) +RETURNS integer STABLE AS +$body$ +BEGIN + RETURN stable_max(); +END +$body$ +LANGUAGE 'plpgsql'; +-- Create immutable functions for testing +CREATE OR REPLACE FUNCTION public.x_imm2 ( + integer +) +RETURNS integer IMMUTABLE AS +$body$ +BEGIN + RAISE NOTICE 'i2'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_imm2_strict ( + integer +) +RETURNS integer IMMUTABLE STRICT AS +$body$ +BEGIN + RAISE NOTICE 'i2 strict'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.x_imm2_my_integer ( + my_integer +) +RETURNS my_integer IMMUTABLE AS +$body$ +BEGIN + RAISE NOTICE 'i2 my_integer'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.equal_integers_imm ( + integer, + integer +) +RETURNS boolean IMMUTABLE AS +$body$ +BEGIN + RAISE NOTICE 'equal integers immutable'; + RETURN $1 = $2; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.equal_booleans_imm ( + boolean, + boolean +) +RETURNS boolean IMMUTABLE AS +$body$ +BEGIN + RAISE NOTICE 'equal booleans immutable'; + RETURN $1 = $2; +END; +$body$ +LANGUAGE 'plpgsql'; +CREATE OR REPLACE FUNCTION public.equal_my_integer_imm ( + my_integer, + my_integer +) +RETURNS boolean IMMUTABLE AS +$body$ +BEGIN + RAISE NOTICE 'equal my_integer immutable'; + RETURN $1.value = $2.value; +END; +$body$ +LANGUAGE 'plpgsql'; +-- Create operators for testing +CREATE OPERATOR === ( + PROCEDURE = equal_integers_vlt, + LEFTARG = integer, + RIGHTARG = integer +); +CREATE OPERATOR ==== ( + PROCEDURE = equal_integers_stl, + LEFTARG = integer, + RIGHTARG = integer +); +CREATE OPERATOR ===== ( + PROCEDURE = equal_integers_imm, + LEFTARG = integer, + RIGHTARG = integer +); +CREATE OPERATOR ==== ( + PROCEDURE = equal_booleans_stl_strict, + LEFTARG = boolean, + RIGHTARG = boolean +); +CREATE OPERATOR ===== ( + PROCEDURE = equal_booleans_imm, + LEFTARG = boolean, + RIGHTARG = boolean +); +-- Functions testing +-- Simple functions testing +SELECT x_vlt() FROM x; -- should not be precalculated +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v + x_vlt +------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl() FROM x; +NOTICE: s + x_stl +------- + 1 + 1 + 1 + 1 +(4 rows) + +-- WHERE clause testing +SELECT x_vlt() FROM x WHERE x_vlt() < x; -- should not be precalculated +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v + x_vlt +------- + 1 + 1 + 1 +(3 rows) + +SELECT x_stl() FROM x WHERE x_stl() < x; +NOTICE: s +NOTICE: s +NOTICE: s + x_stl +------- + 1 + 1 + 1 +(3 rows) + +-- JOIN/ON clause testing +-- should not be precalculated +SELECT * FROM x JOIN generate_series(1, 2) y ON x_vlt() < x; +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v + x | y +---+--- + 2 | 1 + 3 | 1 + 4 | 1 + 2 | 2 + 3 | 2 + 4 | 2 +(6 rows) + +SELECT * FROM x JOIN generate_series(1, 2) y ON x_stl() < x; +NOTICE: s +NOTICE: s + x | y +---+--- + 2 | 1 + 3 | 1 + 4 | 1 + 2 | 2 + 3 | 2 + 4 | 2 +(6 rows) + +-- Functions with constant arguments testing +SELECT x_vlt2(1) FROM x; -- should not be precalculated +NOTICE: v2 +NOTICE: v2 +NOTICE: v2 +NOTICE: v2 + x_vlt2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(1) FROM x; +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Nested functions testing +SELECT x_stl2(x_vlt()) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_imm2(x_vlt()) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: i2 +NOTICE: v +NOTICE: i2 +NOTICE: v +NOTICE: i2 +NOTICE: v +NOTICE: i2 + x_imm2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(x_stl()) FROM x; +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_imm2(x_stl()) FROM x; +NOTICE: s +NOTICE: i2 + x_imm2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Strict functions testing +SELECT x_stl2_strict(x_vlt()) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: s2 strict +NOTICE: v +NOTICE: s2 strict +NOTICE: v +NOTICE: s2 strict +NOTICE: v +NOTICE: s2 strict + x_stl2_strict +--------------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_imm2_strict(x_vlt()) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: i2 strict +NOTICE: v +NOTICE: i2 strict +NOTICE: v +NOTICE: i2 strict +NOTICE: v +NOTICE: i2 strict + x_imm2_strict +--------------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2_strict(x_stl2_strict(1)) FROM x; +NOTICE: s2 strict +NOTICE: s2 strict + x_stl2_strict +--------------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_imm2_strict(x_stl2_strict(1)) FROM x; +NOTICE: s2 strict +NOTICE: i2 strict + x_imm2_strict +--------------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Strict functions with null arguments testing +SELECT x_stl2_strict(x_stl2(NULL)) FROM x; +NOTICE: s2 + x_stl2_strict +--------------- + + + + +(4 rows) + +SELECT x_imm2_strict(x_stl2(NULL)) FROM x; +NOTICE: s2 + x_imm2_strict +--------------- + + + + +(4 rows) + +-- Operators testing +SELECT 1 === 2 FROM x; -- should not be precalculated +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== 2 FROM x; +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- Strict operators testing +SELECT x_stl2_boolean(NULL) ==== TRUE FROM x; +NOTICE: s2 boolean + ?column? +---------- + + + + +(4 rows) + +SELECT x_stl2_boolean(NULL) ===== TRUE FROM x; +NOTICE: s2 boolean +NOTICE: equal booleans immutable + ?column? +---------- + + + + +(4 rows) + +-- Mixed functions and operators testing +SELECT x_stl2_boolean(1 === 2) FROM x; -- should not be precalculated +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(1 ==== 2) FROM x; +NOTICE: equal integers stable +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_vlt() ==== 1 FROM x; -- should not be precalculated +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable + ?column? +---------- + t + t + t + t +(4 rows) + +SELECT x_stl() ==== 1 FROM x; +NOTICE: s +NOTICE: equal integers stable + ?column? +---------- + t + t + t + t +(4 rows) + +-- IS (NOT) DISTINCT FROM expression testing +-- create operator here because we will drop and reuse it several times +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT '(1)'::my_integer IS DISTINCT FROM '(2)'::my_integer FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile + ?column? +---------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT '(1)'::my_integer IS NOT DISTINCT FROM '(2)'::my_integer FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile + ?column? +---------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT '(1)'::my_integer IS DISTINCT FROM '(2)'::my_integer FROM x; +NOTICE: equal my_integer stable + ?column? +---------- + t + t + t + t +(4 rows) + +SELECT '(1)'::my_integer IS NOT DISTINCT FROM '(2)'::my_integer FROM x; +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- IS (NOT) DISTINCT FROM expressions with null arguments testing +SELECT x_stl2_boolean(x_stl2(NULL) IS DISTINCT FROM 1) FROM x; +NOTICE: s2 +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2(NULL) IS NOT DISTINCT FROM 1) FROM x; +NOTICE: s2 +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl2(NULL) IS DISTINCT FROM x_stl2(NULL)) FROM x; +NOTICE: s2 +NOTICE: s2 +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl2(NULL) IS NOT DISTINCT FROM x_stl2(NULL)) FROM x; +NOTICE: s2 +NOTICE: s2 +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- Mixed functions and IS (NOT) DISTINCT FROM expressions testing +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT equal_booleans_stl_strict( + ('(1)'::my_integer IS DISTINCT FROM '(1)'::my_integer), + ('(1)'::my_integer IS NOT DISTINCT FROM '(1)'::my_integer) +) +FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal booleans stable strict +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal booleans stable strict +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal booleans stable strict +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal booleans stable strict + equal_booleans_stl_strict +--------------------------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT equal_booleans_stl_strict( + ('(1)'::my_integer IS DISTINCT FROM '(1)'::my_integer), + ('(1)'::my_integer IS NOT DISTINCT FROM '(1)'::my_integer) +) +FROM x; +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: equal booleans stable strict + equal_booleans_stl_strict +--------------------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT (x_vlt_my_integer() IS DISTINCT FROM '(1)'::my_integer) FROM x; +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT (x_vlt_my_integer() IS NOT DISTINCT FROM '(1)'::my_integer) FROM x; +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable + ?column? +---------- + t + t + t + t +(4 rows) + +SELECT (x_stl_my_integer() IS DISTINCT FROM '(1)'::my_integer) FROM x; +NOTICE: s my_integer +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT (x_stl_my_integer() IS NOT DISTINCT FROM '(1)'::my_integer) FROM x; +NOTICE: s my_integer +NOTICE: equal my_integer stable + ?column? +---------- + t + t + t + t +(4 rows) + +-- NULLIF expressions testing +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT NULLIF('(1)'::my_integer, '(2)'::my_integer) FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile + nullif +-------- + (1) + (1) + (1) + (1) +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT NULLIF('(1)'::my_integer, '(2)'::my_integer) FROM x; +NOTICE: equal my_integer stable + nullif +-------- + (1) + (1) + (1) + (1) +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_imm, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT NULLIF('(1)'::my_integer, '(2)'::my_integer) FROM x; +NOTICE: equal my_integer immutable + nullif +-------- + (1) + (1) + (1) + (1) +(4 rows) + +-- NULLIF expressions with null arguments testing +SELECT x_stl2(NULLIF(1, NULL)) FROM x; +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(NULLIF(NULL::integer, NULL)) FROM x; +NOTICE: s2 + x_stl2 +-------- + + + + +(4 rows) + +-- Mixed functions and NULLIF expressions testing +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT equal_my_integer_stl( + NULLIF('(1)'::my_integer, '(2)'::my_integer), + NULLIF('(2)'::my_integer, '(2)'::my_integer) +) +FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer stable +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer stable +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer stable +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer stable + equal_my_integer_stl +---------------------- + + + + +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT equal_my_integer_stl( + NULLIF('(1)'::my_integer, '(2)'::my_integer), + NULLIF('(2)'::my_integer, '(2)'::my_integer) +) +FROM x; +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable + equal_my_integer_stl +---------------------- + + + + +(4 rows) + +-- should not be precalculated +SELECT NULLIF(x_vlt_my_integer(), '(2)'::my_integer) FROM x; +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable + nullif +-------- + (1) + (1) + (1) + (1) +(4 rows) + +SELECT NULLIF(x_stl_my_integer(), '(2)'::my_integer) FROM x; +NOTICE: s my_integer +NOTICE: equal my_integer stable + nullif +-------- + (1) + (1) + (1) + (1) +(4 rows) + +-- "scalar op ANY/ALL (array)" / "scalar IN (2 or more values)" expressions +-- testing +SELECT 1 === ANY ('{2, 3}') FROM x; -- should not be precalculated +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 === ALL ('{2, 3}') FROM x; -- should not be precalculated +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile + ?column? +---------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== ANY ('{2, 3}') FROM x; +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== ALL ('{2, 3}') FROM x; +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ===== ANY ('{2, 3}') FROM x; +NOTICE: equal integers immutable +NOTICE: equal integers immutable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ===== ALL ('{2, 3}') FROM x; +NOTICE: equal integers immutable + ?column? +---------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_imm, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; +NOTICE: equal my_integer immutable +NOTICE: equal my_integer immutable + ?column? +---------- + f + f + f + f +(4 rows) + +-- "scalar op ANY/ALL (array)" / "scalar IN (2 or more values)" expressions with +-- null arguments testing +SELECT 1 ==== ANY ('{2, NULL}') FROM x; +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + + + + +(4 rows) + +SELECT x_stl2_boolean(1 ==== ANY (NULL)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + + + + +(4 rows) + +SELECT NULL ==== ANY ('{2, 3}'::integer[]) FROM x; +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + + + + +(4 rows) + +SELECT NULL ==== ANY ('{2, NULL}'::integer[]) FROM x; +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + + + + +(4 rows) + +SELECT x_stl2_boolean(NULL::integer ==== ANY (NULL)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + + + + +(4 rows) + +SELECT 1 ==== ALL ('{2, NULL}') FROM x; +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(1 ==== ALL (NULL)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + + + + +(4 rows) + +SELECT NULL ==== ALL ('{2, 3}'::integer[]) FROM x; +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + + + + +(4 rows) + +SELECT NULL ==== ALL ('{2, NULL}'::integer[]) FROM x; +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + + + + +(4 rows) + +SELECT x_stl2_boolean(NULL::integer ==== ALL (NULL)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + + + + +(4 rows) + +SELECT x_stl2_boolean(1 IN (2, NULL)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + + + + +(4 rows) + +SELECT x_stl2_boolean(NULL IN (2, 3)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + + + + +(4 rows) + +SELECT x_stl2_boolean(NULL IN (2, NULL)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + + + + +(4 rows) + +-- Mixed functions and "scalar op ANY/ALL (array)" / "scalar IN (2 or more +-- values)" expressions testing +-- should not be precalculated +SELECT x_stl2_boolean(1 === ANY ('{2, 3}')) FROM x; +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(1 === ALL ('{2, 3}')) FROM x; +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT x_stl2_boolean( + '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) +) +FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: s2 boolean +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: s2 boolean +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: s2 boolean +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(1 ==== ANY ('{2, 3}')) FROM x; +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(1 ==== ALL ('{2, 3}')) FROM x; +NOTICE: equal integers stable +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT x_stl2_boolean( + '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) +) +FROM x; +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_vlt() ==== ANY ('{2, 3}') FROM x; +NOTICE: v +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_vlt() ==== ALL ('{2, 3}') FROM x; +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT 1 ==== ANY (x_vlt_array_integer()) FROM x; +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT 1 ==== ALL (x_vlt_array_integer()) FROM x; +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_vlt_my_integer() IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT x_stl() ==== ANY ('{2, 3}') FROM x; +NOTICE: s +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT x_stl() ==== ALL ('{2, 3}') FROM x; +NOTICE: s +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== ANY (x_stl_array_integer()) FROM x; +NOTICE: s array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== ALL (x_stl_array_integer()) FROM x; +NOTICE: s array_integer +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT x_stl_my_integer() IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; +NOTICE: s my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- Boolean expressions testing +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() AND x_stl2_boolean(TRUE)) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() OR x_stl2_boolean(TRUE)) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(NOT x_vlt_boolean()) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) AND x_stl2_boolean(TRUE)) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) OR x_stl2_boolean(TRUE)) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(NOT x_stl2_boolean(TRUE)) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- ARRAY[] expressions testing +-- should not be precalculated +SELECT x_stl2_array_integer(ARRAY[x_vlt(), 2]) FROM x; +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1,2} + {1,2} + {1,2} + {1,2} +(4 rows) + +SELECT x_stl2_array_integer(ARRAY[x_stl(), 2]) FROM x; +NOTICE: s +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1,2} + {1,2} + {1,2} + {1,2} +(4 rows) + +-- Multidimensional ARRAY[] expressions testing +-- should not be precalculated +SELECT x_stl2_array_integer(ARRAY[[x_vlt(), 2], [3, 4]]) FROM x; +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {{1,2},{3,4}} + {{1,2},{3,4}} + {{1,2},{3,4}} + {{1,2},{3,4}} +(4 rows) + +SELECT x_stl2_array_integer(ARRAY[[x_stl(), 2], [3, 4]]) FROM x; +NOTICE: s +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {{1,2},{3,4}} + {{1,2},{3,4}} + {{1,2},{3,4}} + {{1,2},{3,4}} +(4 rows) + +-- Array subscripting operations testing +SELECT x_stl2(('{1, 2}'::integer[])[1]) FROM x; +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2_array_integer(('{1, 2}'::integer[])[:]) FROM x; +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1,2} + {1,2} + {1,2} + {1,2} +(4 rows) + +-- Mixed functions and array subscripting operations testing +-- should not be precalculated +SELECT x_stl2((x_vlt_array_integer())[x_vlt()]) FROM x; +NOTICE: v array_integer +NOTICE: v +NOTICE: s2 +NOTICE: v array_integer +NOTICE: v +NOTICE: s2 +NOTICE: v array_integer +NOTICE: v +NOTICE: s2 +NOTICE: v array_integer +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +-- should not be precalculated +SELECT x_stl2((x_vlt_array_integer())[1]) FROM x; +NOTICE: v array_integer +NOTICE: s2 +NOTICE: v array_integer +NOTICE: s2 +NOTICE: v array_integer +NOTICE: s2 +NOTICE: v array_integer +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +-- should not be precalculated +SELECT x_stl2_array_integer((x_vlt_array_integer())[:]) FROM x; +NOTICE: v array_integer +NOTICE: s2 array_integer +NOTICE: v array_integer +NOTICE: s2 array_integer +NOTICE: v array_integer +NOTICE: s2 array_integer +NOTICE: v array_integer +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {2,3} + {2,3} + {2,3} + {2,3} +(4 rows) + +-- should not be precalculated +SELECT x_stl2(('{1, 2}'::integer[])[x_vlt()]) FROM x; +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2((x_stl_array_integer())[x_stl()]) FROM x; +NOTICE: s array_integer +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +SELECT x_stl2((x_stl_array_integer())[1]) FROM x; +NOTICE: s array_integer +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +SELECT x_stl2_array_integer((x_stl_array_integer())[:]) FROM x; +NOTICE: s array_integer +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {2,3} + {2,3} + {2,3} + {2,3} +(4 rows) + +SELECT x_stl2(('{1, 2}'::integer[])[x_stl()]) FROM x; +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- FieldSelect expressions testing +SELECT x_stl2(('(1, {2}, TRUE, 3)'::wxyz).w) FROM x; +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(('(1)'::my_integer).value) FROM x; +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Mixed functions and FieldSelect expressions testing +SELECT x_stl2((x_vlt_wxyz()).w) FROM x; -- should not be precalculated +NOTICE: v wxyz +NOTICE: s2 +NOTICE: v wxyz +NOTICE: s2 +NOTICE: v wxyz +NOTICE: s2 +NOTICE: v wxyz +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2((x_vlt_my_integer()).value) FROM x; -- should not be precalculated +NOTICE: v my_integer +NOTICE: s2 +NOTICE: v my_integer +NOTICE: s2 +NOTICE: v my_integer +NOTICE: s2 +NOTICE: v my_integer +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2((x_stl_wxyz()).w) FROM x; +NOTICE: s wxyz +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2((x_stl_my_integer()).value) FROM x; +NOTICE: s my_integer +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- ROW() expressions testing +SELECT x_stl2_wxyz((1, '{2}', TRUE, 3)) FROM x; +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz(ROW(1, '{2}', TRUE, 3)) FROM x; +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz((1, '{2}', TRUE, 3)::wxyz) FROM x; +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_composite_type((1, '{2}', TRUE)) FROM x; +NOTICE: s2 composite_type + x_stl2_composite_type +----------------------- + (1,{2},t) + (1,{2},t) + (1,{2},t) + (1,{2},t) +(4 rows) + +SELECT x_stl2_composite_type(ROW(1, '{2}', TRUE)) FROM x; +NOTICE: s2 composite_type + x_stl2_composite_type +----------------------- + (1,{2},t) + (1,{2},t) + (1,{2},t) + (1,{2},t) +(4 rows) + +SELECT x_stl2_composite_type((1, '{2}', TRUE)::composite_type) FROM x; +NOTICE: s2 composite_type + x_stl2_composite_type +----------------------- + (1,{2},t) + (1,{2},t) + (1,{2},t) + (1,{2},t) +(4 rows) + +-- Mixed functions and ROW() expressions testing +-- should not be precalculated +SELECT x_stl2_wxyz((x_vlt(), '{2}', TRUE, 3)) FROM x; +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz((x_stl(), '{2}', TRUE, 3)) FROM x; +NOTICE: s +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +-- RelabelType expressions testing +-- should not be precalculated +SELECT x_stl2(x_vlt_oid()::integer) FROM x; +NOTICE: v oid +NOTICE: s2 +NOTICE: v oid +NOTICE: s2 +NOTICE: v oid +NOTICE: s2 +NOTICE: v oid +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(x_stl_oid()::integer) FROM x; +NOTICE: s oid +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- CoerceViaIO expressions testing +SELECT x_stl2_my_integer('(1)'::text::my_integer) FROM x; +NOTICE: s2 my_integer + x_stl2_my_integer +------------------- + (1) + (1) + (1) + (1) +(4 rows) + +-- should not be precalculated +SELECT x_stl2(x_vlt_text_integer()::integer) FROM x; +NOTICE: v text integer +NOTICE: s2 +NOTICE: v text integer +NOTICE: s2 +NOTICE: v text integer +NOTICE: s2 +NOTICE: v text integer +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(x_stl_text_integer()::integer) FROM x; +NOTICE: s text integer +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Mixed functions and CoerceViaIO expressions testing +-- should not be precalculated +SELECT x_stl2_my_integer(x_vlt_text_my_integer()::my_integer) FROM x; +NOTICE: v text my_integer +NOTICE: s2 my_integer +NOTICE: v text my_integer +NOTICE: s2 my_integer +NOTICE: v text my_integer +NOTICE: s2 my_integer +NOTICE: v text my_integer +NOTICE: s2 my_integer + x_stl2_my_integer +------------------- + (1) + (1) + (1) + (1) +(4 rows) + +SELECT x_stl2_my_integer(x_stl_text_my_integer()::my_integer) FROM x; +NOTICE: s text my_integer +NOTICE: s2 my_integer + x_stl2_my_integer +------------------- + (1) + (1) + (1) + (1) +(4 rows) + +-- ArrayCoerce expressions testing +-- Binary-coercible types: +-- should not be precalculated +SELECT x_stl2_array_oid(x_vlt_array_integer()::oid[]) FROM x; +NOTICE: v array_integer +NOTICE: s2 array_oid +NOTICE: v array_integer +NOTICE: s2 array_oid +NOTICE: v array_integer +NOTICE: s2 array_oid +NOTICE: v array_integer +NOTICE: s2 array_oid + x_stl2_array_oid +------------------ + {2,3} + {2,3} + {2,3} + {2,3} +(4 rows) + +SELECT x_stl2_array_oid(x_stl_array_integer()::oid[]) FROM x; +NOTICE: s array_integer +NOTICE: s2 array_oid + x_stl2_array_oid +------------------ + {2,3} + {2,3} + {2,3} + {2,3} +(4 rows) + +-- Not binary-coercible types: +-- create cast here because we will drop and reuse it several times +CREATE CAST (integer AS my_integer) + WITH FUNCTION cast_integer_as_my_integer_vlt; +SELECT '{1, 2}'::integer[]::my_integer[] FROM x; -- should not be precalculated +NOTICE: cast integer as my_integer volatile +NOTICE: cast integer as my_integer volatile +NOTICE: cast integer as my_integer volatile +NOTICE: cast integer as my_integer volatile +NOTICE: cast integer as my_integer volatile +NOTICE: cast integer as my_integer volatile +NOTICE: cast integer as my_integer volatile +NOTICE: cast integer as my_integer volatile + my_integer +------------ + {(1),(2)} + {(1),(2)} + {(1),(2)} + {(1),(2)} +(4 rows) + +DROP CAST (integer AS my_integer); +CREATE CAST (integer AS my_integer) + WITH FUNCTION cast_integer_as_my_integer_stl; +SELECT '{1, 2}'::integer[]::my_integer[] FROM x; +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable + my_integer +------------ + {(1),(2)} + {(1),(2)} + {(1),(2)} + {(1),(2)} +(4 rows) + +-- Mixed functions and ArrayCoerce expressions testing +-- Not binary-coercible types: +-- create cast here because we will drop and reuse it several times +CREATE CAST (my_integer AS integer) + WITH FUNCTION cast_my_integer_as_integer_vlt; +-- should not be precalculated +SELECT x_stl2_array_integer('{(1), (2)}'::my_integer[]::integer[]) FROM x; +NOTICE: cast my_integer as integer volatile +NOTICE: cast my_integer as integer volatile +NOTICE: s2 array_integer +NOTICE: cast my_integer as integer volatile +NOTICE: cast my_integer as integer volatile +NOTICE: s2 array_integer +NOTICE: cast my_integer as integer volatile +NOTICE: cast my_integer as integer volatile +NOTICE: s2 array_integer +NOTICE: cast my_integer as integer volatile +NOTICE: cast my_integer as integer volatile +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1,2} + {1,2} + {1,2} + {1,2} +(4 rows) + +DROP CAST (my_integer AS integer); +CREATE CAST (my_integer AS integer) + WITH FUNCTION cast_my_integer_as_integer_stl; +SELECT x_stl2_array_integer('{(1), (2)}'::my_integer[]::integer[]) FROM x; +NOTICE: cast my_integer as integer stable +NOTICE: cast my_integer as integer stable +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1,2} + {1,2} + {1,2} + {1,2} +(4 rows) + +DROP CAST (integer AS my_integer); +CREATE CAST (integer AS my_integer) + WITH FUNCTION cast_integer_as_my_integer_stl; +-- should not be precalculated +SELECT x_vlt_array_integer()::my_integer[] FROM x; +NOTICE: v array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable +NOTICE: v array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable +NOTICE: v array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable +NOTICE: v array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable + x_vlt_array_integer +--------------------- + {(2),(3)} + {(2),(3)} + {(2),(3)} + {(2),(3)} +(4 rows) + +SELECT x_stl_array_integer()::my_integer[] FROM x; +NOTICE: s array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable + x_stl_array_integer +--------------------- + {(2),(3)} + {(2),(3)} + {(2),(3)} + {(2),(3)} +(4 rows) + +-- ConvertRowtypeExpr testing +SELECT x_stl2_wxyz('(1, {2}, TRUE, 3)'::wxyz_child::wxyz) FROM x; +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz('(1, {2}, TRUE, 3, 4, 5)'::wxyz_child2::wxyz) FROM x; +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_no_columns('()'::no_columns_child::no_columns) FROM x; +NOTICE: s2 no_columns + x_stl2_no_columns +------------------- + () + () + () + () +(4 rows) + +SELECT x_stl2_no_columns('(1, 2)'::no_columns_child2::no_columns) FROM x; +NOTICE: s2 no_columns + x_stl2_no_columns +------------------- + () + () + () + () +(4 rows) + +-- Mixed functions and ConvertRowtypeExpr testing +-- should not be precalculated +SELECT x_stl2_wxyz(x_vlt_wxyz_child()::wxyz_child::wxyz) FROM x; +NOTICE: v wxyz_child +NOTICE: s2 wxyz +NOTICE: v wxyz_child +NOTICE: s2 wxyz +NOTICE: v wxyz_child +NOTICE: s2 wxyz +NOTICE: v wxyz_child +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +-- should not be precalculated +SELECT x_stl2_wxyz(x_vlt_wxyz_child2()::wxyz_child2::wxyz) FROM x; +NOTICE: v wxyz_child2 +NOTICE: s2 wxyz +NOTICE: v wxyz_child2 +NOTICE: s2 wxyz +NOTICE: v wxyz_child2 +NOTICE: s2 wxyz +NOTICE: v wxyz_child2 +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz(x_stl_wxyz_child()::wxyz_child::wxyz) FROM x; +NOTICE: s wxyz_child +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz(x_stl_wxyz_child2()::wxyz_child2::wxyz) FROM x; +NOTICE: s wxyz_child2 +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +-- CASE expressions testing +-- should not be precalculated +SELECT x_stl2(CASE WHEN x_vlt_boolean() THEN x_vlt() ELSE x_vlt() END) FROM x; +NOTICE: v boolean +NOTICE: v +NOTICE: s2 +NOTICE: v boolean +NOTICE: v +NOTICE: s2 +NOTICE: v boolean +NOTICE: v +NOTICE: s2 +NOTICE: v boolean +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- should not be precalculated +SELECT x_stl2(CASE x_vlt() WHEN x_vlt() THEN x_vlt() ELSE x_vlt() END) FROM x; +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(CASE WHEN x_stl2_boolean(TRUE) THEN x_stl() ELSE x_stl() END) +FROM x; +NOTICE: s2 boolean +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(CASE x_stl() WHEN x_stl() THEN x_stl() ELSE x_stl() END) FROM x; +NOTICE: s +NOTICE: s +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- RowCompareExpr testing +SELECT x_stl2_boolean((1, 2) < (1, 3)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- Mixed functions and RowCompareExpr testing +-- should not be precalculated +SELECT x_stl2_boolean((x_vlt(), 2) < (1, 3)) FROM x; +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean((x_stl(), 2) < (1, 3)) FROM x; +NOTICE: s +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- COALESCE expressions testing +-- should not be precalculated +SELECT x_stl2(COALESCE(NULL, x_vlt2(NULL), 2)) FROM x; +NOTICE: v2 +NOTICE: s2 +NOTICE: v2 +NOTICE: s2 +NOTICE: v2 +NOTICE: s2 +NOTICE: v2 +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +SELECT x_stl2(COALESCE(NULL, x_stl2(NULL), 2)) FROM x; +NOTICE: s2 +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +-- GREATEST and LEAST functions testing +SELECT x_stl2(GREATEST(2, 1, 3)) FROM x; +NOTICE: s2 + x_stl2 +-------- + 3 + 3 + 3 + 3 +(4 rows) + +SELECT x_stl2(LEAST(2, 1, 3)) FROM x; +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Mixed functions and GREATEST and LEAST functions testing +-- should not be precalculated +SELECT x_stl2(GREATEST(2, x_vlt(), 3)) FROM x; +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 3 + 3 + 3 + 3 +(4 rows) + +-- should not be precalculated +SELECT x_stl2(LEAST(2, x_vlt(), 3)) FROM x; +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(GREATEST(2, x_stl(), 3)) FROM x; +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 3 + 3 + 3 + 3 +(4 rows) + +SELECT x_stl2(LEAST(2, x_stl(), 3)) FROM x; +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- SQLValueFunction testing +CREATE ROLE regress_testrol2 SUPERUSER; +CREATE ROLE regress_testrol1 SUPERUSER LOGIN IN ROLE regress_testrol2; +\c - +SET SESSION AUTHORIZATION regress_testrol1; +SET ROLE regress_testrol2; +SELECT x_stl2_boolean(date(now()) = current_date) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(now()::timetz = current_time) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(now()::timetz(2) = current_time(2)) FROM x; -- precision +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(now() = current_timestamp) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- precision +SELECT x_stl2_boolean( + length(current_timestamp::text) >= length(current_timestamp(0)::text) +) +FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(now()::time = localtime) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(now()::time(2) = localtime(2)) FROM x; -- precision +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(now()::timestamp = localtimestamp) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- precision +SELECT x_stl2_boolean(now()::timestamp(2) = localtimestamp(2)) FROM x; +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_name(current_role) FROM x; +NOTICE: s2 name + x_stl2_name +------------------ + regress_testrol2 + regress_testrol2 + regress_testrol2 + regress_testrol2 +(4 rows) + +SELECT x_stl2_name(current_user) FROM x; +NOTICE: s2 name + x_stl2_name +------------------ + regress_testrol2 + regress_testrol2 + regress_testrol2 + regress_testrol2 +(4 rows) + +SELECT x_stl2_name(user) FROM x; +NOTICE: s2 name + x_stl2_name +------------------ + regress_testrol2 + regress_testrol2 + regress_testrol2 + regress_testrol2 +(4 rows) + +SELECT x_stl2_name(session_user) FROM x; +NOTICE: s2 name + x_stl2_name +------------------ + regress_testrol1 + regress_testrol1 + regress_testrol1 + regress_testrol1 +(4 rows) + +SELECT x_stl2_name(current_catalog) FROM x; +NOTICE: s2 name + x_stl2_name +------------- + regression + regression + regression + regression +(4 rows) + +SELECT x_stl2_name(current_schema) FROM x; +NOTICE: s2 name + x_stl2_name +------------- + public + public + public + public +(4 rows) + +\c +DROP ROLE regress_testrol1, regress_testrol2; +-- Xml expressions testing +SELECT x_stl2_xml(XMLCONCAT('', 'foo')) FROM x; +ERROR: unsupported XML feature +LINE 1: SELECT x_stl2_xml(XMLCONCAT('', 'foo')) FRO... + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml( + XMLELEMENT(name foo, xmlattributes('bar' as bar), 'cont', 'ent') +) +FROM x; +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml(XMLFOREST('abc' AS foo, 123 AS bar)) FROM x; +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml(XMLPARSE( + DOCUMENT 'Manual' +)) +FROM x; +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml(XMLPARSE(CONTENT 'abcbarfoo')) FROM x; +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml(XMLPI(name php, 'echo "hello world";')) FROM x; +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml(XMLROOT( + 'abc', + version '1.0', + standalone yes +)) +FROM x; +ERROR: unsupported XML feature +LINE 2: 'abc', + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_text(XMLSERIALIZE( + DOCUMENT 'Manual' AS text +)) +FROM x; +ERROR: unsupported XML feature +LINE 2: DOCUMENT 'Manual... + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_text(XMLSERIALIZE( + CONTENT 'abcbarfoo' AS text +)) +FROM x; +ERROR: unsupported XML feature +LINE 2: CONTENT 'abcbarfoo' AS text + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_boolean('abcbarfoo' IS DOCUMENT) FROM x; +ERROR: unsupported XML feature +LINE 1: SELECT x_stl2_boolean('abcbarfoo' IS D... + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +-- Mixed functions and Xml expressions testing +-- should not be precalculated +SELECT x_stl2_xml(XMLCONCAT('', x_vlt_xml())) FROM x; +ERROR: unsupported XML feature +LINE 1: SELECT x_stl2_xml(XMLCONCAT('', x_vlt_xml())) FROM x; + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +-- should not be precalculated +SELECT x_stl2_xml( + XMLELEMENT(name foo, xmlattributes('bar' as bar), x_vlt_xml()) +) +FROM x; +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +-- should not be precalculated +SELECT x_stl2_xml(XMLFOREST('abc' AS foo, x_vlt_xml() AS bar)) FROM x; +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +-- should not be precalculated +SELECT x_stl2_xml(XMLPARSE(DOCUMENT x_vlt_text_xml())) FROM x; +NOTICE: v text xml +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +-- should not be precalculated +SELECT x_stl2_xml(XMLPARSE(CONTENT x_vlt_text_xml_content())) FROM x; +NOTICE: v text xml content +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +-- should not be precalculated +SELECT x_stl2_xml(XMLPI(name php, x_vlt_text_xml_instruction_content())) FROM x; +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +-- should not be precalculated +SELECT x_stl2_xml(XMLROOT(x_vlt_xml(), version '1.0', standalone yes)) FROM x; +NOTICE: v xml +ERROR: unsupported XML feature +LINE 1: SELECT 'foo'::xml + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +QUERY: SELECT 'foo'::xml +CONTEXT: PL/pgSQL function x_vlt_xml() line 4 at RETURN +-- should not be precalculated +SELECT x_stl2_text(XMLSERIALIZE(DOCUMENT x_vlt_xml() AS text)) FROM x; +NOTICE: v xml +ERROR: unsupported XML feature +LINE 1: SELECT 'foo'::xml + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +QUERY: SELECT 'foo'::xml +CONTEXT: PL/pgSQL function x_vlt_xml() line 4 at RETURN +-- should not be precalculated +SELECT x_stl2_text(XMLSERIALIZE(CONTENT x_vlt_xml_content() AS text)) FROM x; +NOTICE: v xml content +ERROR: unsupported XML feature +LINE 1: SELECT 'abcbarfoo'::xml + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +QUERY: SELECT 'abcbarfoo'::xml +CONTEXT: PL/pgSQL function x_vlt_xml_content() line 4 at RETURN +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_xml_content() IS DOCUMENT) FROM x; +NOTICE: v xml content +ERROR: unsupported XML feature +LINE 1: SELECT 'abcbarfoo'::xml + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +QUERY: SELECT 'abcbarfoo'::xml +CONTEXT: PL/pgSQL function x_vlt_xml_content() line 4 at RETURN +SELECT x_stl2_xml(XMLCONCAT('', x_stl_xml())) FROM x; +ERROR: unsupported XML feature +LINE 1: SELECT x_stl2_xml(XMLCONCAT('', x_stl_xml())) FROM x; + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml( + XMLELEMENT(name foo, xmlattributes('bar' as bar), x_stl_xml()) +) +FROM x; +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml(XMLFOREST('abc' AS foo, x_stl_xml() AS bar)) FROM x; +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml(XMLPARSE(DOCUMENT x_stl_text_xml())) FROM x; +NOTICE: s text xml +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml(XMLPARSE(CONTENT x_stl_text_xml_content())) FROM x; +NOTICE: s xml content +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml(XMLPI(name php, x_stl_text_xml_instruction_content())) FROM x; +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml(XMLROOT(x_stl_xml(), version '1.0', standalone yes)) FROM x; +NOTICE: s xml +ERROR: unsupported XML feature +LINE 1: SELECT 'foo'::xml + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +QUERY: SELECT 'foo'::xml +CONTEXT: PL/pgSQL function x_stl_xml() line 4 at RETURN +SELECT x_stl2_text(XMLSERIALIZE(DOCUMENT x_stl_xml() AS text)) FROM x; +NOTICE: s xml +ERROR: unsupported XML feature +LINE 1: SELECT 'foo'::xml + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +QUERY: SELECT 'foo'::xml +CONTEXT: PL/pgSQL function x_stl_xml() line 4 at RETURN +SELECT x_stl2_text(XMLSERIALIZE(CONTENT x_stl_xml_content() AS text)) FROM x; +NOTICE: s xml content +ERROR: unsupported XML feature +LINE 1: SELECT 'abcbarfoo'::xml + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +QUERY: SELECT 'abcbarfoo'::xml +CONTEXT: PL/pgSQL function x_stl_xml_content() line 4 at RETURN +SELECT x_stl2_boolean(x_stl_xml_content() IS DOCUMENT) FROM x; +NOTICE: s xml content +ERROR: unsupported XML feature +LINE 1: SELECT 'abcbarfoo'::xml + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +QUERY: SELECT 'abcbarfoo'::xml +CONTEXT: PL/pgSQL function x_stl_xml_content() line 4 at RETURN +-- NullTest expressions testing +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt() IS NULL) FROM x; +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt() IS NOT NULL) FROM x; +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_wxyz() IS NULL) FROM x; +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_wxyz() IS NOT NULL) FROM x; +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl() IS NULL) FROM x; +NOTICE: s +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl() IS NOT NULL) FROM x; +NOTICE: s +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl_wxyz() IS NULL) FROM x; +NOTICE: s wxyz +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl_wxyz() IS NOT NULL) FROM x; +NOTICE: s wxyz +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- BooleanTest expressions testing +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS TRUE) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT TRUE) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS FALSE) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT FALSE) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS UNKNOWN) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT UNKNOWN) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS TRUE) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS NOT TRUE) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS FALSE) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS NOT FALSE) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(NULL) IS UNKNOWN) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(NULL) IS NOT UNKNOWN) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- Tracking functions testing +SET track_functions TO 'all'; +-- Simple functions testing +SELECT x_vlt() FROM x; -- should not be precalculated +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v + x_vlt +------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl() FROM x; +NOTICE: s + x_stl +------- + 1 + 1 + 1 + 1 +(4 rows) + +-- WHERE clause testing +SELECT x_vlt() FROM x WHERE x_vlt() < x; -- should not be precalculated +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v + x_vlt +------- + 1 + 1 + 1 +(3 rows) + +SELECT x_stl() FROM x WHERE x_stl() < x; +NOTICE: s +NOTICE: s +NOTICE: s + x_stl +------- + 1 + 1 + 1 +(3 rows) + +-- JOIN/ON clause testing +-- should not be precalculated +SELECT * FROM x JOIN generate_series(1, 2) y ON x_vlt() < x; +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: v + x | y +---+--- + 2 | 1 + 3 | 1 + 4 | 1 + 2 | 2 + 3 | 2 + 4 | 2 +(6 rows) + +SELECT * FROM x JOIN generate_series(1, 2) y ON x_stl() < x; +NOTICE: s +NOTICE: s + x | y +---+--- + 2 | 1 + 3 | 1 + 4 | 1 + 2 | 2 + 3 | 2 + 4 | 2 +(6 rows) + +-- Functions with constant arguments testing +SELECT x_vlt2(1) FROM x; -- should not be precalculated +NOTICE: v2 +NOTICE: v2 +NOTICE: v2 +NOTICE: v2 + x_vlt2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(1) FROM x; +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Nested functions testing +SELECT x_stl2(x_vlt()) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_imm2(x_vlt()) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: i2 +NOTICE: v +NOTICE: i2 +NOTICE: v +NOTICE: i2 +NOTICE: v +NOTICE: i2 + x_imm2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(x_stl()) FROM x; +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_imm2(x_stl()) FROM x; +NOTICE: s +NOTICE: i2 + x_imm2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Strict functions testing +SELECT x_stl2_strict(x_vlt()) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: s2 strict +NOTICE: v +NOTICE: s2 strict +NOTICE: v +NOTICE: s2 strict +NOTICE: v +NOTICE: s2 strict + x_stl2_strict +--------------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_imm2_strict(x_vlt()) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: i2 strict +NOTICE: v +NOTICE: i2 strict +NOTICE: v +NOTICE: i2 strict +NOTICE: v +NOTICE: i2 strict + x_imm2_strict +--------------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2_strict(x_stl2_strict(1)) FROM x; +NOTICE: s2 strict +NOTICE: s2 strict + x_stl2_strict +--------------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_imm2_strict(x_stl2_strict(1)) FROM x; +NOTICE: s2 strict +NOTICE: i2 strict + x_imm2_strict +--------------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Strict functions with null arguments testing +SELECT x_stl2_strict(x_stl2(NULL)) FROM x; +NOTICE: s2 + x_stl2_strict +--------------- + + + + +(4 rows) + +SELECT x_imm2_strict(x_stl2(NULL)) FROM x; +NOTICE: s2 + x_imm2_strict +--------------- + + + + +(4 rows) + +-- Operators testing +SELECT 1 === 2 FROM x; -- should not be precalculated +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: equal integers volatile + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== 2 FROM x; +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- Strict operators testing +SELECT x_stl2_boolean(NULL) ==== TRUE FROM x; +NOTICE: s2 boolean + ?column? +---------- + + + + +(4 rows) + +SELECT x_stl2_boolean(NULL) ===== TRUE FROM x; +NOTICE: s2 boolean +NOTICE: equal booleans immutable + ?column? +---------- + + + + +(4 rows) + +-- Mixed functions and operators testing +SELECT x_stl2_boolean(1 === 2) FROM x; -- should not be precalculated +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(1 ==== 2) FROM x; +NOTICE: equal integers stable +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_vlt() ==== 1 FROM x; -- should not be precalculated +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable + ?column? +---------- + t + t + t + t +(4 rows) + +SELECT x_stl() ==== 1 FROM x; +NOTICE: s +NOTICE: equal integers stable + ?column? +---------- + t + t + t + t +(4 rows) + +-- Mixed functions and IS (NOT) DISTINCT FROM expressions testing +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT equal_booleans_stl_strict( + ('(1)'::my_integer IS DISTINCT FROM '(1)'::my_integer), + ('(1)'::my_integer IS NOT DISTINCT FROM '(1)'::my_integer) +) +FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal booleans stable strict +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal booleans stable strict +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal booleans stable strict +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal booleans stable strict + equal_booleans_stl_strict +--------------------------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT equal_booleans_stl_strict( + ('(1)'::my_integer IS DISTINCT FROM '(1)'::my_integer), + ('(1)'::my_integer IS NOT DISTINCT FROM '(1)'::my_integer) +) +FROM x; +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: equal booleans stable strict + equal_booleans_stl_strict +--------------------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT (x_vlt_my_integer() IS DISTINCT FROM '(1)'::my_integer) FROM x; +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT (x_vlt_my_integer() IS NOT DISTINCT FROM '(1)'::my_integer) FROM x; +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable + ?column? +---------- + t + t + t + t +(4 rows) + +SELECT (x_stl_my_integer() IS DISTINCT FROM '(1)'::my_integer) FROM x; +NOTICE: s my_integer +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT (x_stl_my_integer() IS NOT DISTINCT FROM '(1)'::my_integer) FROM x; +NOTICE: s my_integer +NOTICE: equal my_integer stable + ?column? +---------- + t + t + t + t +(4 rows) + +-- Mixed functions and NULLIF expressions testing +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT equal_my_integer_stl( + NULLIF('(1)'::my_integer, '(2)'::my_integer), + NULLIF('(2)'::my_integer, '(2)'::my_integer) +) +FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer stable +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer stable +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer stable +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: equal my_integer stable + equal_my_integer_stl +---------------------- + + + + +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT equal_my_integer_stl( + NULLIF('(1)'::my_integer, '(2)'::my_integer), + NULLIF('(2)'::my_integer, '(2)'::my_integer) +) +FROM x; +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable + equal_my_integer_stl +---------------------- + + + + +(4 rows) + +-- should not be precalculated +SELECT NULLIF(x_vlt_my_integer(), '(2)'::my_integer) FROM x; +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable + nullif +-------- + (1) + (1) + (1) + (1) +(4 rows) + +SELECT NULLIF(x_stl_my_integer(), '(2)'::my_integer) FROM x; +NOTICE: s my_integer +NOTICE: equal my_integer stable + nullif +-------- + (1) + (1) + (1) + (1) +(4 rows) + +-- Mixed functions and "scalar op ANY/ALL (array)" / "scalar IN (2 or more +-- values)" expressions testing +-- should not be precalculated +SELECT x_stl2_boolean(1 === ANY ('{2, 3}')) FROM x; +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: equal integers volatile +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(1 === ALL ('{2, 3}')) FROM x; +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean +NOTICE: equal integers volatile +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +-- should not be precalculated +SELECT x_stl2_boolean( + '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) +) +FROM x; +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: s2 boolean +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: s2 boolean +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: s2 boolean +NOTICE: equal my_integer volatile +NOTICE: equal my_integer volatile +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(1 ==== ANY ('{2, 3}')) FROM x; +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(1 ==== ALL ('{2, 3}')) FROM x; +NOTICE: equal integers stable +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); +SELECT x_stl2_boolean( + '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) +) +FROM x; +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_vlt() ==== ANY ('{2, 3}') FROM x; -- should not be precalculated +NOTICE: v +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT x_vlt() ==== ALL ('{2, 3}') FROM x; -- should not be precalculated +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable +NOTICE: v +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== ANY (x_vlt_array_integer()) FROM x; -- should not be precalculated +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== ALL (x_vlt_array_integer()) FROM x; -- should not be precalculated +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable +NOTICE: v array_integer +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_vlt_my_integer() IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable +NOTICE: v my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT x_stl() ==== ANY ('{2, 3}') FROM x; +NOTICE: s +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT x_stl() ==== ALL ('{2, 3}') FROM x; +NOTICE: s +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== ANY (x_stl_array_integer()) FROM x; +NOTICE: s array_integer +NOTICE: equal integers stable +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT 1 ==== ALL (x_stl_array_integer()) FROM x; +NOTICE: s array_integer +NOTICE: equal integers stable + ?column? +---------- + f + f + f + f +(4 rows) + +SELECT x_stl_my_integer() IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; +NOTICE: s my_integer +NOTICE: equal my_integer stable +NOTICE: equal my_integer stable + ?column? +---------- + f + f + f + f +(4 rows) + +-- Mixed functions and boolean expressions testing +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() AND x_stl2_boolean(TRUE)) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() OR x_stl2_boolean(TRUE)) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(NOT x_vlt_boolean()) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) AND x_stl2_boolean(TRUE)) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) OR x_stl2_boolean(TRUE)) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(NOT x_stl2_boolean(TRUE)) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- Mixed functions and ARRAY[] expressions testing +-- should not be precalculated +SELECT x_stl2_array_integer(ARRAY[x_vlt()]) FROM x; +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer +NOTICE: v +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1} + {1} + {1} + {1} +(4 rows) + +SELECT x_stl2_array_integer(ARRAY[x_stl()]) FROM x; +NOTICE: s +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1} + {1} + {1} + {1} +(4 rows) + +-- Mixed functions and array subscripting operations testing +-- should not be precalculated +SELECT x_stl2((x_vlt_array_integer())[x_vlt()]) FROM x; +NOTICE: v array_integer +NOTICE: v +NOTICE: s2 +NOTICE: v array_integer +NOTICE: v +NOTICE: s2 +NOTICE: v array_integer +NOTICE: v +NOTICE: s2 +NOTICE: v array_integer +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +-- should not be precalculated +SELECT x_stl2((x_vlt_array_integer())[1]) FROM x; +NOTICE: v array_integer +NOTICE: s2 +NOTICE: v array_integer +NOTICE: s2 +NOTICE: v array_integer +NOTICE: s2 +NOTICE: v array_integer +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +-- should not be precalculated +SELECT x_stl2_array_integer((x_vlt_array_integer())[:]) FROM x; +NOTICE: v array_integer +NOTICE: s2 array_integer +NOTICE: v array_integer +NOTICE: s2 array_integer +NOTICE: v array_integer +NOTICE: s2 array_integer +NOTICE: v array_integer +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {2,3} + {2,3} + {2,3} + {2,3} +(4 rows) + +-- should not be precalculated +SELECT x_stl2(('{1, 2}'::integer[])[x_vlt()]) FROM x; +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2((x_stl_array_integer())[x_stl()]) FROM x; +NOTICE: s array_integer +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +SELECT x_stl2((x_stl_array_integer())[1]) FROM x; +NOTICE: s array_integer +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +SELECT x_stl2_array_integer((x_stl_array_integer())[:]) FROM x; +NOTICE: s array_integer +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {2,3} + {2,3} + {2,3} + {2,3} +(4 rows) + +SELECT x_stl2(('{1, 2}'::integer[])[x_stl()]) FROM x; +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Mixed functions and FieldSelect expressions testing +SELECT x_stl2((x_vlt_wxyz()).w) FROM x; -- should not be precalculated +NOTICE: v wxyz +NOTICE: s2 +NOTICE: v wxyz +NOTICE: s2 +NOTICE: v wxyz +NOTICE: s2 +NOTICE: v wxyz +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2((x_vlt_my_integer()).value) FROM x; -- should not be precalculated +NOTICE: v my_integer +NOTICE: s2 +NOTICE: v my_integer +NOTICE: s2 +NOTICE: v my_integer +NOTICE: s2 +NOTICE: v my_integer +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2((x_stl_wxyz()).w) FROM x; +NOTICE: s wxyz +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2((x_stl_my_integer()).value) FROM x; +NOTICE: s my_integer +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Mixed functions and ROW() expressions testing +-- should not be precalculated +SELECT x_stl2_wxyz((x_vlt(), '{2}', TRUE, 3)) FROM x; +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz((x_stl(), '{2}', TRUE, 3)) FROM x; +NOTICE: s +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +-- Mixed functions and RelabelType expressions testing +SELECT x_stl2(x_vlt_oid()::integer) FROM x; -- should not be precalculated +NOTICE: v oid +NOTICE: s2 +NOTICE: v oid +NOTICE: s2 +NOTICE: v oid +NOTICE: s2 +NOTICE: v oid +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(x_stl_oid()::integer) FROM x; +NOTICE: s oid +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Mixed functions and CoerceViaIO expressions testing +-- should not be precalculated +SELECT x_stl2(x_vlt_text_integer()::integer) FROM x; +NOTICE: v text integer +NOTICE: s2 +NOTICE: v text integer +NOTICE: s2 +NOTICE: v text integer +NOTICE: s2 +NOTICE: v text integer +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(x_stl_text_integer()::integer) FROM x; +NOTICE: s text integer +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- should not be precalculated +SELECT x_stl2_my_integer(x_vlt_text_my_integer()::my_integer) FROM x; +NOTICE: v text my_integer +NOTICE: s2 my_integer +NOTICE: v text my_integer +NOTICE: s2 my_integer +NOTICE: v text my_integer +NOTICE: s2 my_integer +NOTICE: v text my_integer +NOTICE: s2 my_integer + x_stl2_my_integer +------------------- + (1) + (1) + (1) + (1) +(4 rows) + +SELECT x_stl2_my_integer(x_stl_text_my_integer()::my_integer) FROM x; +NOTICE: s text my_integer +NOTICE: s2 my_integer + x_stl2_my_integer +------------------- + (1) + (1) + (1) + (1) +(4 rows) + +-- Mixed functions and ArrayCoerce expressions testing +-- Binary-coercible types: +-- should not be precalculated +SELECT x_stl2_array_oid(x_vlt_array_integer()::oid[]) FROM x; +NOTICE: v array_integer +NOTICE: s2 array_oid +NOTICE: v array_integer +NOTICE: s2 array_oid +NOTICE: v array_integer +NOTICE: s2 array_oid +NOTICE: v array_integer +NOTICE: s2 array_oid + x_stl2_array_oid +------------------ + {2,3} + {2,3} + {2,3} + {2,3} +(4 rows) + +SELECT x_stl2_array_oid(x_stl_array_integer()::oid[]) FROM x; +NOTICE: s array_integer +NOTICE: s2 array_oid + x_stl2_array_oid +------------------ + {2,3} + {2,3} + {2,3} + {2,3} +(4 rows) + +-- Not binary-coercible types: +DROP CAST (my_integer AS integer); +CREATE CAST (my_integer AS integer) + WITH FUNCTION cast_my_integer_as_integer_vlt; +-- should not be precalculated +SELECT x_stl2_array_integer('{(1), (2)}'::my_integer[]::integer[]) FROM x; +NOTICE: cast my_integer as integer volatile +NOTICE: cast my_integer as integer volatile +NOTICE: s2 array_integer +NOTICE: cast my_integer as integer volatile +NOTICE: cast my_integer as integer volatile +NOTICE: s2 array_integer +NOTICE: cast my_integer as integer volatile +NOTICE: cast my_integer as integer volatile +NOTICE: s2 array_integer +NOTICE: cast my_integer as integer volatile +NOTICE: cast my_integer as integer volatile +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1,2} + {1,2} + {1,2} + {1,2} +(4 rows) + +DROP CAST (my_integer AS integer); +CREATE CAST (my_integer AS integer) + WITH FUNCTION cast_my_integer_as_integer_stl; +SELECT x_stl2_array_integer('{(1), (2)}'::my_integer[]::integer[]) FROM x; +NOTICE: cast my_integer as integer stable +NOTICE: cast my_integer as integer stable +NOTICE: s2 array_integer + x_stl2_array_integer +---------------------- + {1,2} + {1,2} + {1,2} + {1,2} +(4 rows) + +DROP CAST (integer AS my_integer); +CREATE CAST (integer AS my_integer) + WITH FUNCTION cast_integer_as_my_integer_stl; +-- should not be precalculated +SELECT x_vlt_array_integer()::my_integer[] FROM x; +NOTICE: v array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable +NOTICE: v array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable +NOTICE: v array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable +NOTICE: v array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable + x_vlt_array_integer +--------------------- + {(2),(3)} + {(2),(3)} + {(2),(3)} + {(2),(3)} +(4 rows) + +SELECT x_stl_array_integer()::my_integer[] FROM x; +NOTICE: s array_integer +NOTICE: cast integer as my_integer stable +NOTICE: cast integer as my_integer stable + x_stl_array_integer +--------------------- + {(2),(3)} + {(2),(3)} + {(2),(3)} + {(2),(3)} +(4 rows) + +-- Mixed functions and ConvertRowtypeExpr testing +-- should not be precalculated +SELECT x_stl2_wxyz(x_vlt_wxyz_child()::wxyz_child::wxyz) FROM x; +NOTICE: v wxyz_child +NOTICE: s2 wxyz +NOTICE: v wxyz_child +NOTICE: s2 wxyz +NOTICE: v wxyz_child +NOTICE: s2 wxyz +NOTICE: v wxyz_child +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +-- should not be precalculated +SELECT x_stl2_wxyz(x_vlt_wxyz_child2()::wxyz_child2::wxyz) FROM x; +NOTICE: v wxyz_child2 +NOTICE: s2 wxyz +NOTICE: v wxyz_child2 +NOTICE: s2 wxyz +NOTICE: v wxyz_child2 +NOTICE: s2 wxyz +NOTICE: v wxyz_child2 +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz(x_stl_wxyz_child()::wxyz_child::wxyz) FROM x; +NOTICE: s wxyz_child +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +SELECT x_stl2_wxyz(x_stl_wxyz_child2()::wxyz_child2::wxyz) FROM x; +NOTICE: s wxyz_child2 +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) + (1,{2},t,3) +(4 rows) + +-- Mixed functions and CASE expressions testing +-- should not be precalculated +SELECT x_stl2(CASE WHEN x_vlt_boolean() THEN x_vlt() ELSE x_vlt() END) FROM x; +NOTICE: v boolean +NOTICE: v +NOTICE: s2 +NOTICE: v boolean +NOTICE: v +NOTICE: s2 +NOTICE: v boolean +NOTICE: v +NOTICE: s2 +NOTICE: v boolean +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- should not be precalculated +SELECT x_stl2(CASE x_vlt() WHEN x_vlt() THEN x_vlt() ELSE x_vlt() END) FROM x; +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: v +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(CASE WHEN x_stl2_boolean(TRUE) THEN x_stl() ELSE x_stl() END) +FROM x; +NOTICE: s2 boolean +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(CASE x_stl() WHEN x_stl() THEN x_stl() ELSE x_stl() END) FROM x; +NOTICE: s +NOTICE: s +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Mixed functions and RowCompareExpr testing +-- should not be precalculated +SELECT x_stl2_boolean((x_vlt(), 2) < (1, 3)) FROM x; +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean((x_stl(), 2) < (1, 3)) FROM x; +NOTICE: s +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- Mixed functions and COALESCE expressions testing +-- should not be precalculated +SELECT x_stl2(COALESCE(NULL, x_vlt2(NULL), 2)) FROM x; +NOTICE: v2 +NOTICE: s2 +NOTICE: v2 +NOTICE: s2 +NOTICE: v2 +NOTICE: s2 +NOTICE: v2 +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +SELECT x_stl2(COALESCE(NULL, x_stl2(NULL), 2)) FROM x; +NOTICE: s2 +NOTICE: s2 + x_stl2 +-------- + 2 + 2 + 2 + 2 +(4 rows) + +-- Mixed functions and GREATEST and LEAST functions testing +SELECT x_stl2(GREATEST(2, x_vlt(), 3)) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 3 + 3 + 3 + 3 +(4 rows) + +SELECT x_stl2(LEAST(2, x_vlt(), 3)) FROM x; -- should not be precalculated +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 +NOTICE: v +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +SELECT x_stl2(GREATEST(2, x_stl(), 3)) FROM x; +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 3 + 3 + 3 + 3 +(4 rows) + +SELECT x_stl2(LEAST(2, x_stl(), 3)) FROM x; +NOTICE: s +NOTICE: s2 + x_stl2 +-------- + 1 + 1 + 1 + 1 +(4 rows) + +-- Mixed functions and Xml expressions testing +-- should not be precalculated +SELECT x_stl2_xml(XMLCONCAT('', x_vlt_xml())) FROM x; +ERROR: unsupported XML feature +LINE 1: SELECT x_stl2_xml(XMLCONCAT('', x_vlt_xml())) FROM x; + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +-- should not be precalculated +SELECT x_stl2_xml( + XMLELEMENT(name foo, xmlattributes('bar' as bar), x_vlt_xml()) +) +FROM x; +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +-- should not be precalculated +SELECT x_stl2_xml(XMLFOREST('abc' AS foo, x_vlt_xml() AS bar)) FROM x; +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +-- should not be precalculated +SELECT x_stl2_xml(XMLPARSE(DOCUMENT x_vlt_text_xml())) FROM x; +NOTICE: v text xml +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +-- should not be precalculated +SELECT x_stl2_xml(XMLPARSE(CONTENT x_vlt_text_xml_content())) FROM x; +NOTICE: v text xml content +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +-- should not be precalculated +SELECT x_stl2_xml(XMLPI(name php, x_vlt_text_xml_instruction_content())) FROM x; +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +-- should not be precalculated +SELECT x_stl2_xml(XMLROOT(x_vlt_xml(), version '1.0', standalone yes)) FROM x; +NOTICE: v xml +ERROR: unsupported XML feature +LINE 1: SELECT 'foo'::xml + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +QUERY: SELECT 'foo'::xml +CONTEXT: PL/pgSQL function x_vlt_xml() line 4 at RETURN +-- should not be precalculated +SELECT x_stl2_text(XMLSERIALIZE(DOCUMENT x_vlt_xml() AS text)) FROM x; +NOTICE: v xml +ERROR: unsupported XML feature +LINE 1: SELECT 'foo'::xml + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +QUERY: SELECT 'foo'::xml +CONTEXT: PL/pgSQL function x_vlt_xml() line 4 at RETURN +-- should not be precalculated +SELECT x_stl2_text(XMLSERIALIZE(CONTENT x_vlt_xml_content() AS text)) FROM x; +NOTICE: v xml content +ERROR: unsupported XML feature +LINE 1: SELECT 'abcbarfoo'::xml + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +QUERY: SELECT 'abcbarfoo'::xml +CONTEXT: PL/pgSQL function x_vlt_xml_content() line 4 at RETURN +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_xml_content() IS DOCUMENT) FROM x; +NOTICE: v xml content +ERROR: unsupported XML feature +LINE 1: SELECT 'abcbarfoo'::xml + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +QUERY: SELECT 'abcbarfoo'::xml +CONTEXT: PL/pgSQL function x_vlt_xml_content() line 4 at RETURN +SELECT x_stl2_xml(XMLCONCAT('', x_stl_xml())) FROM x; +ERROR: unsupported XML feature +LINE 1: SELECT x_stl2_xml(XMLCONCAT('', x_stl_xml())) FROM x; + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml( + XMLELEMENT(name foo, xmlattributes('bar' as bar), x_stl_xml()) +) +FROM x; +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml(XMLFOREST('abc' AS foo, x_stl_xml() AS bar)) FROM x; +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml(XMLPARSE(DOCUMENT x_stl_text_xml())) FROM x; +NOTICE: s text xml +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml(XMLPARSE(CONTENT x_stl_text_xml_content())) FROM x; +NOTICE: s xml content +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml(XMLPI(name php, x_stl_text_xml_instruction_content())) FROM x; +ERROR: unsupported XML feature +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +SELECT x_stl2_xml(XMLROOT(x_stl_xml(), version '1.0', standalone yes)) FROM x; +NOTICE: s xml +ERROR: unsupported XML feature +LINE 1: SELECT 'foo'::xml + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +QUERY: SELECT 'foo'::xml +CONTEXT: PL/pgSQL function x_stl_xml() line 4 at RETURN +SELECT x_stl2_text(XMLSERIALIZE(DOCUMENT x_stl_xml() AS text)) FROM x; +NOTICE: s xml +ERROR: unsupported XML feature +LINE 1: SELECT 'foo'::xml + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +QUERY: SELECT 'foo'::xml +CONTEXT: PL/pgSQL function x_stl_xml() line 4 at RETURN +SELECT x_stl2_text(XMLSERIALIZE(CONTENT x_stl_xml_content() AS text)) FROM x; +NOTICE: s xml content +ERROR: unsupported XML feature +LINE 1: SELECT 'abcbarfoo'::xml + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +QUERY: SELECT 'abcbarfoo'::xml +CONTEXT: PL/pgSQL function x_stl_xml_content() line 4 at RETURN +SELECT x_stl2_boolean(x_stl_xml_content() IS DOCUMENT) FROM x; +NOTICE: s xml content +ERROR: unsupported XML feature +LINE 1: SELECT 'abcbarfoo'::xml + ^ +DETAIL: This functionality requires the server to be built with libxml support. +HINT: You need to rebuild PostgreSQL using --with-libxml. +QUERY: SELECT 'abcbarfoo'::xml +CONTEXT: PL/pgSQL function x_stl_xml_content() line 4 at RETURN +-- Mixed functions and NullTest expressions testing +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt() IS NULL) FROM x; +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt() IS NOT NULL) FROM x; +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean +NOTICE: v +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_wxyz() IS NULL) FROM x; +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_wxyz() IS NOT NULL) FROM x; +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean +NOTICE: v wxyz +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl() IS NULL) FROM x; +NOTICE: s +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl() IS NOT NULL) FROM x; +NOTICE: s +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl_wxyz() IS NULL) FROM x; +NOTICE: s wxyz +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl_wxyz() IS NOT NULL) FROM x; +NOTICE: s wxyz +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- Mixed functions and BooleanTest expressions testing +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS TRUE) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT TRUE) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS FALSE) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT FALSE) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS UNKNOWN) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT UNKNOWN) FROM x; +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean +NOTICE: v boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS TRUE) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS NOT TRUE) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS FALSE) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS NOT FALSE) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(NULL) IS UNKNOWN) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + t + t + t + t +(4 rows) + +SELECT x_stl2_boolean(x_stl2_boolean(NULL) IS NOT UNKNOWN) FROM x; +NOTICE: s2 boolean +NOTICE: s2 boolean + x_stl2_boolean +---------------- + f + f + f + f +(4 rows) + +SET track_functions TO DEFAULT; +-- ROW() expressions with dropped columns testing +ALTER TABLE wxyz DROP COLUMN z; +-- Update some functions +CREATE OR REPLACE FUNCTION public.x_stl2_wxyz ( + wxyz +) +RETURNS wxyz STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 wxyz'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; +-- ROW() expressions testing +SELECT x_stl2_wxyz((1, '{2}', TRUE)) FROM x; +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t) + (1,{2},t) + (1,{2},t) + (1,{2},t) +(4 rows) + +SELECT x_stl2_wxyz(ROW(1, '{2}', TRUE)) FROM x; +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t) + (1,{2},t) + (1,{2},t) + (1,{2},t) +(4 rows) + +SELECT x_stl2_wxyz((1, '{2}', TRUE)::wxyz) FROM x; +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t) + (1,{2},t) + (1,{2},t) + (1,{2},t) +(4 rows) + +-- Mixed functions and ROW() expressions testing +-- should not be precalculated +SELECT x_stl2_wxyz((x_vlt(), '{2}', TRUE)) FROM x; +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz +NOTICE: v +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t) + (1,{2},t) + (1,{2},t) + (1,{2},t) +(4 rows) + +SELECT x_stl2_wxyz((x_stl(), '{2}', TRUE)) FROM x; +NOTICE: s +NOTICE: s2 wxyz + x_stl2_wxyz +------------- + (1,{2},t) + (1,{2},t) + (1,{2},t) + (1,{2},t) +(4 rows) + +-- PL/pgSQL Simple expressions +-- Make sure precalculated stable functions can't be simple expressions: these +-- expressions are only initialized once per transaction and then executed +-- multiple times. +BEGIN; +SELECT simple(); + simple +-------- + 4 +(1 row) + +INSERT INTO x VALUES (5); +SELECT simple(); + simple +-------- + 5 +(1 row) + +ROLLBACK; +-- Drop tables for testing +DROP TABLE x; +DROP FUNCTION x_vlt_wxyz, x_vlt_wxyz_child, x_vlt_wxyz_child2; +DROP FUNCTION x_stl_wxyz, x_stl_wxyz_child, x_stl_wxyz_child2, x_stl2_wxyz; +DROP TABLE wxyz, wxyz_child, wxyz_child2; +DROP FUNCTION x_stl2_no_columns; +DROP TABLE no_columns, no_columns_child, no_columns_child2; diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index 16f979c..a5c6bf1 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -116,7 +116,7 @@ test: plancache limit plpgsql copy2 temp domain rangefuncs prepare without_oid c # ---------- # Another group of parallel tests # ---------- -test: identity partition_join partition_prune reloptions hash_part indexing partition_aggregate +test: identity partition_join partition_prune reloptions hash_part indexing partition_aggregate precalculate_stable_functions # event triggers cannot run concurrently with any test that runs DDL test: event_trigger diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index 42632be..eb47939 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -188,6 +188,7 @@ test: reloptions test: hash_part test: indexing test: partition_aggregate +test: precalculate_stable_functions test: event_trigger test: fast_default test: stats diff --git a/src/test/regress/sql/precalculate_stable_functions.sql b/src/test/regress/sql/precalculate_stable_functions.sql new file mode 100644 index 0000000..23b1f04 --- /dev/null +++ b/src/test/regress/sql/precalculate_stable_functions.sql @@ -0,0 +1,1932 @@ +-- +-- PRECALCULATE STABLE FUNCTIONS +-- +-- Create types and tables for testing + +CREATE TYPE my_integer AS (value integer); +CREATE TYPE composite_type AS (first integer, second integer[], third boolean); + +CREATE TABLE x (x integer); +INSERT INTO x SELECT generate_series(1, 4) x; + +CREATE TABLE wxyz (w integer, x integer[], y boolean, z integer); +CREATE TABLE wxyz_child () INHERITS (wxyz); +CREATE TABLE wxyz_child2 (a integer, b integer) INHERITS (wxyz); + +CREATE TABLE no_columns (); +CREATE TABLE no_columns_child () INHERITS (no_columns); +CREATE TABLE no_columns_child2 (a integer, b integer) INHERITS (no_columns); + +-- Create volatile functions for testing + +CREATE OR REPLACE FUNCTION public.x_vlt ( +) +RETURNS integer VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v'; + RETURN 1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_vlt_my_integer ( +) +RETURNS my_integer VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v my_integer'; + RETURN '(1)'::my_integer; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_vlt_array_integer ( +) +RETURNS int[] VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v array_integer'; + RETURN '{2, 3}'::integer[]; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_vlt_boolean ( +) +RETURNS boolean VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v boolean'; + RETURN TRUE; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_vlt_wxyz ( +) +RETURNS wxyz VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v wxyz'; + RETURN '(1, {2}, TRUE, 3)'::wxyz; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_vlt_wxyz_child ( +) +RETURNS wxyz_child VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v wxyz_child'; + RETURN '(1, {2}, TRUE, 3)'::wxyz_child; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_vlt_wxyz_child2 ( +) +RETURNS wxyz_child2 VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v wxyz_child2'; + RETURN '(1, {2}, TRUE, 3, 4, 5)'::wxyz_child2; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_vlt_oid ( +) +RETURNS oid VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v oid'; + RETURN 1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_vlt_text_integer ( +) +RETURNS text VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v text integer'; + RETURN 1::text; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_vlt_text_my_integer ( +) +RETURNS text VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v text my_integer'; + RETURN '(1)'::text; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_vlt_text_xml ( +) +RETURNS text VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v text xml'; + RETURN 'Manual'::text; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_vlt_text_xml_content ( +) +RETURNS text VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v text xml content'; + RETURN 'abcbarfoo'::text; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_vlt_text_xml_instruction_content ( +) +RETURNS text VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v text xml instruction content'; + RETURN 'echo "hello world";'::text; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_vlt_xml ( +) +RETURNS xml VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v xml'; + RETURN 'foo'::xml; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_vlt_xml_content ( +) +RETURNS xml VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v xml content'; + RETURN 'abcbarfoo'::xml; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_vlt2 ( + integer +) +RETURNS integer VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'v2'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.equal_integers_vlt ( + integer, + integer +) +RETURNS boolean VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'equal integers volatile'; + RETURN $1 = $2; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.equal_my_integer_vlt ( + my_integer, + my_integer +) +RETURNS boolean VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'equal my_integer volatile'; + RETURN $1.value = $2.value; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.cast_integer_as_my_integer_vlt ( + integer +) +RETURNS my_integer VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'cast integer as my_integer volatile'; + RETURN ROW($1)::my_integer; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.cast_my_integer_as_integer_vlt ( + my_integer +) +RETURNS integer VOLATILE AS +$body$ +BEGIN + RAISE NOTICE 'cast my_integer as integer volatile'; + RETURN $1.value; +END; +$body$ +LANGUAGE 'plpgsql'; + +-- Create stable functions for testing + +CREATE OR REPLACE FUNCTION public.x_stl ( +) +RETURNS integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 's'; + RETURN 1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl_my_integer ( +) +RETURNS my_integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 's my_integer'; + RETURN '(1)'::my_integer; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl_array_integer ( +) +RETURNS int[] STABLE AS +$body$ +BEGIN + RAISE NOTICE 's array_integer'; + RETURN '{2, 3}'::integer[]; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl_wxyz ( +) +RETURNS wxyz STABLE AS +$body$ +BEGIN + RAISE NOTICE 's wxyz'; + RETURN '(1, {2}, TRUE, 3)'::wxyz; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl_wxyz_child ( +) +RETURNS wxyz_child STABLE AS +$body$ +BEGIN + RAISE NOTICE 's wxyz_child'; + RETURN '(1, {2}, TRUE, 3)'::wxyz_child; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl_wxyz_child2 ( +) +RETURNS wxyz_child2 STABLE AS +$body$ +BEGIN + RAISE NOTICE 's wxyz_child2'; + RETURN '(1, {2}, TRUE, 3, 4, 5)'::wxyz_child2; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl_oid ( +) +RETURNS oid STABLE AS +$body$ +BEGIN + RAISE NOTICE 's oid'; + RETURN 1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl_text_integer ( +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's text integer'; + RETURN 1::text; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl_text_my_integer ( +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's text my_integer'; + RETURN '(1)'::text; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl_text_xml ( +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's text xml'; + RETURN 'Manual'::text; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl_text_xml_content ( +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's xml content'; + RETURN 'abcbarfoo'::text; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl_text_xml_instruction_content ( +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's text xml instruction content'; + RETURN 'echo "hello world";'::text; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl_xml ( +) +RETURNS xml STABLE AS +$body$ +BEGIN + RAISE NOTICE 's xml'; + RETURN 'foo'::xml; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl_xml_content ( +) +RETURNS xml STABLE AS +$body$ +BEGIN + RAISE NOTICE 's xml content'; + RETURN 'abcbarfoo'::xml; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl2 ( + integer +) +RETURNS integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl2_strict ( + integer +) +RETURNS integer STABLE STRICT AS +$body$ +BEGIN + RAISE NOTICE 's2 strict'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl2_boolean ( + boolean +) +RETURNS boolean STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 boolean'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl2_array_integer ( + integer[] +) +RETURNS integer[] STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 array_integer'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl2_array_oid ( + oid[] +) +RETURNS oid[] STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 array_oid'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl2_wxyz ( + wxyz +) +RETURNS wxyz STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 wxyz'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl2_composite_type ( + composite_type +) +RETURNS composite_type STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 composite_type'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl2_my_integer ( + my_integer +) +RETURNS my_integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 my_integer'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl2_no_columns ( + no_columns +) +RETURNS no_columns STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 no_columns'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl2_name ( + name +) +RETURNS name STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 name'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl2_xml ( + xml +) +RETURNS xml STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 xml'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_stl2_text ( + text +) +RETURNS text STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 text'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.equal_integers_stl ( + integer, + integer +) +RETURNS boolean STABLE AS +$body$ +BEGIN + RAISE NOTICE 'equal integers stable'; + RETURN $1 = $2; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.equal_booleans_stl_strict ( + boolean, + boolean +) +RETURNS boolean STABLE STRICT AS +$body$ +BEGIN + RAISE NOTICE 'equal booleans stable strict'; + RETURN $1 = $2; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.equal_my_integer_stl ( + my_integer, + my_integer +) +RETURNS boolean STABLE AS +$body$ +BEGIN + RAISE NOTICE 'equal my_integer stable'; + RETURN $1.value = $2.value; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.cast_integer_as_my_integer_stl ( + integer +) +RETURNS my_integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 'cast integer as my_integer stable'; + RETURN ROW($1)::my_integer; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.cast_my_integer_as_integer_stl ( + my_integer +) +RETURNS integer STABLE AS +$body$ +BEGIN + RAISE NOTICE 'cast my_integer as integer stable'; + RETURN $1.value; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.stable_max( +) +RETURNS integer STABLE AS +$body$ +BEGIN + RETURN (SELECT max(x) from x); +END +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.simple( +) +RETURNS integer STABLE AS +$body$ +BEGIN + RETURN stable_max(); +END +$body$ +LANGUAGE 'plpgsql'; + +-- Create immutable functions for testing + +CREATE OR REPLACE FUNCTION public.x_imm2 ( + integer +) +RETURNS integer IMMUTABLE AS +$body$ +BEGIN + RAISE NOTICE 'i2'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_imm2_strict ( + integer +) +RETURNS integer IMMUTABLE STRICT AS +$body$ +BEGIN + RAISE NOTICE 'i2 strict'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.x_imm2_my_integer ( + my_integer +) +RETURNS my_integer IMMUTABLE AS +$body$ +BEGIN + RAISE NOTICE 'i2 my_integer'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.equal_integers_imm ( + integer, + integer +) +RETURNS boolean IMMUTABLE AS +$body$ +BEGIN + RAISE NOTICE 'equal integers immutable'; + RETURN $1 = $2; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.equal_booleans_imm ( + boolean, + boolean +) +RETURNS boolean IMMUTABLE AS +$body$ +BEGIN + RAISE NOTICE 'equal booleans immutable'; + RETURN $1 = $2; +END; +$body$ +LANGUAGE 'plpgsql'; + +CREATE OR REPLACE FUNCTION public.equal_my_integer_imm ( + my_integer, + my_integer +) +RETURNS boolean IMMUTABLE AS +$body$ +BEGIN + RAISE NOTICE 'equal my_integer immutable'; + RETURN $1.value = $2.value; +END; +$body$ +LANGUAGE 'plpgsql'; + +-- Create operators for testing + +CREATE OPERATOR === ( + PROCEDURE = equal_integers_vlt, + LEFTARG = integer, + RIGHTARG = integer +); + +CREATE OPERATOR ==== ( + PROCEDURE = equal_integers_stl, + LEFTARG = integer, + RIGHTARG = integer +); + +CREATE OPERATOR ===== ( + PROCEDURE = equal_integers_imm, + LEFTARG = integer, + RIGHTARG = integer +); + +CREATE OPERATOR ==== ( + PROCEDURE = equal_booleans_stl_strict, + LEFTARG = boolean, + RIGHTARG = boolean +); + +CREATE OPERATOR ===== ( + PROCEDURE = equal_booleans_imm, + LEFTARG = boolean, + RIGHTARG = boolean +); + +-- Functions testing + +-- Simple functions testing +SELECT x_vlt() FROM x; -- should not be precalculated +SELECT x_stl() FROM x; + +-- WHERE clause testing +SELECT x_vlt() FROM x WHERE x_vlt() < x; -- should not be precalculated +SELECT x_stl() FROM x WHERE x_stl() < x; + +-- JOIN/ON clause testing + +-- should not be precalculated +SELECT * FROM x JOIN generate_series(1, 2) y ON x_vlt() < x; + +SELECT * FROM x JOIN generate_series(1, 2) y ON x_stl() < x; + +-- Functions with constant arguments testing +SELECT x_vlt2(1) FROM x; -- should not be precalculated +SELECT x_stl2(1) FROM x; + +-- Nested functions testing +SELECT x_stl2(x_vlt()) FROM x; -- should not be precalculated +SELECT x_imm2(x_vlt()) FROM x; -- should not be precalculated + +SELECT x_stl2(x_stl()) FROM x; +SELECT x_imm2(x_stl()) FROM x; + +-- Strict functions testing +SELECT x_stl2_strict(x_vlt()) FROM x; -- should not be precalculated +SELECT x_imm2_strict(x_vlt()) FROM x; -- should not be precalculated + +SELECT x_stl2_strict(x_stl2_strict(1)) FROM x; +SELECT x_imm2_strict(x_stl2_strict(1)) FROM x; + +-- Strict functions with null arguments testing +SELECT x_stl2_strict(x_stl2(NULL)) FROM x; +SELECT x_imm2_strict(x_stl2(NULL)) FROM x; + +-- Operators testing + +SELECT 1 === 2 FROM x; -- should not be precalculated +SELECT 1 ==== 2 FROM x; + +-- Strict operators testing +SELECT x_stl2_boolean(NULL) ==== TRUE FROM x; +SELECT x_stl2_boolean(NULL) ===== TRUE FROM x; + +-- Mixed functions and operators testing +SELECT x_stl2_boolean(1 === 2) FROM x; -- should not be precalculated +SELECT x_stl2_boolean(1 ==== 2) FROM x; + +SELECT x_vlt() ==== 1 FROM x; -- should not be precalculated +SELECT x_stl() ==== 1 FROM x; + +-- IS (NOT) DISTINCT FROM expression testing + +-- create operator here because we will drop and reuse it several times +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +-- should not be precalculated +SELECT '(1)'::my_integer IS DISTINCT FROM '(2)'::my_integer FROM x; + +-- should not be precalculated +SELECT '(1)'::my_integer IS NOT DISTINCT FROM '(2)'::my_integer FROM x; + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +SELECT '(1)'::my_integer IS DISTINCT FROM '(2)'::my_integer FROM x; +SELECT '(1)'::my_integer IS NOT DISTINCT FROM '(2)'::my_integer FROM x; + +-- IS (NOT) DISTINCT FROM expressions with null arguments testing +SELECT x_stl2_boolean(x_stl2(NULL) IS DISTINCT FROM 1) FROM x; +SELECT x_stl2_boolean(x_stl2(NULL) IS NOT DISTINCT FROM 1) FROM x; + +SELECT x_stl2_boolean(x_stl2(NULL) IS DISTINCT FROM x_stl2(NULL)) FROM x; +SELECT x_stl2_boolean(x_stl2(NULL) IS NOT DISTINCT FROM x_stl2(NULL)) FROM x; + +-- Mixed functions and IS (NOT) DISTINCT FROM expressions testing +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +-- should not be precalculated +SELECT equal_booleans_stl_strict( + ('(1)'::my_integer IS DISTINCT FROM '(1)'::my_integer), + ('(1)'::my_integer IS NOT DISTINCT FROM '(1)'::my_integer) +) +FROM x; + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +SELECT equal_booleans_stl_strict( + ('(1)'::my_integer IS DISTINCT FROM '(1)'::my_integer), + ('(1)'::my_integer IS NOT DISTINCT FROM '(1)'::my_integer) +) +FROM x; + +-- should not be precalculated +SELECT (x_vlt_my_integer() IS DISTINCT FROM '(1)'::my_integer) FROM x; + +-- should not be precalculated +SELECT (x_vlt_my_integer() IS NOT DISTINCT FROM '(1)'::my_integer) FROM x; + +SELECT (x_stl_my_integer() IS DISTINCT FROM '(1)'::my_integer) FROM x; +SELECT (x_stl_my_integer() IS NOT DISTINCT FROM '(1)'::my_integer) FROM x; + +-- NULLIF expressions testing + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +-- should not be precalculated +SELECT NULLIF('(1)'::my_integer, '(2)'::my_integer) FROM x; + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +SELECT NULLIF('(1)'::my_integer, '(2)'::my_integer) FROM x; + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_imm, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +SELECT NULLIF('(1)'::my_integer, '(2)'::my_integer) FROM x; + +-- NULLIF expressions with null arguments testing +SELECT x_stl2(NULLIF(1, NULL)) FROM x; +SELECT x_stl2(NULLIF(NULL::integer, NULL)) FROM x; + +-- Mixed functions and NULLIF expressions testing +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +-- should not be precalculated +SELECT equal_my_integer_stl( + NULLIF('(1)'::my_integer, '(2)'::my_integer), + NULLIF('(2)'::my_integer, '(2)'::my_integer) +) +FROM x; + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +SELECT equal_my_integer_stl( + NULLIF('(1)'::my_integer, '(2)'::my_integer), + NULLIF('(2)'::my_integer, '(2)'::my_integer) +) +FROM x; + +-- should not be precalculated +SELECT NULLIF(x_vlt_my_integer(), '(2)'::my_integer) FROM x; + +SELECT NULLIF(x_stl_my_integer(), '(2)'::my_integer) FROM x; + +-- "scalar op ANY/ALL (array)" / "scalar IN (2 or more values)" expressions +-- testing + +SELECT 1 === ANY ('{2, 3}') FROM x; -- should not be precalculated +SELECT 1 === ALL ('{2, 3}') FROM x; -- should not be precalculated + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +-- should not be precalculated +SELECT '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; + +SELECT 1 ==== ANY ('{2, 3}') FROM x; +SELECT 1 ==== ALL ('{2, 3}') FROM x; + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +SELECT '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; + +SELECT 1 ===== ANY ('{2, 3}') FROM x; +SELECT 1 ===== ALL ('{2, 3}') FROM x; + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_imm, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +SELECT '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; + +-- "scalar op ANY/ALL (array)" / "scalar IN (2 or more values)" expressions with +-- null arguments testing +SELECT 1 ==== ANY ('{2, NULL}') FROM x; +SELECT x_stl2_boolean(1 ==== ANY (NULL)) FROM x; +SELECT NULL ==== ANY ('{2, 3}'::integer[]) FROM x; +SELECT NULL ==== ANY ('{2, NULL}'::integer[]) FROM x; +SELECT x_stl2_boolean(NULL::integer ==== ANY (NULL)) FROM x; + +SELECT 1 ==== ALL ('{2, NULL}') FROM x; +SELECT x_stl2_boolean(1 ==== ALL (NULL)) FROM x; +SELECT NULL ==== ALL ('{2, 3}'::integer[]) FROM x; +SELECT NULL ==== ALL ('{2, NULL}'::integer[]) FROM x; +SELECT x_stl2_boolean(NULL::integer ==== ALL (NULL)) FROM x; + +SELECT x_stl2_boolean(1 IN (2, NULL)) FROM x; +SELECT x_stl2_boolean(NULL IN (2, 3)) FROM x; +SELECT x_stl2_boolean(NULL IN (2, NULL)) FROM x; + +-- Mixed functions and "scalar op ANY/ALL (array)" / "scalar IN (2 or more +-- values)" expressions testing + +-- should not be precalculated +SELECT x_stl2_boolean(1 === ANY ('{2, 3}')) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(1 === ALL ('{2, 3}')) FROM x; + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +-- should not be precalculated +SELECT x_stl2_boolean( + '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) +) +FROM x; + +SELECT x_stl2_boolean(1 ==== ANY ('{2, 3}')) FROM x; +SELECT x_stl2_boolean(1 ==== ALL ('{2, 3}')) FROM x; + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +SELECT x_stl2_boolean( + '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) +) +FROM x; + +-- should not be precalculated +SELECT x_vlt() ==== ANY ('{2, 3}') FROM x; + +-- should not be precalculated +SELECT x_vlt() ==== ALL ('{2, 3}') FROM x; + +-- should not be precalculated +SELECT 1 ==== ANY (x_vlt_array_integer()) FROM x; + +-- should not be precalculated +SELECT 1 ==== ALL (x_vlt_array_integer()) FROM x; + +-- should not be precalculated +SELECT x_vlt_my_integer() IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; + +SELECT x_stl() ==== ANY ('{2, 3}') FROM x; +SELECT x_stl() ==== ALL ('{2, 3}') FROM x; + +SELECT 1 ==== ANY (x_stl_array_integer()) FROM x; +SELECT 1 ==== ALL (x_stl_array_integer()) FROM x; + +SELECT x_stl_my_integer() IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; + +-- Boolean expressions testing + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() AND x_stl2_boolean(TRUE)) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() OR x_stl2_boolean(TRUE)) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(NOT x_vlt_boolean()) FROM x; + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) AND x_stl2_boolean(TRUE)) FROM x; +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) OR x_stl2_boolean(TRUE)) FROM x; +SELECT x_stl2_boolean(NOT x_stl2_boolean(TRUE)) FROM x; + +-- ARRAY[] expressions testing + +-- should not be precalculated +SELECT x_stl2_array_integer(ARRAY[x_vlt(), 2]) FROM x; + +SELECT x_stl2_array_integer(ARRAY[x_stl(), 2]) FROM x; + +-- Multidimensional ARRAY[] expressions testing + +-- should not be precalculated +SELECT x_stl2_array_integer(ARRAY[[x_vlt(), 2], [3, 4]]) FROM x; + +SELECT x_stl2_array_integer(ARRAY[[x_stl(), 2], [3, 4]]) FROM x; + +-- Array subscripting operations testing + +SELECT x_stl2(('{1, 2}'::integer[])[1]) FROM x; +SELECT x_stl2_array_integer(('{1, 2}'::integer[])[:]) FROM x; + +-- Mixed functions and array subscripting operations testing + +-- should not be precalculated +SELECT x_stl2((x_vlt_array_integer())[x_vlt()]) FROM x; + +-- should not be precalculated +SELECT x_stl2((x_vlt_array_integer())[1]) FROM x; + +-- should not be precalculated +SELECT x_stl2_array_integer((x_vlt_array_integer())[:]) FROM x; + +-- should not be precalculated +SELECT x_stl2(('{1, 2}'::integer[])[x_vlt()]) FROM x; + +SELECT x_stl2((x_stl_array_integer())[x_stl()]) FROM x; +SELECT x_stl2((x_stl_array_integer())[1]) FROM x; +SELECT x_stl2_array_integer((x_stl_array_integer())[:]) FROM x; +SELECT x_stl2(('{1, 2}'::integer[])[x_stl()]) FROM x; + +-- FieldSelect expressions testing + +SELECT x_stl2(('(1, {2}, TRUE, 3)'::wxyz).w) FROM x; +SELECT x_stl2(('(1)'::my_integer).value) FROM x; + +-- Mixed functions and FieldSelect expressions testing +SELECT x_stl2((x_vlt_wxyz()).w) FROM x; -- should not be precalculated +SELECT x_stl2((x_vlt_my_integer()).value) FROM x; -- should not be precalculated + +SELECT x_stl2((x_stl_wxyz()).w) FROM x; +SELECT x_stl2((x_stl_my_integer()).value) FROM x; + +-- ROW() expressions testing + +SELECT x_stl2_wxyz((1, '{2}', TRUE, 3)) FROM x; +SELECT x_stl2_wxyz(ROW(1, '{2}', TRUE, 3)) FROM x; +SELECT x_stl2_wxyz((1, '{2}', TRUE, 3)::wxyz) FROM x; + +SELECT x_stl2_composite_type((1, '{2}', TRUE)) FROM x; +SELECT x_stl2_composite_type(ROW(1, '{2}', TRUE)) FROM x; +SELECT x_stl2_composite_type((1, '{2}', TRUE)::composite_type) FROM x; + +-- Mixed functions and ROW() expressions testing + +-- should not be precalculated +SELECT x_stl2_wxyz((x_vlt(), '{2}', TRUE, 3)) FROM x; + +SELECT x_stl2_wxyz((x_stl(), '{2}', TRUE, 3)) FROM x; + +-- RelabelType expressions testing + +-- should not be precalculated +SELECT x_stl2(x_vlt_oid()::integer) FROM x; + +SELECT x_stl2(x_stl_oid()::integer) FROM x; + +-- CoerceViaIO expressions testing + +SELECT x_stl2_my_integer('(1)'::text::my_integer) FROM x; + +-- should not be precalculated +SELECT x_stl2(x_vlt_text_integer()::integer) FROM x; + +SELECT x_stl2(x_stl_text_integer()::integer) FROM x; + +-- Mixed functions and CoerceViaIO expressions testing + +-- should not be precalculated +SELECT x_stl2_my_integer(x_vlt_text_my_integer()::my_integer) FROM x; + +SELECT x_stl2_my_integer(x_stl_text_my_integer()::my_integer) FROM x; + +-- ArrayCoerce expressions testing + +-- Binary-coercible types: + +-- should not be precalculated +SELECT x_stl2_array_oid(x_vlt_array_integer()::oid[]) FROM x; + +SELECT x_stl2_array_oid(x_stl_array_integer()::oid[]) FROM x; + +-- Not binary-coercible types: +-- create cast here because we will drop and reuse it several times +CREATE CAST (integer AS my_integer) + WITH FUNCTION cast_integer_as_my_integer_vlt; + +SELECT '{1, 2}'::integer[]::my_integer[] FROM x; -- should not be precalculated + +DROP CAST (integer AS my_integer); +CREATE CAST (integer AS my_integer) + WITH FUNCTION cast_integer_as_my_integer_stl; + +SELECT '{1, 2}'::integer[]::my_integer[] FROM x; + +-- Mixed functions and ArrayCoerce expressions testing +-- Not binary-coercible types: +-- create cast here because we will drop and reuse it several times +CREATE CAST (my_integer AS integer) + WITH FUNCTION cast_my_integer_as_integer_vlt; + +-- should not be precalculated +SELECT x_stl2_array_integer('{(1), (2)}'::my_integer[]::integer[]) FROM x; + +DROP CAST (my_integer AS integer); +CREATE CAST (my_integer AS integer) + WITH FUNCTION cast_my_integer_as_integer_stl; + +SELECT x_stl2_array_integer('{(1), (2)}'::my_integer[]::integer[]) FROM x; + +DROP CAST (integer AS my_integer); +CREATE CAST (integer AS my_integer) + WITH FUNCTION cast_integer_as_my_integer_stl; + +-- should not be precalculated +SELECT x_vlt_array_integer()::my_integer[] FROM x; + +SELECT x_stl_array_integer()::my_integer[] FROM x; + +-- ConvertRowtypeExpr testing + +SELECT x_stl2_wxyz('(1, {2}, TRUE, 3)'::wxyz_child::wxyz) FROM x; +SELECT x_stl2_wxyz('(1, {2}, TRUE, 3, 4, 5)'::wxyz_child2::wxyz) FROM x; + +SELECT x_stl2_no_columns('()'::no_columns_child::no_columns) FROM x; +SELECT x_stl2_no_columns('(1, 2)'::no_columns_child2::no_columns) FROM x; + +-- Mixed functions and ConvertRowtypeExpr testing + +-- should not be precalculated +SELECT x_stl2_wxyz(x_vlt_wxyz_child()::wxyz_child::wxyz) FROM x; + +-- should not be precalculated +SELECT x_stl2_wxyz(x_vlt_wxyz_child2()::wxyz_child2::wxyz) FROM x; + +SELECT x_stl2_wxyz(x_stl_wxyz_child()::wxyz_child::wxyz) FROM x; +SELECT x_stl2_wxyz(x_stl_wxyz_child2()::wxyz_child2::wxyz) FROM x; + +-- CASE expressions testing + +-- should not be precalculated +SELECT x_stl2(CASE WHEN x_vlt_boolean() THEN x_vlt() ELSE x_vlt() END) FROM x; + +-- should not be precalculated +SELECT x_stl2(CASE x_vlt() WHEN x_vlt() THEN x_vlt() ELSE x_vlt() END) FROM x; + +SELECT x_stl2(CASE WHEN x_stl2_boolean(TRUE) THEN x_stl() ELSE x_stl() END) +FROM x; + +SELECT x_stl2(CASE x_stl() WHEN x_stl() THEN x_stl() ELSE x_stl() END) FROM x; + +-- RowCompareExpr testing + +SELECT x_stl2_boolean((1, 2) < (1, 3)) FROM x; + +-- Mixed functions and RowCompareExpr testing + +-- should not be precalculated +SELECT x_stl2_boolean((x_vlt(), 2) < (1, 3)) FROM x; + +SELECT x_stl2_boolean((x_stl(), 2) < (1, 3)) FROM x; + +-- COALESCE expressions testing + +-- should not be precalculated +SELECT x_stl2(COALESCE(NULL, x_vlt2(NULL), 2)) FROM x; + +SELECT x_stl2(COALESCE(NULL, x_stl2(NULL), 2)) FROM x; + +-- GREATEST and LEAST functions testing + +SELECT x_stl2(GREATEST(2, 1, 3)) FROM x; +SELECT x_stl2(LEAST(2, 1, 3)) FROM x; + +-- Mixed functions and GREATEST and LEAST functions testing + +-- should not be precalculated +SELECT x_stl2(GREATEST(2, x_vlt(), 3)) FROM x; + +-- should not be precalculated +SELECT x_stl2(LEAST(2, x_vlt(), 3)) FROM x; + +SELECT x_stl2(GREATEST(2, x_stl(), 3)) FROM x; +SELECT x_stl2(LEAST(2, x_stl(), 3)) FROM x; + +-- SQLValueFunction testing + +CREATE ROLE regress_testrol2 SUPERUSER; +CREATE ROLE regress_testrol1 SUPERUSER LOGIN IN ROLE regress_testrol2; + +\c - +SET SESSION AUTHORIZATION regress_testrol1; +SET ROLE regress_testrol2; + +SELECT x_stl2_boolean(date(now()) = current_date) FROM x; + +SELECT x_stl2_boolean(now()::timetz = current_time) FROM x; +SELECT x_stl2_boolean(now()::timetz(2) = current_time(2)) FROM x; -- precision + +SELECT x_stl2_boolean(now() = current_timestamp) FROM x; + +-- precision +SELECT x_stl2_boolean( + length(current_timestamp::text) >= length(current_timestamp(0)::text) +) +FROM x; + +SELECT x_stl2_boolean(now()::time = localtime) FROM x; +SELECT x_stl2_boolean(now()::time(2) = localtime(2)) FROM x; -- precision + +SELECT x_stl2_boolean(now()::timestamp = localtimestamp) FROM x; + +-- precision +SELECT x_stl2_boolean(now()::timestamp(2) = localtimestamp(2)) FROM x; + +SELECT x_stl2_name(current_role) FROM x; +SELECT x_stl2_name(current_user) FROM x; +SELECT x_stl2_name(user) FROM x; +SELECT x_stl2_name(session_user) FROM x; +SELECT x_stl2_name(current_catalog) FROM x; +SELECT x_stl2_name(current_schema) FROM x; + +\c +DROP ROLE regress_testrol1, regress_testrol2; + +-- Xml expressions testing + +SELECT x_stl2_xml(XMLCONCAT('', 'foo')) FROM x; + +SELECT x_stl2_xml( + XMLELEMENT(name foo, xmlattributes('bar' as bar), 'cont', 'ent') +) +FROM x; + +SELECT x_stl2_xml(XMLFOREST('abc' AS foo, 123 AS bar)) FROM x; + +SELECT x_stl2_xml(XMLPARSE( + DOCUMENT 'Manual' +)) +FROM x; + +SELECT x_stl2_xml(XMLPARSE(CONTENT 'abcbarfoo')) FROM x; + +SELECT x_stl2_xml(XMLPI(name php, 'echo "hello world";')) FROM x; + +SELECT x_stl2_xml(XMLROOT( + 'abc', + version '1.0', + standalone yes +)) +FROM x; + +SELECT x_stl2_text(XMLSERIALIZE( + DOCUMENT 'Manual' AS text +)) +FROM x; + +SELECT x_stl2_text(XMLSERIALIZE( + CONTENT 'abcbarfoo' AS text +)) +FROM x; + +SELECT x_stl2_boolean('abcbarfoo' IS DOCUMENT) FROM x; + +-- Mixed functions and Xml expressions testing +-- should not be precalculated +SELECT x_stl2_xml(XMLCONCAT('', x_vlt_xml())) FROM x; + +-- should not be precalculated +SELECT x_stl2_xml( + XMLELEMENT(name foo, xmlattributes('bar' as bar), x_vlt_xml()) +) +FROM x; + +-- should not be precalculated +SELECT x_stl2_xml(XMLFOREST('abc' AS foo, x_vlt_xml() AS bar)) FROM x; + +-- should not be precalculated +SELECT x_stl2_xml(XMLPARSE(DOCUMENT x_vlt_text_xml())) FROM x; + +-- should not be precalculated +SELECT x_stl2_xml(XMLPARSE(CONTENT x_vlt_text_xml_content())) FROM x; + +-- should not be precalculated +SELECT x_stl2_xml(XMLPI(name php, x_vlt_text_xml_instruction_content())) FROM x; + +-- should not be precalculated +SELECT x_stl2_xml(XMLROOT(x_vlt_xml(), version '1.0', standalone yes)) FROM x; + +-- should not be precalculated +SELECT x_stl2_text(XMLSERIALIZE(DOCUMENT x_vlt_xml() AS text)) FROM x; + +-- should not be precalculated +SELECT x_stl2_text(XMLSERIALIZE(CONTENT x_vlt_xml_content() AS text)) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_xml_content() IS DOCUMENT) FROM x; + +SELECT x_stl2_xml(XMLCONCAT('', x_stl_xml())) FROM x; + +SELECT x_stl2_xml( + XMLELEMENT(name foo, xmlattributes('bar' as bar), x_stl_xml()) +) +FROM x; + +SELECT x_stl2_xml(XMLFOREST('abc' AS foo, x_stl_xml() AS bar)) FROM x; + +SELECT x_stl2_xml(XMLPARSE(DOCUMENT x_stl_text_xml())) FROM x; + +SELECT x_stl2_xml(XMLPARSE(CONTENT x_stl_text_xml_content())) FROM x; + +SELECT x_stl2_xml(XMLPI(name php, x_stl_text_xml_instruction_content())) FROM x; + +SELECT x_stl2_xml(XMLROOT(x_stl_xml(), version '1.0', standalone yes)) FROM x; + +SELECT x_stl2_text(XMLSERIALIZE(DOCUMENT x_stl_xml() AS text)) FROM x; + +SELECT x_stl2_text(XMLSERIALIZE(CONTENT x_stl_xml_content() AS text)) FROM x; + +SELECT x_stl2_boolean(x_stl_xml_content() IS DOCUMENT) FROM x; + +-- NullTest expressions testing + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt() IS NULL) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt() IS NOT NULL) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_wxyz() IS NULL) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_wxyz() IS NOT NULL) FROM x; + +SELECT x_stl2_boolean(x_stl() IS NULL) FROM x; +SELECT x_stl2_boolean(x_stl() IS NOT NULL) FROM x; + +SELECT x_stl2_boolean(x_stl_wxyz() IS NULL) FROM x; +SELECT x_stl2_boolean(x_stl_wxyz() IS NOT NULL) FROM x; + +-- BooleanTest expressions testing + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS TRUE) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT TRUE) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS FALSE) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT FALSE) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS UNKNOWN) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT UNKNOWN) FROM x; + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS TRUE) FROM x; +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS NOT TRUE) FROM x; +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS FALSE) FROM x; +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS NOT FALSE) FROM x; +SELECT x_stl2_boolean(x_stl2_boolean(NULL) IS UNKNOWN) FROM x; +SELECT x_stl2_boolean(x_stl2_boolean(NULL) IS NOT UNKNOWN) FROM x; + +-- Tracking functions testing + +SET track_functions TO 'all'; + +-- Simple functions testing +SELECT x_vlt() FROM x; -- should not be precalculated +SELECT x_stl() FROM x; + +-- WHERE clause testing +SELECT x_vlt() FROM x WHERE x_vlt() < x; -- should not be precalculated +SELECT x_stl() FROM x WHERE x_stl() < x; + +-- JOIN/ON clause testing + +-- should not be precalculated +SELECT * FROM x JOIN generate_series(1, 2) y ON x_vlt() < x; + +SELECT * FROM x JOIN generate_series(1, 2) y ON x_stl() < x; + +-- Functions with constant arguments testing +SELECT x_vlt2(1) FROM x; -- should not be precalculated +SELECT x_stl2(1) FROM x; + +-- Nested functions testing +SELECT x_stl2(x_vlt()) FROM x; -- should not be precalculated +SELECT x_imm2(x_vlt()) FROM x; -- should not be precalculated + +SELECT x_stl2(x_stl()) FROM x; +SELECT x_imm2(x_stl()) FROM x; + +-- Strict functions testing +SELECT x_stl2_strict(x_vlt()) FROM x; -- should not be precalculated +SELECT x_imm2_strict(x_vlt()) FROM x; -- should not be precalculated + +SELECT x_stl2_strict(x_stl2_strict(1)) FROM x; +SELECT x_imm2_strict(x_stl2_strict(1)) FROM x; + +-- Strict functions with null arguments testing +SELECT x_stl2_strict(x_stl2(NULL)) FROM x; +SELECT x_imm2_strict(x_stl2(NULL)) FROM x; + +-- Operators testing +SELECT 1 === 2 FROM x; -- should not be precalculated +SELECT 1 ==== 2 FROM x; + +-- Strict operators testing +SELECT x_stl2_boolean(NULL) ==== TRUE FROM x; +SELECT x_stl2_boolean(NULL) ===== TRUE FROM x; + +-- Mixed functions and operators testing +SELECT x_stl2_boolean(1 === 2) FROM x; -- should not be precalculated +SELECT x_stl2_boolean(1 ==== 2) FROM x; + +SELECT x_vlt() ==== 1 FROM x; -- should not be precalculated +SELECT x_stl() ==== 1 FROM x; + +-- Mixed functions and IS (NOT) DISTINCT FROM expressions testing +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +-- should not be precalculated +SELECT equal_booleans_stl_strict( + ('(1)'::my_integer IS DISTINCT FROM '(1)'::my_integer), + ('(1)'::my_integer IS NOT DISTINCT FROM '(1)'::my_integer) +) +FROM x; + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +SELECT equal_booleans_stl_strict( + ('(1)'::my_integer IS DISTINCT FROM '(1)'::my_integer), + ('(1)'::my_integer IS NOT DISTINCT FROM '(1)'::my_integer) +) +FROM x; + +-- should not be precalculated +SELECT (x_vlt_my_integer() IS DISTINCT FROM '(1)'::my_integer) FROM x; + +-- should not be precalculated +SELECT (x_vlt_my_integer() IS NOT DISTINCT FROM '(1)'::my_integer) FROM x; + +SELECT (x_stl_my_integer() IS DISTINCT FROM '(1)'::my_integer) FROM x; +SELECT (x_stl_my_integer() IS NOT DISTINCT FROM '(1)'::my_integer) FROM x; + +-- Mixed functions and NULLIF expressions testing +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +-- should not be precalculated +SELECT equal_my_integer_stl( + NULLIF('(1)'::my_integer, '(2)'::my_integer), + NULLIF('(2)'::my_integer, '(2)'::my_integer) +) +FROM x; + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +SELECT equal_my_integer_stl( + NULLIF('(1)'::my_integer, '(2)'::my_integer), + NULLIF('(2)'::my_integer, '(2)'::my_integer) +) +FROM x; + +-- should not be precalculated +SELECT NULLIF(x_vlt_my_integer(), '(2)'::my_integer) FROM x; + +SELECT NULLIF(x_stl_my_integer(), '(2)'::my_integer) FROM x; + +-- Mixed functions and "scalar op ANY/ALL (array)" / "scalar IN (2 or more +-- values)" expressions testing + +-- should not be precalculated +SELECT x_stl2_boolean(1 === ANY ('{2, 3}')) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(1 === ALL ('{2, 3}')) FROM x; + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_vlt, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +-- should not be precalculated +SELECT x_stl2_boolean( + '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) +) +FROM x; + +SELECT x_stl2_boolean(1 ==== ANY ('{2, 3}')) FROM x; +SELECT x_stl2_boolean(1 ==== ALL ('{2, 3}')) FROM x; + +DROP OPERATOR = (my_integer, my_integer); +CREATE OPERATOR = ( + PROCEDURE = equal_my_integer_stl, + LEFTARG = my_integer, + RIGHTARG = my_integer +); + +SELECT x_stl2_boolean( + '(1)'::my_integer IN ('(2)'::my_integer, '(3)'::my_integer) +) +FROM x; + +SELECT x_vlt() ==== ANY ('{2, 3}') FROM x; -- should not be precalculated +SELECT x_vlt() ==== ALL ('{2, 3}') FROM x; -- should not be precalculated + +SELECT 1 ==== ANY (x_vlt_array_integer()) FROM x; -- should not be precalculated +SELECT 1 ==== ALL (x_vlt_array_integer()) FROM x; -- should not be precalculated + +-- should not be precalculated +SELECT x_vlt_my_integer() IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; + +SELECT x_stl() ==== ANY ('{2, 3}') FROM x; +SELECT x_stl() ==== ALL ('{2, 3}') FROM x; + +SELECT 1 ==== ANY (x_stl_array_integer()) FROM x; +SELECT 1 ==== ALL (x_stl_array_integer()) FROM x; + +SELECT x_stl_my_integer() IN ('(2)'::my_integer, '(3)'::my_integer) FROM x; + +-- Mixed functions and boolean expressions testing + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() AND x_stl2_boolean(TRUE)) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() OR x_stl2_boolean(TRUE)) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(NOT x_vlt_boolean()) FROM x; + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) AND x_stl2_boolean(TRUE)) FROM x; +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) OR x_stl2_boolean(TRUE)) FROM x; +SELECT x_stl2_boolean(NOT x_stl2_boolean(TRUE)) FROM x; + +-- Mixed functions and ARRAY[] expressions testing + +-- should not be precalculated +SELECT x_stl2_array_integer(ARRAY[x_vlt()]) FROM x; + +SELECT x_stl2_array_integer(ARRAY[x_stl()]) FROM x; + +-- Mixed functions and array subscripting operations testing + +-- should not be precalculated +SELECT x_stl2((x_vlt_array_integer())[x_vlt()]) FROM x; + +-- should not be precalculated +SELECT x_stl2((x_vlt_array_integer())[1]) FROM x; + +-- should not be precalculated +SELECT x_stl2_array_integer((x_vlt_array_integer())[:]) FROM x; + +-- should not be precalculated +SELECT x_stl2(('{1, 2}'::integer[])[x_vlt()]) FROM x; + +SELECT x_stl2((x_stl_array_integer())[x_stl()]) FROM x; +SELECT x_stl2((x_stl_array_integer())[1]) FROM x; +SELECT x_stl2_array_integer((x_stl_array_integer())[:]) FROM x; +SELECT x_stl2(('{1, 2}'::integer[])[x_stl()]) FROM x; + +-- Mixed functions and FieldSelect expressions testing +SELECT x_stl2((x_vlt_wxyz()).w) FROM x; -- should not be precalculated +SELECT x_stl2((x_vlt_my_integer()).value) FROM x; -- should not be precalculated + +SELECT x_stl2((x_stl_wxyz()).w) FROM x; +SELECT x_stl2((x_stl_my_integer()).value) FROM x; + +-- Mixed functions and ROW() expressions testing + +-- should not be precalculated +SELECT x_stl2_wxyz((x_vlt(), '{2}', TRUE, 3)) FROM x; + +SELECT x_stl2_wxyz((x_stl(), '{2}', TRUE, 3)) FROM x; + +-- Mixed functions and RelabelType expressions testing +SELECT x_stl2(x_vlt_oid()::integer) FROM x; -- should not be precalculated +SELECT x_stl2(x_stl_oid()::integer) FROM x; + +-- Mixed functions and CoerceViaIO expressions testing + +-- should not be precalculated +SELECT x_stl2(x_vlt_text_integer()::integer) FROM x; + +SELECT x_stl2(x_stl_text_integer()::integer) FROM x; + +-- should not be precalculated +SELECT x_stl2_my_integer(x_vlt_text_my_integer()::my_integer) FROM x; + +SELECT x_stl2_my_integer(x_stl_text_my_integer()::my_integer) FROM x; + +-- Mixed functions and ArrayCoerce expressions testing +-- Binary-coercible types: + +-- should not be precalculated +SELECT x_stl2_array_oid(x_vlt_array_integer()::oid[]) FROM x; + +SELECT x_stl2_array_oid(x_stl_array_integer()::oid[]) FROM x; + +-- Not binary-coercible types: +DROP CAST (my_integer AS integer); +CREATE CAST (my_integer AS integer) + WITH FUNCTION cast_my_integer_as_integer_vlt; + +-- should not be precalculated +SELECT x_stl2_array_integer('{(1), (2)}'::my_integer[]::integer[]) FROM x; + +DROP CAST (my_integer AS integer); +CREATE CAST (my_integer AS integer) + WITH FUNCTION cast_my_integer_as_integer_stl; + +SELECT x_stl2_array_integer('{(1), (2)}'::my_integer[]::integer[]) FROM x; + +DROP CAST (integer AS my_integer); +CREATE CAST (integer AS my_integer) + WITH FUNCTION cast_integer_as_my_integer_stl; + +-- should not be precalculated +SELECT x_vlt_array_integer()::my_integer[] FROM x; + +SELECT x_stl_array_integer()::my_integer[] FROM x; + +-- Mixed functions and ConvertRowtypeExpr testing + +-- should not be precalculated +SELECT x_stl2_wxyz(x_vlt_wxyz_child()::wxyz_child::wxyz) FROM x; + +-- should not be precalculated +SELECT x_stl2_wxyz(x_vlt_wxyz_child2()::wxyz_child2::wxyz) FROM x; + +SELECT x_stl2_wxyz(x_stl_wxyz_child()::wxyz_child::wxyz) FROM x; +SELECT x_stl2_wxyz(x_stl_wxyz_child2()::wxyz_child2::wxyz) FROM x; + +-- Mixed functions and CASE expressions testing + +-- should not be precalculated +SELECT x_stl2(CASE WHEN x_vlt_boolean() THEN x_vlt() ELSE x_vlt() END) FROM x; + +-- should not be precalculated +SELECT x_stl2(CASE x_vlt() WHEN x_vlt() THEN x_vlt() ELSE x_vlt() END) FROM x; + +SELECT x_stl2(CASE WHEN x_stl2_boolean(TRUE) THEN x_stl() ELSE x_stl() END) +FROM x; + +SELECT x_stl2(CASE x_stl() WHEN x_stl() THEN x_stl() ELSE x_stl() END) FROM x; + +-- Mixed functions and RowCompareExpr testing + +-- should not be precalculated +SELECT x_stl2_boolean((x_vlt(), 2) < (1, 3)) FROM x; + +SELECT x_stl2_boolean((x_stl(), 2) < (1, 3)) FROM x; + +-- Mixed functions and COALESCE expressions testing + +-- should not be precalculated +SELECT x_stl2(COALESCE(NULL, x_vlt2(NULL), 2)) FROM x; + +SELECT x_stl2(COALESCE(NULL, x_stl2(NULL), 2)) FROM x; + +-- Mixed functions and GREATEST and LEAST functions testing +SELECT x_stl2(GREATEST(2, x_vlt(), 3)) FROM x; -- should not be precalculated +SELECT x_stl2(LEAST(2, x_vlt(), 3)) FROM x; -- should not be precalculated + +SELECT x_stl2(GREATEST(2, x_stl(), 3)) FROM x; +SELECT x_stl2(LEAST(2, x_stl(), 3)) FROM x; + +-- Mixed functions and Xml expressions testing +-- should not be precalculated +SELECT x_stl2_xml(XMLCONCAT('', x_vlt_xml())) FROM x; + +-- should not be precalculated +SELECT x_stl2_xml( + XMLELEMENT(name foo, xmlattributes('bar' as bar), x_vlt_xml()) +) +FROM x; + +-- should not be precalculated +SELECT x_stl2_xml(XMLFOREST('abc' AS foo, x_vlt_xml() AS bar)) FROM x; + +-- should not be precalculated +SELECT x_stl2_xml(XMLPARSE(DOCUMENT x_vlt_text_xml())) FROM x; + +-- should not be precalculated +SELECT x_stl2_xml(XMLPARSE(CONTENT x_vlt_text_xml_content())) FROM x; + +-- should not be precalculated +SELECT x_stl2_xml(XMLPI(name php, x_vlt_text_xml_instruction_content())) FROM x; + +-- should not be precalculated +SELECT x_stl2_xml(XMLROOT(x_vlt_xml(), version '1.0', standalone yes)) FROM x; + +-- should not be precalculated +SELECT x_stl2_text(XMLSERIALIZE(DOCUMENT x_vlt_xml() AS text)) FROM x; + +-- should not be precalculated +SELECT x_stl2_text(XMLSERIALIZE(CONTENT x_vlt_xml_content() AS text)) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_xml_content() IS DOCUMENT) FROM x; + +SELECT x_stl2_xml(XMLCONCAT('', x_stl_xml())) FROM x; + +SELECT x_stl2_xml( + XMLELEMENT(name foo, xmlattributes('bar' as bar), x_stl_xml()) +) +FROM x; + +SELECT x_stl2_xml(XMLFOREST('abc' AS foo, x_stl_xml() AS bar)) FROM x; + +SELECT x_stl2_xml(XMLPARSE(DOCUMENT x_stl_text_xml())) FROM x; + +SELECT x_stl2_xml(XMLPARSE(CONTENT x_stl_text_xml_content())) FROM x; + +SELECT x_stl2_xml(XMLPI(name php, x_stl_text_xml_instruction_content())) FROM x; + +SELECT x_stl2_xml(XMLROOT(x_stl_xml(), version '1.0', standalone yes)) FROM x; + +SELECT x_stl2_text(XMLSERIALIZE(DOCUMENT x_stl_xml() AS text)) FROM x; + +SELECT x_stl2_text(XMLSERIALIZE(CONTENT x_stl_xml_content() AS text)) FROM x; + +SELECT x_stl2_boolean(x_stl_xml_content() IS DOCUMENT) FROM x; + +-- Mixed functions and NullTest expressions testing + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt() IS NULL) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt() IS NOT NULL) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_wxyz() IS NULL) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_wxyz() IS NOT NULL) FROM x; + +SELECT x_stl2_boolean(x_stl() IS NULL) FROM x; +SELECT x_stl2_boolean(x_stl() IS NOT NULL) FROM x; + +SELECT x_stl2_boolean(x_stl_wxyz() IS NULL) FROM x; +SELECT x_stl2_boolean(x_stl_wxyz() IS NOT NULL) FROM x; + +-- Mixed functions and BooleanTest expressions testing + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS TRUE) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT TRUE) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS FALSE) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT FALSE) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS UNKNOWN) FROM x; + +-- should not be precalculated +SELECT x_stl2_boolean(x_vlt_boolean() IS NOT UNKNOWN) FROM x; + +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS TRUE) FROM x; +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS NOT TRUE) FROM x; +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS FALSE) FROM x; +SELECT x_stl2_boolean(x_stl2_boolean(TRUE) IS NOT FALSE) FROM x; +SELECT x_stl2_boolean(x_stl2_boolean(NULL) IS UNKNOWN) FROM x; +SELECT x_stl2_boolean(x_stl2_boolean(NULL) IS NOT UNKNOWN) FROM x; + +SET track_functions TO DEFAULT; + +-- ROW() expressions with dropped columns testing + +ALTER TABLE wxyz DROP COLUMN z; + +-- Update some functions +CREATE OR REPLACE FUNCTION public.x_stl2_wxyz ( + wxyz +) +RETURNS wxyz STABLE AS +$body$ +BEGIN + RAISE NOTICE 's2 wxyz'; + RETURN $1; +END; +$body$ +LANGUAGE 'plpgsql'; + +-- ROW() expressions testing +SELECT x_stl2_wxyz((1, '{2}', TRUE)) FROM x; +SELECT x_stl2_wxyz(ROW(1, '{2}', TRUE)) FROM x; +SELECT x_stl2_wxyz((1, '{2}', TRUE)::wxyz) FROM x; + +-- Mixed functions and ROW() expressions testing + +-- should not be precalculated +SELECT x_stl2_wxyz((x_vlt(), '{2}', TRUE)) FROM x; + +SELECT x_stl2_wxyz((x_stl(), '{2}', TRUE)) FROM x; + +-- PL/pgSQL Simple expressions +-- Make sure precalculated stable functions can't be simple expressions: these +-- expressions are only initialized once per transaction and then executed +-- multiple times. + +BEGIN; +SELECT simple(); +INSERT INTO x VALUES (5); +SELECT simple(); +ROLLBACK; + +-- Drop tables for testing + +DROP TABLE x; + +DROP FUNCTION x_vlt_wxyz, x_vlt_wxyz_child, x_vlt_wxyz_child2; +DROP FUNCTION x_stl_wxyz, x_stl_wxyz_child, x_stl_wxyz_child2, x_stl2_wxyz; +DROP TABLE wxyz, wxyz_child, wxyz_child2; + +DROP FUNCTION x_stl2_no_columns; +DROP TABLE no_columns, no_columns_child, no_columns_child2; -- 2.7.4