summaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
authorTom Lane2012-03-23 21:29:57 +0000
committerTom Lane2012-03-23 21:29:57 +0000
commit0339047bc93147c1c6f78f867ae6b0c215406235 (patch)
tree116a4cd10a9eb1b0b6beb4cf871bc126c504572a /src/backend/optimizer
parente08b4101e1daa2f4e6644330918177a10cac0aab (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.c115
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);