diff options
| author | Tom Lane | 2012-03-23 21:29:57 +0000 |
|---|---|---|
| committer | Tom Lane | 2012-03-23 21:29:57 +0000 |
| commit | 0339047bc93147c1c6f78f867ae6b0c215406235 (patch) | |
| tree | 116a4cd10a9eb1b0b6beb4cf871bc126c504572a /src/backend/optimizer | |
| parent | e08b4101e1daa2f4e6644330918177a10cac0aab (diff) | |
Code review for protransform patches.
Fix loss of previous expression-simplification work when a transform
function fires: we must not simply revert to untransformed input tree.
Instead build a dummy FuncExpr node to pass to the transform function.
This has the additional advantage of providing a simpler, more uniform
API for transform functions.
Move documentation to a somewhat less buried spot, relocate some
poorly-placed code, be more wary of null constants and invalid typmod
values, add an opr_sanity check on protransform function signatures,
and some other minor cosmetic adjustments.
Note: although this patch touches pg_proc.h, no need for catversion
bump, because the changes are cosmetic and don't actually change the
intended catalog contents.
Diffstat (limited to 'src/backend/optimizer')
| -rw-r--r-- | src/backend/optimizer/util/clauses.c | 115 |
1 files changed, 50 insertions, 65 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index b14ae2e367..117c9c0e45 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -107,11 +107,11 @@ static List *simplify_and_arguments(List *args, eval_const_expressions_context *context, bool *haveNull, bool *forceFalse); static Node *simplify_boolean_equality(Oid opno, List *args); -static Expr *simplify_function(Expr *oldexpr, Oid funcid, - Oid result_type, int32 result_typmod, Oid result_collid, - Oid input_collid, List **args, +static Expr *simplify_function(Oid funcid, + Oid result_type, int32 result_typmod, + Oid result_collid, Oid input_collid, List **args, bool has_named_args, - bool allow_inline, + bool allow_non_const, eval_const_expressions_context *context); static List *reorder_function_arguments(List *args, Oid result_type, HeapTuple func_tuple, @@ -2332,8 +2332,7 @@ eval_const_expressions_mutator(Node *node, * length coercion; we want to preserve the typmod in the * eventual Const if so. */ - simple = simplify_function((Expr *) expr, - expr->funcid, + simple = simplify_function(expr->funcid, expr->funcresulttype, exprTypmod(node), expr->funccollid, @@ -2389,8 +2388,7 @@ eval_const_expressions_mutator(Node *node, * Code for op/func reduction is pretty bulky, so split it out * as a separate function. */ - simple = simplify_function((Expr *) expr, - expr->opfuncid, + simple = simplify_function(expr->opfuncid, expr->opresulttype, -1, expr->opcollid, expr->inputcollid, @@ -2491,8 +2489,7 @@ eval_const_expressions_mutator(Node *node, * Code for op/func reduction is pretty bulky, so split it * out as a separate function. */ - simple = simplify_function((Expr *) expr, - expr->opfuncid, + simple = simplify_function(expr->opfuncid, expr->opresulttype, -1, expr->opcollid, expr->inputcollid, @@ -2698,8 +2695,7 @@ eval_const_expressions_mutator(Node *node, getTypeInputInfo(expr->resulttype, &infunc, &intypioparam); - simple = simplify_function(NULL, - outfunc, + simple = simplify_function(outfunc, CSTRINGOID, -1, InvalidOid, InvalidOid, @@ -2728,8 +2724,7 @@ eval_const_expressions_mutator(Node *node, false, true)); - simple = simplify_function(NULL, - infunc, + simple = simplify_function(infunc, expr->resulttype, -1, expr->resultcollid, InvalidOid, @@ -3581,15 +3576,11 @@ simplify_boolean_equality(Oid opno, List *args) * Subroutine for eval_const_expressions: try to simplify a function call * (which might originally have been an operator; we don't care) * - * Inputs are the original expression (can be NULL), 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 - * pre-simplified argument list, and some flags; also the context data for - * eval_const_expressions. In common cases, several of the arguments could be - * derived from the original expression. Sending them separately avoids - * duplicating NodeTag-specific knowledge, and it's necessary for CoerceViaIO. - * A NULL original expression disables use of transform functions while - * retaining all other behaviors. + * 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 pre-simplified argument list, 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. @@ -3601,28 +3592,32 @@ simplify_boolean_equality(Oid opno, List *args) * pass-by-reference, and it may get modified even if simplification fails. */ static Expr * -simplify_function(Expr *oldexpr, Oid funcid, - Oid result_type, int32 result_typmod, Oid result_collid, - Oid input_collid, List **args, +simplify_function(Oid funcid, Oid result_type, int32 result_typmod, + Oid result_collid, Oid input_collid, List **args, bool has_named_args, - bool allow_inline, + bool allow_non_const, eval_const_expressions_context *context) { HeapTuple func_tuple; + Form_pg_proc func_form; Expr *newexpr; - Oid transform; /* * We have three 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 * definition (which only works for simple SQL-language functions, but - * that is a common case). Each needs access to the function's pg_proc - * tuple, so fetch it just once. + * that is a common case). 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. */ func_tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(func_tuple)) elog(ERROR, "cache lookup failed for function %u", funcid); + func_form = (Form_pg_proc) GETSTRUCT(func_tuple); /* * While we have the tuple, reorder named arguments and add default @@ -3631,48 +3626,38 @@ simplify_function(Expr *oldexpr, Oid funcid, if (has_named_args) *args = reorder_function_arguments(*args, result_type, func_tuple, context); - else if (((Form_pg_proc) GETSTRUCT(func_tuple))->pronargs > list_length(*args)) + else if (func_form->pronargs > list_length(*args)) *args = add_function_defaults(*args, result_type, func_tuple, context); newexpr = evaluate_function(funcid, result_type, result_typmod, result_collid, input_collid, *args, func_tuple, context); - /* - * Some functions calls can be simplified at plan time based on properties - * specific to the function. For example, "varchar(s::varchar(4), 8, - * true)" simplifies to "s::varchar(4)", and "int4mul(n, 1)" could - * simplify to "n". To define such function-specific optimizations, write - * a "transform function" and store its OID in the pg_proc.protransform of - * the primary function. Give each transform function the signature - * "protransform(internal) RETURNS internal". The argument, internally an - * Expr *, is the node representing a call to the primary function. If - * the transform function's study of that node proves that a simplified - * Expr substitutes for all possible concrete calls represented thereby, - * return that simplified Expr. Otherwise, return the NULL pointer. - * - * Currently, the specific Expr nodetag can be FuncExpr, OpExpr or - * DistinctExpr. This list may change in the future. The function should - * check the nodetag and return the NULL pointer for unexpected inputs. - * - * We make no guarantee that PostgreSQL will never call the primary - * function in cases that the transform function would simplify. Ensure - * rigorous equivalence between the simplified expression and an actual - * call to the primary function. - * - * Currently, this facility is undocumented and not exposed to users at - * the SQL level. Core length coercion casts use it to avoid calls - * guaranteed to return their input unchanged. This in turn allows ALTER - * TABLE ALTER TYPE to avoid rewriting tables for some typmod changes. In - * the future, this facility may find other applications, like simplifying - * x*0, x*1, and x+0. - */ - transform = ((Form_pg_proc) GETSTRUCT(func_tuple))->protransform; - if (!newexpr && OidIsValid(transform) && oldexpr) - newexpr = (Expr *) DatumGetPointer(OidFunctionCall1(transform, - PointerGetDatum(oldexpr))); + if (!newexpr && allow_non_const && OidIsValid(func_form->protransform)) + { + /* + * Build a dummy FuncExpr node containing the simplified arg list. We + * use this approach to present a uniform interface to the transform + * function regardless of how the function is actually being invoked. + */ + FuncExpr fexpr; + + fexpr.xpr.type = T_FuncExpr; + fexpr.funcid = funcid; + fexpr.funcresulttype = result_type; + fexpr.funcretset = func_form->proretset; + fexpr.funcformat = COERCE_DONTCARE; + fexpr.funccollid = result_collid; + fexpr.inputcollid = input_collid; + fexpr.args = *args; + fexpr.location = -1; + + newexpr = (Expr *) + DatumGetPointer(OidFunctionCall1(func_form->protransform, + PointerGetDatum(&fexpr))); + } - if (!newexpr && allow_inline) + if (!newexpr && allow_non_const) newexpr = inline_function(funcid, result_type, result_collid, input_collid, *args, func_tuple, context); |
