diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2019-02-09 18:08:48 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2019-02-09 18:08:48 -0500 |
commit | 1fb57af92069ee104c09e2016af9e0e620681be3 (patch) | |
tree | 8bb9db8431972a220f6bd6f8b13e663049172583 /src/backend/utils/adt/timestamp.c | |
parent | 1a8d5afb0dfc5d0dcc6eda0656a34cb1f0cf0bdf (diff) | |
download | postgresql-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/timestamp.c')
-rw-r--r-- | src/backend/utils/adt/timestamp.c | 138 |
1 files changed, 68 insertions, 70 deletions
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index 7befb6a7e28..e0ef2f78616 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -29,6 +29,7 @@ #include "miscadmin.h" #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" +#include "nodes/supportnodes.h" #include "parser/scansup.h" #include "utils/array.h" #include "utils/builtins.h" @@ -297,15 +298,26 @@ timestamptypmodout(PG_FUNCTION_ARGS) } -/* timestamp_transform() - * Flatten calls to timestamp_scale() and timestamptz_scale() that solely - * represent increases in allowed precision. +/* + * timestamp_support() + * + * Planner support function for the timestamp_scale() and timestamptz_scale() + * length coercion functions (we need not distinguish them here). */ Datum -timestamp_transform(PG_FUNCTION_ARGS) +timestamp_support(PG_FUNCTION_ARGS) { - PG_RETURN_POINTER(TemporalTransform(MAX_TIMESTAMP_PRECISION, - (Node *) PG_GETARG_POINTER(0))); + Node *rawreq = (Node *) PG_GETARG_POINTER(0); + Node *ret = NULL; + + if (IsA(rawreq, SupportRequestSimplify)) + { + SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq; + + ret = TemporalSimplify(MAX_TIMESTAMP_PRECISION, (Node *) req->fcall); + } + + PG_RETURN_POINTER(ret); } /* timestamp_scale() @@ -1235,59 +1247,69 @@ intervaltypmodleastfield(int32 typmod) } -/* interval_transform() +/* + * interval_support() + * + * Planner support function for interval_scale(). + * * Flatten superfluous calls to interval_scale(). The interval typmod is * complex to permit accepting and regurgitating all SQL standard variations. * For truncation purposes, it boils down to a single, simple granularity. */ Datum -interval_transform(PG_FUNCTION_ARGS) +interval_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 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue); - bool noop; + typmod = (Node *) lsecond(expr->args); - if (new_typmod < 0) - noop = true; - else + if (IsA(typmod, Const) &&!((Const *) typmod)->constisnull) { - int32 old_typmod = exprTypmod(source); - int old_least_field; - int new_least_field; - int old_precis; - int new_precis; - - old_least_field = intervaltypmodleastfield(old_typmod); - new_least_field = intervaltypmodleastfield(new_typmod); - if (old_typmod < 0) - old_precis = INTERVAL_FULL_PRECISION; + Node *source = (Node *) linitial(expr->args); + int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue); + bool noop; + + if (new_typmod < 0) + noop = true; else - old_precis = INTERVAL_PRECISION(old_typmod); - new_precis = INTERVAL_PRECISION(new_typmod); - - /* - * Cast is a no-op if least field stays the same or decreases - * while precision stays the same or increases. But precision, - * which is to say, sub-second precision, only affects ranges that - * include SECOND. - */ - noop = (new_least_field <= old_least_field) && - (old_least_field > 0 /* SECOND */ || - new_precis >= MAX_INTERVAL_PRECISION || - new_precis >= old_precis); + { + int32 old_typmod = exprTypmod(source); + int old_least_field; + int new_least_field; + int old_precis; + int new_precis; + + old_least_field = intervaltypmodleastfield(old_typmod); + new_least_field = intervaltypmodleastfield(new_typmod); + if (old_typmod < 0) + old_precis = INTERVAL_FULL_PRECISION; + else + old_precis = INTERVAL_PRECISION(old_typmod); + new_precis = INTERVAL_PRECISION(new_typmod); + + /* + * Cast is a no-op if least field stays the same or decreases + * while precision stays the same or increases. But + * precision, which is to say, sub-second precision, only + * affects ranges that include SECOND. + */ + noop = (new_least_field <= old_least_field) && + (old_least_field > 0 /* SECOND */ || + new_precis >= MAX_INTERVAL_PRECISION || + new_precis >= old_precis); + } + if (noop) + ret = relabel_to_typmod(source, new_typmod); } - if (noop) - ret = relabel_to_typmod(source, new_typmod); } PG_RETURN_POINTER(ret); @@ -1359,7 +1381,7 @@ AdjustIntervalForTypmod(Interval *interval, int32 typmod) * can't do it consistently. (We cannot enforce a range limit on the * highest expected field, since we do not have any equivalent of * SQL's <interval leading field precision>.) If we ever decide to - * revisit this, interval_transform will likely require adjusting. + * revisit this, interval_support will likely require adjusting. * * Note: before PG 8.4 we interpreted a limited set of fields as * actually causing a "modulo" operation on a given value, potentially @@ -5020,18 +5042,6 @@ interval_part(PG_FUNCTION_ARGS) } -/* timestamp_zone_transform() - * The original optimization here caused problems by relabeling Vars that - * could be matched to index entries. It might be possible to resurrect it - * at some point by teaching the planner to be less cavalier with RelabelType - * nodes, but that will take careful analysis. - */ -Datum -timestamp_zone_transform(PG_FUNCTION_ARGS) -{ - PG_RETURN_POINTER(NULL); -} - /* timestamp_zone() * Encode timestamp type with specified time zone. * This function is just timestamp2timestamptz() except instead of @@ -5125,18 +5135,6 @@ timestamp_zone(PG_FUNCTION_ARGS) PG_RETURN_TIMESTAMPTZ(result); } -/* timestamp_izone_transform() - * The original optimization here caused problems by relabeling Vars that - * could be matched to index entries. It might be possible to resurrect it - * at some point by teaching the planner to be less cavalier with RelabelType - * nodes, but that will take careful analysis. - */ -Datum -timestamp_izone_transform(PG_FUNCTION_ARGS) -{ - PG_RETURN_POINTER(NULL); -} - /* timestamp_izone() * Encode timestamp type with specified time interval as time zone. */ |