aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/numeric.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2019-02-09 18:08:48 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2019-02-09 18:08:48 -0500
commit1fb57af92069ee104c09e2016af9e0e620681be3 (patch)
tree8bb9db8431972a220f6bd6f8b13e663049172583 /src/backend/utils/adt/numeric.c
parent1a8d5afb0dfc5d0dcc6eda0656a34cb1f0cf0bdf (diff)
downloadpostgresql-1fb57af92069ee104c09e2016af9e0e620681be3.tar.gz
postgresql-1fb57af92069ee104c09e2016af9e0e620681be3.zip
Create the infrastructure for planner support functions.
Rename/repurpose pg_proc.protransform as "prosupport". The idea is still that it names an internal function that provides knowledge to the planner about the behavior of the function it's attached to; but redesign the API specification so that it's not limited to doing just one thing, but can support an extensible set of requests. The original purpose of simplifying a function call is handled by the first request type to be invented, SupportRequestSimplify. Adjust all the existing transform functions to handle this API, and rename them fron "xxx_transform" to "xxx_support" to reflect the potential generalization of what they do. (Since we never previously provided any way for extensions to add transform functions, this change doesn't create an API break for them.) Also add DDL and pg_dump support for attaching a support function to a user-defined function. Unfortunately, DDL access has to be restricted to superusers, at least for now; but seeing that support functions will pretty much have to be written in C, that limitation is just theoretical. (This support is untested in this patch, but a follow-on patch will add cases that exercise it.) Discussion: https://postgr.es/m/15193.1548028093@sss.pgh.pa.us
Diffstat (limited to 'src/backend/utils/adt/numeric.c')
-rw-r--r--src/backend/utils/adt/numeric.c69
1 files changed, 39 insertions, 30 deletions
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 45cd1a0664f..1c9deebc1dd 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -34,6 +34,7 @@
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
+#include "nodes/supportnodes.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/float.h"
@@ -890,45 +891,53 @@ numeric_send(PG_FUNCTION_ARGS)
/*
- * numeric_transform() -
+ * numeric_support()
*
- * Flatten calls to numeric's length coercion function that solely represent
- * increases in allowable precision. Scale changes mutate every datum, so
- * they are unoptimizable. Some values, e.g. 1E-1001, can only fit into an
- * unconstrained numeric, so a change from an unconstrained numeric to any
- * constrained numeric is also unoptimizable.
+ * Planner support function for the numeric() length coercion function.
+ *
+ * Flatten calls that solely represent increases in allowable precision.
+ * Scale changes mutate every datum, so they are unoptimizable. Some values,
+ * e.g. 1E-1001, can only fit into an unconstrained numeric, so a change from
+ * an unconstrained numeric to any constrained numeric is also unoptimizable.
*/
Datum
-numeric_transform(PG_FUNCTION_ARGS)
+numeric_support(PG_FUNCTION_ARGS)
{
- FuncExpr *expr = castNode(FuncExpr, PG_GETARG_POINTER(0));
+ Node *rawreq = (Node *) PG_GETARG_POINTER(0);
Node *ret = NULL;
- Node *typmod;
- Assert(list_length(expr->args) >= 2);
+ if (IsA(rawreq, SupportRequestSimplify))
+ {
+ SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
+ FuncExpr *expr = req->fcall;
+ Node *typmod;
- typmod = (Node *) lsecond(expr->args);
+ Assert(list_length(expr->args) >= 2);
- if (IsA(typmod, Const) &&!((Const *) typmod)->constisnull)
- {
- Node *source = (Node *) linitial(expr->args);
- int32 old_typmod = exprTypmod(source);
- int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
- int32 old_scale = (old_typmod - VARHDRSZ) & 0xffff;
- int32 new_scale = (new_typmod - VARHDRSZ) & 0xffff;
- int32 old_precision = (old_typmod - VARHDRSZ) >> 16 & 0xffff;
- int32 new_precision = (new_typmod - VARHDRSZ) >> 16 & 0xffff;
+ typmod = (Node *) lsecond(expr->args);
- /*
- * If new_typmod < VARHDRSZ, the destination is unconstrained; that's
- * always OK. If old_typmod >= VARHDRSZ, the source is constrained,
- * and we're OK if the scale is unchanged and the precision is not
- * decreasing. See further notes in function header comment.
- */
- if (new_typmod < (int32) VARHDRSZ ||
- (old_typmod >= (int32) VARHDRSZ &&
- new_scale == old_scale && new_precision >= old_precision))
- ret = relabel_to_typmod(source, new_typmod);
+ if (IsA(typmod, Const) &&!((Const *) typmod)->constisnull)
+ {
+ Node *source = (Node *) linitial(expr->args);
+ int32 old_typmod = exprTypmod(source);
+ int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
+ int32 old_scale = (old_typmod - VARHDRSZ) & 0xffff;
+ int32 new_scale = (new_typmod - VARHDRSZ) & 0xffff;
+ int32 old_precision = (old_typmod - VARHDRSZ) >> 16 & 0xffff;
+ int32 new_precision = (new_typmod - VARHDRSZ) >> 16 & 0xffff;
+
+ /*
+ * If new_typmod < VARHDRSZ, the destination is unconstrained;
+ * that's always OK. If old_typmod >= VARHDRSZ, the source is
+ * constrained, and we're OK if the scale is unchanged and the
+ * precision is not decreasing. See further notes in function
+ * header comment.
+ */
+ if (new_typmod < (int32) VARHDRSZ ||
+ (old_typmod >= (int32) VARHDRSZ &&
+ new_scale == old_scale && new_precision >= old_precision))
+ ret = relabel_to_typmod(source, new_typmod);
+ }
}
PG_RETURN_POINTER(ret);