v1-0001-change-protransform-API-apply.patch
text/x-diff
Filename: v1-0001-change-protransform-API-apply.patch
Type: text/x-diff
Part: 1
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v1-0001
| File | + | − |
|---|---|---|
| doc/src/sgml/catalogs.sgml | 3 | 3 |
| doc/src/sgml/xfunc.sgml | 86 | 34 |
| doc/src/sgml/xoper.sgml | 12 | 0 |
| src/backend/catalog/pg_proc.c | 1 | 1 |
| src/backend/optimizer/util/clauses.c | 17 | 6 |
| src/backend/utils/adt/date.c | 17 | 6 |
| src/backend/utils/adt/datetime.c | 12 | 5 |
| src/backend/utils/adt/numeric.c | 39 | 30 |
| src/backend/utils/adt/timestamp.c | 68 | 70 |
| src/backend/utils/adt/varbit.c | 29 | 19 |
| src/backend/utils/adt/varchar.c | 29 | 19 |
| src/bin/pg_dump/t/002_pg_dump.pl | 4 | 4 |
| src/include/catalog/pg_proc.dat | 35 | 46 |
| src/include/catalog/pg_proc.h | 2 | 2 |
| src/include/nodes/nodes.h | 2 | 1 |
| src/include/nodes/supportnodes.h | 70 | 0 |
| src/include/utils/datetime.h | 1 | 1 |
| src/test/modules/test_ddl_deparse/expected/create_transform.out | 1 | 1 |
| src/test/modules/test_ddl_deparse/sql/create_transform.sql | 1 | 1 |
| src/test/regress/expected/object_address.out | 1 | 1 |
| src/test/regress/expected/oidjoins.out | 5 | 5 |
| src/test/regress/expected/opr_sanity.out | 2 | 2 |
| src/test/regress/sql/object_address.sql | 1 | 1 |
| src/test/regress/sql/oidjoins.sql | 3 | 3 |
| src/test/regress/sql/opr_sanity.sql | 2 | 2 |
| src/tools/findoidjoins/README | 1 | 1 |
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index af4d062..6dd0700 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -5146,11 +5146,11 @@ SCRAM-SHA-256$<replaceable><iteration count></replaceable>:<replaceable>&l
</row>
<row>
- <entry><structfield>protransform</structfield></entry>
+ <entry><structfield>prosupport</structfield></entry>
<entry><type>regproc</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
- <entry>Calls to this function can be simplified by this other function
- (see <xref linkend="xfunc-transform-functions"/>)</entry>
+ <entry>Optional planner support function for this function
+ (see <xref linkend="xfunc-optimization"/>)</entry>
</row>
<row>
diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index e18272c..d70aa6e 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -3241,40 +3241,6 @@ CREATE FUNCTION make_array(anyelement) RETURNS anyarray
</para>
</sect2>
- <sect2 id="xfunc-transform-functions">
- <title>Transform Functions</title>
-
- <para>
- Some function calls can be simplified during planning based on
- properties specific to the function. For example,
- <literal>int4mul(n, 1)</literal> could be simplified to just <literal>n</literal>.
- To define such function-specific optimizations, write a
- <firstterm>transform function</firstterm> and place its OID in the
- <structfield>protransform</structfield> field of the primary function's
- <structname>pg_proc</structname> entry. The transform function must have the SQL
- signature <literal>protransform(internal) RETURNS internal</literal>. The
- argument, actually <type>FuncExpr *</type>, is a dummy node representing a
- call to the primary function. If the transform function's study of the
- expression tree proves that a simplified expression tree can substitute
- for all possible concrete calls represented thereby, build and return
- that simplified expression. Otherwise, return a <literal>NULL</literal>
- pointer (<emphasis>not</emphasis> a SQL null).
- </para>
-
- <para>
- We make no guarantee that <productname>PostgreSQL</productname> will never call the
- primary function in cases that the transform function could simplify.
- Ensure rigorous equivalence between the simplified expression and an
- actual call to the primary function.
- </para>
-
- <para>
- Currently, this facility is not exposed to users at the SQL level
- because of security concerns, so it is only practical to use for
- optimizing built-in functions.
- </para>
- </sect2>
-
<sect2>
<title>Shared Memory and LWLocks</title>
@@ -3388,3 +3354,89 @@ if (!ptr)
</sect2>
</sect1>
+
+ <sect1 id="xfunc-optimization">
+ <title>Function Optimization Information</title>
+
+ <indexterm zone="xfunc-optimization">
+ <primary>optimization information</primary>
+ <secondary>for functions</secondary>
+ </indexterm>
+
+ <para>
+ By default, a function is just a <quote>black box</quote> that the
+ database system knows very little about the behavior of. However,
+ that means that queries using the function may be executed much less
+ efficiently than they could be. It is possible to supply additional
+ knowledge that helps the planner optimize function calls.
+ </para>
+
+ <para>
+ Some basic facts can be supplied by declarative annotations provided in
+ the <xref linkend="sql-createfunction"/> command. Most important of
+ these is the function's <link linkend="xfunc-volatility">volatility
+ category</link> (<literal>IMMUTABLE</literal>, <literal>STABLE</literal>,
+ or <literal>VOLATILE</literal>); one should always be careful to
+ specify this correctly when defining a function.
+ The parallel safety property (<literal>PARALLEL
+ UNSAFE</literal>, <literal>PARALLEL RESTRICTED</literal>, or
+ <literal>PARALLEL SAFE</literal>) must also be specified if you hope
+ to use the function in parallelized queries.
+ It can also be useful to specify the function's estimated execution
+ cost, and/or the number of rows a set-returning function is estimated
+ to return. However, the declarative way of specifying those two
+ facts only allows specifying a constant value, which is often
+ inadequate.
+ </para>
+
+ <para>
+ It is also possible to attach a <firstterm>planner support
+ function</firstterm> to a SQL-callable function (called
+ its <firstterm>target function</firstterm>), and thereby provide
+ knowledge about the target function that is too complex to be
+ represented declaratively. Planner support functions have to be
+ written in C (although their target functions might not be), so this is
+ an advanced feature that relatively few people will use.
+ </para>
+
+ <para>
+ A planner support function must have the SQL signature
+<programlisting>
+supportfn(internal) returns internal
+</programlisting>
+ It is attached to its target function by specifying
+ the <literal>SUPPORT</literal> clause when creating the target function.
+ </para>
+
+ <para>
+ The details of the API for planner support functions can be found in
+ file <filename>src/include/nodes/supportnodes.h</filename> in the
+ <productname>PostgreSQL</productname> source code. Here we provide
+ just an overview of what planner support functions can do.
+ The set of possible requests to a support function is extensible,
+ so more things might be possible in future versions.
+ </para>
+
+ <para>
+ Some function calls can be simplified during planning based on
+ properties specific to the function. For example,
+ <literal>int4mul(n, 1)</literal> could be simplified to
+ just <literal>n</literal>. This type of transformation can be
+ performed by a planner support function, by having it implement
+ the <literal>SupportRequestSimplify</literal> request type.
+ The support function will be called for each instance of its target
+ function found in a query parse tree. If it finds that the particular
+ call can be simplified into some other form, it can build and return a
+ parse tree representing that expression. This will automatically work
+ for operators based on the function, too — in the example just
+ given, <literal>n * 1</literal> would also be simplified to
+ <literal>n</literal>.
+ (But note that this is just an example; this particular
+ optimization is not actually performed by
+ standard <productname>PostgreSQL</productname>.)
+ We make no guarantee that <productname>PostgreSQL</productname> will
+ never call the target function in cases that the support function could
+ simplify. Ensure rigorous equivalence between the simplified
+ expression and an actual execution of the target function.
+ </para>
+ </sect1>
diff --git a/doc/src/sgml/xoper.sgml b/doc/src/sgml/xoper.sgml
index 2f5560a..260e43c 100644
--- a/doc/src/sgml/xoper.sgml
+++ b/doc/src/sgml/xoper.sgml
@@ -78,6 +78,11 @@ SELECT (a + b) AS c FROM test_complex;
<sect1 id="xoper-optimization">
<title>Operator Optimization Information</title>
+ <indexterm zone="xoper-optimization">
+ <primary>optimization information</primary>
+ <secondary>for operators</secondary>
+ </indexterm>
+
<para>
A <productname>PostgreSQL</productname> operator definition can include
several optional clauses that tell the system useful things about how
@@ -97,6 +102,13 @@ SELECT (a + b) AS c FROM test_complex;
the ones that release &version; understands.
</para>
+ <para>
+ It is also possible to attach a planner support function to the function
+ that underlies an operator, providing another way of telling the system
+ about the behavior of the operator.
+ See <xref linkend="xfunc-optimization"/> for more information.
+ </para>
+
<sect2>
<title><literal>COMMUTATOR</literal></title>
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index db78061..3a86f1e 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -319,7 +319,7 @@ ProcedureCreate(const char *procedureName,
values[Anum_pg_proc_procost - 1] = Float4GetDatum(procost);
values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows);
values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType);
- values[Anum_pg_proc_protransform - 1] = ObjectIdGetDatum(InvalidOid);
+ values[Anum_pg_proc_prosupport - 1] = ObjectIdGetDatum(InvalidOid);
values[Anum_pg_proc_prokind - 1] = CharGetDatum(prokind);
values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer);
values[Anum_pg_proc_proleakproof - 1] = BoolGetDatum(isLeakProof);
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index f0ef102..061a855 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -32,6 +32,7 @@
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
+#include "nodes/supportnodes.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/planmain.h"
@@ -4269,13 +4270,16 @@ 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_non_const && OidIsValid(func_form->prosupport))
{
/*
- * 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.
+ * Build a SupportRequestSimplify node to pass to the support
+ * function, pointing to a dummy FuncExpr node containing the
+ * simplified arg list. We use this approach to present a uniform
+ * interface to the support function regardless of how the target
+ * function is actually being invoked.
*/
+ SupportRequestSimplify req;
FuncExpr fexpr;
fexpr.xpr.type = T_FuncExpr;
@@ -4289,9 +4293,16 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
fexpr.args = args;
fexpr.location = -1;
+ req.type = T_SupportRequestSimplify;
+ req.root = context->root;
+ req.fcall = &fexpr;
+
newexpr = (Expr *)
- DatumGetPointer(OidFunctionCall1(func_form->protransform,
- PointerGetDatum(&fexpr)));
+ DatumGetPointer(OidFunctionCall1(func_form->prosupport,
+ PointerGetDatum(&req)));
+
+ /* catch a possible API misunderstanding */
+ Assert(newexpr != (Expr *) &fexpr);
}
if (!newexpr && allow_non_const)
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index 3810e4a..cf5a1c6 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -24,6 +24,7 @@
#include "access/xact.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
+#include "nodes/supportnodes.h"
#include "parser/scansup.h"
#include "utils/array.h"
#include "utils/builtins.h"
@@ -1341,15 +1342,25 @@ make_time(PG_FUNCTION_ARGS)
}
-/* time_transform()
- * Flatten calls to time_scale() and timetz_scale() that solely represent
- * increases in allowed precision.
+/* time_support()
+ *
+ * Planner support function for the time_scale() and timetz_scale()
+ * length coercion functions (we need not distinguish them here).
*/
Datum
-time_transform(PG_FUNCTION_ARGS)
+time_support(PG_FUNCTION_ARGS)
{
- PG_RETURN_POINTER(TemporalTransform(MAX_TIME_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_TIME_PRECISION, (Node *) req->fcall);
+ }
+
+ PG_RETURN_POINTER(ret);
}
/* time_scale()
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 61dbd05..0068e71 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -4462,16 +4462,23 @@ CheckDateTokenTables(void)
}
/*
- * Common code for temporal protransform functions. Types time, timetz,
- * timestamp and timestamptz each have a range of allowed precisions. An
- * unspecified precision is rigorously equivalent to the highest specifiable
- * precision.
+ * Common code for temporal prosupport functions: simplify, if possible,
+ * a call to a temporal type's length-coercion function.
+ *
+ * Types time, timetz, timestamp and timestamptz each have a range of allowed
+ * precisions. An unspecified precision is rigorously equivalent to the
+ * highest specifiable precision. We can replace the function call with a
+ * no-op RelabelType if it is coercing to the same or higher precision as the
+ * input is known to have.
+ *
+ * The input Node is always a FuncExpr, but to reduce the #include footprint
+ * of datetime.h, we declare it as Node *.
*
* Note: timestamp_scale throws an error when the typmod is out of range, but
* we can't get there from a cast: our typmodin will have caught it already.
*/
Node *
-TemporalTransform(int32 max_precis, Node *node)
+TemporalSimplify(int32 max_precis, Node *node)
{
FuncExpr *expr = castNode(FuncExpr, node);
Node *ret = NULL;
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 45cd1a0..1c9deeb 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);
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 7befb6a..e0ef2f7 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.
*/
diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c
index 1585da0..fdcc620 100644
--- a/src/backend/utils/adt/varbit.c
+++ b/src/backend/utils/adt/varbit.c
@@ -20,6 +20,7 @@
#include "common/int.h"
#include "libpq/pqformat.h"
#include "nodes/nodeFuncs.h"
+#include "nodes/supportnodes.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/varbit.h"
@@ -672,32 +673,41 @@ varbit_send(PG_FUNCTION_ARGS)
}
/*
- * varbit_transform()
- * Flatten calls to varbit's length coercion function that set the new maximum
- * length >= the previous maximum length. We can ignore the isExplicit
- * argument, since that only affects truncation cases.
+ * varbit_support()
+ *
+ * Planner support function for the varbit() length coercion function.
+ *
+ * Currently, the only interesting thing we can do is flatten calls that set
+ * the new maximum length >= the previous maximum length. We can ignore the
+ * isExplicit argument, since that only affects truncation cases.
*/
Datum
-varbit_transform(PG_FUNCTION_ARGS)
+varbit_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);
- int32 old_max = exprTypmod(source);
- int32 new_max = new_typmod;
-
- /* Note: varbit() treats typmod 0 as invalid, so we do too */
- if (new_max <= 0 || (old_max > 0 && old_max <= new_max))
- ret = relabel_to_typmod(source, new_typmod);
+ typmod = (Node *) lsecond(expr->args);
+
+ if (IsA(typmod, Const) &&!((Const *) typmod)->constisnull)
+ {
+ Node *source = (Node *) linitial(expr->args);
+ int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
+ int32 old_max = exprTypmod(source);
+ int32 new_max = new_typmod;
+
+ /* Note: varbit() treats typmod 0 as invalid, so we do too */
+ if (new_max <= 0 || (old_max > 0 && old_max <= new_max))
+ ret = relabel_to_typmod(source, new_typmod);
+ }
}
PG_RETURN_POINTER(ret);
diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c
index 5cf927e..c866af0 100644
--- a/src/backend/utils/adt/varchar.c
+++ b/src/backend/utils/adt/varchar.c
@@ -21,6 +21,7 @@
#include "catalog/pg_type.h"
#include "libpq/pqformat.h"
#include "nodes/nodeFuncs.h"
+#include "nodes/supportnodes.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/varlena.h"
@@ -547,32 +548,41 @@ varcharsend(PG_FUNCTION_ARGS)
/*
- * varchar_transform()
- * Flatten calls to varchar's length coercion function that set the new maximum
- * length >= the previous maximum length. We can ignore the isExplicit
- * argument, since that only affects truncation cases.
+ * varchar_support()
+ *
+ * Planner support function for the varchar() length coercion function.
+ *
+ * Currently, the only interesting thing we can do is flatten calls that set
+ * the new maximum length >= the previous maximum length. We can ignore the
+ * isExplicit argument, since that only affects truncation cases.
*/
Datum
-varchar_transform(PG_FUNCTION_ARGS)
+varchar_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_max = old_typmod - VARHDRSZ;
- int32 new_max = new_typmod - VARHDRSZ;
-
- if (new_typmod < 0 || (old_typmod >= 0 && old_max <= new_max))
- ret = relabel_to_typmod(source, new_typmod);
+ typmod = (Node *) lsecond(expr->args);
+
+ 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_max = old_typmod - VARHDRSZ;
+ int32 new_max = new_typmod - VARHDRSZ;
+
+ if (new_typmod < 0 || (old_typmod >= 0 && old_max <= new_max))
+ ret = relabel_to_typmod(source, new_typmod);
+ }
}
PG_RETURN_POINTER(ret);
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index 245fcbf..4ff358a 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -1883,9 +1883,9 @@ my %tests = (
'CREATE TRANSFORM FOR int' => {
create_order => 34,
create_sql =>
- 'CREATE TRANSFORM FOR int LANGUAGE SQL (FROM SQL WITH FUNCTION varchar_transform(internal), TO SQL WITH FUNCTION int4recv(internal));',
+ 'CREATE TRANSFORM FOR int LANGUAGE SQL (FROM SQL WITH FUNCTION varchar_support(internal), TO SQL WITH FUNCTION int4recv(internal));',
regexp =>
- qr/CREATE TRANSFORM FOR integer LANGUAGE sql \(FROM SQL WITH FUNCTION pg_catalog\.varchar_transform\(internal\), TO SQL WITH FUNCTION pg_catalog\.int4recv\(internal\)\);/m,
+ qr/CREATE TRANSFORM FOR integer LANGUAGE sql \(FROM SQL WITH FUNCTION pg_catalog\.varchar_support\(internal\), TO SQL WITH FUNCTION pg_catalog\.int4recv\(internal\)\);/m,
like => { %full_runs, section_pre_data => 1, },
},
@@ -2880,7 +2880,7 @@ my %tests = (
procost,
prorows,
provariadic,
- protransform,
+ prosupport,
prokind,
prosecdef,
proleakproof,
@@ -2912,7 +2912,7 @@ my %tests = (
\QGRANT SELECT(procost) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
\QGRANT SELECT(prorows) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
\QGRANT SELECT(provariadic) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
- \QGRANT SELECT(protransform) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
+ \QGRANT SELECT(prosupport) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
\QGRANT SELECT(prokind) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
\QGRANT SELECT(prosecdef) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
\QGRANT SELECT(proleakproof) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 3ecc2e1..e5cb5bb 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -1326,11 +1326,11 @@
{ oid => '668', descr => 'adjust char() to typmod length',
proname => 'bpchar', prorettype => 'bpchar',
proargtypes => 'bpchar int4 bool', prosrc => 'bpchar' },
-{ oid => '3097', descr => 'transform a varchar length coercion',
- proname => 'varchar_transform', prorettype => 'internal',
- proargtypes => 'internal', prosrc => 'varchar_transform' },
+{ oid => '3097', descr => 'planner support for varchar length coercion',
+ proname => 'varchar_support', prorettype => 'internal',
+ proargtypes => 'internal', prosrc => 'varchar_support' },
{ oid => '669', descr => 'adjust varchar() to typmod length',
- proname => 'varchar', protransform => 'varchar_transform',
+ proname => 'varchar', prosupport => 'varchar_support',
prorettype => 'varchar', proargtypes => 'varchar int4 bool',
prosrc => 'varchar' },
@@ -1954,13 +1954,9 @@
# OIDS 1000 - 1999
-{ oid => '3994', descr => 'transform a time zone adjustment',
- proname => 'timestamp_izone_transform', prorettype => 'internal',
- proargtypes => 'internal', prosrc => 'timestamp_izone_transform' },
{ oid => '1026', descr => 'adjust timestamp to new time zone',
- proname => 'timezone', protransform => 'timestamp_izone_transform',
- prorettype => 'timestamp', proargtypes => 'interval timestamptz',
- prosrc => 'timestamptz_izone' },
+ proname => 'timezone', prorettype => 'timestamp',
+ proargtypes => 'interval timestamptz', prosrc => 'timestamptz_izone' },
{ oid => '1031', descr => 'I/O',
proname => 'aclitemin', provolatile => 's', prorettype => 'aclitem',
@@ -2190,13 +2186,9 @@
{ oid => '1158', descr => 'convert UNIX epoch to timestamptz',
proname => 'to_timestamp', prorettype => 'timestamptz',
proargtypes => 'float8', prosrc => 'float8_timestamptz' },
-{ oid => '3995', descr => 'transform a time zone adjustment',
- proname => 'timestamp_zone_transform', prorettype => 'internal',
- proargtypes => 'internal', prosrc => 'timestamp_zone_transform' },
{ oid => '1159', descr => 'adjust timestamp to new time zone',
- proname => 'timezone', protransform => 'timestamp_zone_transform',
- prorettype => 'timestamp', proargtypes => 'text timestamptz',
- prosrc => 'timestamptz_zone' },
+ proname => 'timezone', prorettype => 'timestamp',
+ proargtypes => 'text timestamptz', prosrc => 'timestamptz_zone' },
{ oid => '1160', descr => 'I/O',
proname => 'interval_in', provolatile => 's', prorettype => 'interval',
@@ -2301,11 +2293,11 @@
# OIDS 1200 - 1299
-{ oid => '3918', descr => 'transform an interval length coercion',
- proname => 'interval_transform', prorettype => 'internal',
- proargtypes => 'internal', prosrc => 'interval_transform' },
+{ oid => '3918', descr => 'planner support for interval length coercion',
+ proname => 'interval_support', prorettype => 'internal',
+ proargtypes => 'internal', prosrc => 'interval_support' },
{ oid => '1200', descr => 'adjust interval precision',
- proname => 'interval', protransform => 'interval_transform',
+ proname => 'interval', prosupport => 'interval_support',
prorettype => 'interval', proargtypes => 'interval int4',
prosrc => 'interval_scale' },
@@ -3713,13 +3705,12 @@
{ oid => '1685', descr => 'adjust bit() to typmod length',
proname => 'bit', prorettype => 'bit', proargtypes => 'bit int4 bool',
prosrc => 'bit' },
-{ oid => '3158', descr => 'transform a varbit length coercion',
- proname => 'varbit_transform', prorettype => 'internal',
- proargtypes => 'internal', prosrc => 'varbit_transform' },
+{ oid => '3158', descr => 'planner support for varbit length coercion',
+ proname => 'varbit_support', prorettype => 'internal',
+ proargtypes => 'internal', prosrc => 'varbit_support' },
{ oid => '1687', descr => 'adjust varbit() to typmod length',
- proname => 'varbit', protransform => 'varbit_transform',
- prorettype => 'varbit', proargtypes => 'varbit int4 bool',
- prosrc => 'varbit' },
+ proname => 'varbit', prosupport => 'varbit_support', prorettype => 'varbit',
+ proargtypes => 'varbit int4 bool', prosrc => 'varbit' },
{ oid => '1698', descr => 'position of sub-bitstring',
proname => 'position', prorettype => 'int4', proargtypes => 'bit bit',
@@ -4081,11 +4072,11 @@
{ oid => '2918', descr => 'I/O typmod',
proname => 'numerictypmodout', prorettype => 'cstring', proargtypes => 'int4',
prosrc => 'numerictypmodout' },
-{ oid => '3157', descr => 'transform a numeric length coercion',
- proname => 'numeric_transform', prorettype => 'internal',
- proargtypes => 'internal', prosrc => 'numeric_transform' },
+{ oid => '3157', descr => 'planner support for numeric length coercion',
+ proname => 'numeric_support', prorettype => 'internal',
+ proargtypes => 'internal', prosrc => 'numeric_support' },
{ oid => '1703', descr => 'adjust numeric to typmod precision/scale',
- proname => 'numeric', protransform => 'numeric_transform',
+ proname => 'numeric', prosupport => 'numeric_support',
prorettype => 'numeric', proargtypes => 'numeric int4', prosrc => 'numeric' },
{ oid => '1704',
proname => 'numeric_abs', prorettype => 'numeric', proargtypes => 'numeric',
@@ -5448,15 +5439,15 @@
proname => 'bytea_sortsupport', prorettype => 'void',
proargtypes => 'internal', prosrc => 'bytea_sortsupport' },
-{ oid => '3917', descr => 'transform a timestamp length coercion',
- proname => 'timestamp_transform', prorettype => 'internal',
- proargtypes => 'internal', prosrc => 'timestamp_transform' },
-{ oid => '3944', descr => 'transform a time length coercion',
- proname => 'time_transform', prorettype => 'internal',
- proargtypes => 'internal', prosrc => 'time_transform' },
+{ oid => '3917', descr => 'planner support for timestamp length coercion',
+ proname => 'timestamp_support', prorettype => 'internal',
+ proargtypes => 'internal', prosrc => 'timestamp_support' },
+{ oid => '3944', descr => 'planner support for time length coercion',
+ proname => 'time_support', prorettype => 'internal',
+ proargtypes => 'internal', prosrc => 'time_support' },
{ oid => '1961', descr => 'adjust timestamp precision',
- proname => 'timestamp', protransform => 'timestamp_transform',
+ proname => 'timestamp', prosupport => 'timestamp_support',
prorettype => 'timestamp', proargtypes => 'timestamp int4',
prosrc => 'timestamp_scale' },
@@ -5468,14 +5459,14 @@
prosrc => 'oidsmaller' },
{ oid => '1967', descr => 'adjust timestamptz precision',
- proname => 'timestamptz', protransform => 'timestamp_transform',
+ proname => 'timestamptz', prosupport => 'timestamp_support',
prorettype => 'timestamptz', proargtypes => 'timestamptz int4',
prosrc => 'timestamptz_scale' },
{ oid => '1968', descr => 'adjust time precision',
- proname => 'time', protransform => 'time_transform', prorettype => 'time',
+ proname => 'time', prosupport => 'time_support', prorettype => 'time',
proargtypes => 'time int4', prosrc => 'time_scale' },
{ oid => '1969', descr => 'adjust time with time zone precision',
- proname => 'timetz', protransform => 'time_transform', prorettype => 'timetz',
+ proname => 'timetz', prosupport => 'time_support', prorettype => 'timetz',
proargtypes => 'timetz int4', prosrc => 'timetz_scale' },
{ oid => '2003',
@@ -5662,13 +5653,11 @@
prosrc => 'select pg_catalog.age(cast(current_date as timestamp without time zone), $1)' },
{ oid => '2069', descr => 'adjust timestamp to new time zone',
- proname => 'timezone', protransform => 'timestamp_zone_transform',
- prorettype => 'timestamptz', proargtypes => 'text timestamp',
- prosrc => 'timestamp_zone' },
+ proname => 'timezone', prorettype => 'timestamptz',
+ proargtypes => 'text timestamp', prosrc => 'timestamp_zone' },
{ oid => '2070', descr => 'adjust timestamp to new time zone',
- proname => 'timezone', protransform => 'timestamp_izone_transform',
- prorettype => 'timestamptz', proargtypes => 'interval timestamp',
- prosrc => 'timestamp_izone' },
+ proname => 'timezone', prorettype => 'timestamptz',
+ proargtypes => 'interval timestamp', prosrc => 'timestamp_izone' },
{ oid => '2071',
proname => 'date_pl_interval', prorettype => 'timestamp',
proargtypes => 'date interval', prosrc => 'date_pl_interval' },
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index c2bb951..b433769 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -53,8 +53,8 @@ CATALOG(pg_proc,1255,ProcedureRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81,Proce
/* element type of variadic array, or 0 */
Oid provariadic BKI_DEFAULT(0) BKI_LOOKUP(pg_type);
- /* transforms calls to it during planning */
- regproc protransform BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
+ /* planner support function for this function, or 0 if none */
+ regproc prosupport BKI_DEFAULT(0) BKI_LOOKUP(pg_proc);
/* see PROKIND_ categories below */
char prokind BKI_DEFAULT(f);
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 10dac60..e029b40 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -505,7 +505,8 @@ typedef enum NodeTag
T_IndexAmRoutine, /* in access/amapi.h */
T_TsmRoutine, /* in access/tsmapi.h */
T_ForeignKeyCacheInfo, /* in utils/rel.h */
- T_CallContext /* in nodes/parsenodes.h */
+ T_CallContext, /* in nodes/parsenodes.h */
+ T_SupportRequestSimplify /* in nodes/supportnodes.h */
} NodeTag;
/*
diff --git a/src/include/nodes/supportnodes.h b/src/include/nodes/supportnodes.h
new file mode 100644
index 0000000..1f7d02b
--- /dev/null
+++ b/src/include/nodes/supportnodes.h
@@ -0,0 +1,70 @@
+/*-------------------------------------------------------------------------
+ *
+ * supportnodes.h
+ * Definitions for planner support functions.
+ *
+ * This file defines the API for "planner support functions", which
+ * are SQL functions (normally written in C) that can be attached to
+ * another "target" function to give the system additional knowledge
+ * about the target function. All the current capabilities have to do
+ * with planning queries that use the target function, though it is
+ * possible that future extensions will add functionality to be invoked
+ * by the parser or executor.
+ *
+ * A support function must have the SQL signature
+ * supportfn(internal) returns internal
+ * The argument is a pointer to one of the Node types defined in this file.
+ * The result is usually also a Node pointer, though its type depends on
+ * which capability is being invoked. In all cases, a NULL pointer result
+ * (that's PG_RETURN_POINTER(NULL), not PG_RETURN_NULL()) indicates that
+ * the support function cannot do anything useful for the given request.
+ * Support functions must return a NULL pointer, not fail, if they do not
+ * recognize the request node type or cannot handle the given case; this
+ * allows for future extensions of the set of request cases.
+ *
+ *
+ * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/nodes/supportnodes.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef SUPPORTNODES_H
+#define SUPPORTNODES_H
+
+#include "nodes/primnodes.h"
+
+struct PlannerInfo; /* avoid including relation.h here */
+
+
+/*
+ * The Simplify request allows the support function to perform plan-time
+ * simplification of a call to its target function. For example, a varchar
+ * length coercion that does not decrease the allowed length of its argument
+ * could be replaced by a RelabelType node, or "x + 0" could be replaced by
+ * "x". This is invoked during the planner's constant-folding pass, so the
+ * function's arguments can be presumed already simplified.
+ *
+ * The planner's PlannerInfo "root" is typically not needed, but can be
+ * consulted if it's necessary to obtain info about Vars present in
+ * the given node tree. Beware that root could be NULL in some usages.
+ *
+ * "fcall" will be a FuncExpr invoking the support function's target
+ * function. (This is true even if the original parsetree node was an
+ * operator call; a FuncExpr is synthesized for this purpose.)
+ *
+ * The result should be a semantically-equivalent transformed node tree,
+ * or NULL if no simplification could be performed. Do *not* return or
+ * modify *fcall, as it isn't really a separately allocated Node. But
+ * it's okay to use fcall->args, or parts of it, in the result tree.
+ */
+typedef struct SupportRequestSimplify
+{
+ NodeTag type;
+
+ struct PlannerInfo *root; /* Planner's infrastructure */
+ FuncExpr *fcall; /* Function call to be simplified */
+} SupportRequestSimplify;
+
+#endif /* SUPPORTNODES_H */
diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h
index f5ec9bb..87f819e 100644
--- a/src/include/utils/datetime.h
+++ b/src/include/utils/datetime.h
@@ -330,7 +330,7 @@ extern int DecodeUnits(int field, char *lowtoken, int *val);
extern int j2day(int jd);
-extern Node *TemporalTransform(int32 max_precis, Node *node);
+extern Node *TemporalSimplify(int32 max_precis, Node *node);
extern bool CheckDateTokenTables(void);
diff --git a/src/test/modules/test_ddl_deparse/expected/create_transform.out b/src/test/modules/test_ddl_deparse/expected/create_transform.out
index 0d1cc36..da7fea2 100644
--- a/src/test/modules/test_ddl_deparse/expected/create_transform.out
+++ b/src/test/modules/test_ddl_deparse/expected/create_transform.out
@@ -7,7 +7,7 @@
-- internal and as return argument the datatype of the transform done.
-- pl/plpgsql does not authorize the use of internal as data type.
CREATE TRANSFORM FOR int LANGUAGE SQL (
- FROM SQL WITH FUNCTION varchar_transform(internal),
+ FROM SQL WITH FUNCTION varchar_support(internal),
TO SQL WITH FUNCTION int4recv(internal));
NOTICE: DDL test: type simple, tag CREATE TRANSFORM
DROP TRANSFORM FOR int LANGUAGE SQL;
diff --git a/src/test/modules/test_ddl_deparse/sql/create_transform.sql b/src/test/modules/test_ddl_deparse/sql/create_transform.sql
index 0968702..132fc5a 100644
--- a/src/test/modules/test_ddl_deparse/sql/create_transform.sql
+++ b/src/test/modules/test_ddl_deparse/sql/create_transform.sql
@@ -8,7 +8,7 @@
-- internal and as return argument the datatype of the transform done.
-- pl/plpgsql does not authorize the use of internal as data type.
CREATE TRANSFORM FOR int LANGUAGE SQL (
- FROM SQL WITH FUNCTION varchar_transform(internal),
+ FROM SQL WITH FUNCTION varchar_support(internal),
TO SQL WITH FUNCTION int4recv(internal));
DROP TRANSFORM FOR int LANGUAGE SQL;
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 4085e45..c89ec06 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -38,7 +38,7 @@ CREATE USER MAPPING FOR regress_addr_user SERVER "integer";
ALTER DEFAULT PRIVILEGES FOR ROLE regress_addr_user IN SCHEMA public GRANT ALL ON TABLES TO regress_addr_user;
ALTER DEFAULT PRIVILEGES FOR ROLE regress_addr_user REVOKE DELETE ON TABLES FROM regress_addr_user;
CREATE TRANSFORM FOR int LANGUAGE SQL (
- FROM SQL WITH FUNCTION varchar_transform(internal),
+ FROM SQL WITH FUNCTION varchar_support(internal),
TO SQL WITH FUNCTION int4recv(internal));
CREATE PUBLICATION addr_pub FOR TABLE addr_nsp.gentable;
CREATE SUBSCRIPTION addr_sub CONNECTION '' PUBLICATION bar WITH (connect = false, slot_name = NONE);
diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out
index ef268d3..4edc817 100644
--- a/src/test/regress/expected/oidjoins.out
+++ b/src/test/regress/expected/oidjoins.out
@@ -809,12 +809,12 @@ WHERE provariadic != 0 AND
------+-------------
(0 rows)
-SELECT ctid, protransform
+SELECT ctid, prosupport
FROM pg_catalog.pg_proc fk
-WHERE protransform != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.protransform);
- ctid | protransform
-------+--------------
+WHERE prosupport != 0 AND
+ NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prosupport);
+ ctid | prosupport
+------+------------
(0 rows)
SELECT ctid, prorettype
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 7328095..ce25ee0 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -453,10 +453,10 @@ WHERE proallargtypes IS NOT NULL AND
-----+---------+-------------+----------------+-------------
(0 rows)
--- Check for protransform functions with the wrong signature
+-- Check for prosupport functions with the wrong signature
SELECT p1.oid, p1.proname, p2.oid, p2.proname
FROM pg_proc AS p1, pg_proc AS p2
-WHERE p2.oid = p1.protransform AND
+WHERE p2.oid = p1.prosupport AND
(p2.prorettype != 'internal'::regtype OR p2.proretset OR p2.pronargs != 1
OR p2.proargtypes[0] != 'internal'::regtype);
oid | proname | oid | proname
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index d7df322..fd79465 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -41,7 +41,7 @@ CREATE USER MAPPING FOR regress_addr_user SERVER "integer";
ALTER DEFAULT PRIVILEGES FOR ROLE regress_addr_user IN SCHEMA public GRANT ALL ON TABLES TO regress_addr_user;
ALTER DEFAULT PRIVILEGES FOR ROLE regress_addr_user REVOKE DELETE ON TABLES FROM regress_addr_user;
CREATE TRANSFORM FOR int LANGUAGE SQL (
- FROM SQL WITH FUNCTION varchar_transform(internal),
+ FROM SQL WITH FUNCTION varchar_support(internal),
TO SQL WITH FUNCTION int4recv(internal));
CREATE PUBLICATION addr_pub FOR TABLE addr_nsp.gentable;
CREATE SUBSCRIPTION addr_sub CONNECTION '' PUBLICATION bar WITH (connect = false, slot_name = NONE);
diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql
index c8291d3..dbe4a58 100644
--- a/src/test/regress/sql/oidjoins.sql
+++ b/src/test/regress/sql/oidjoins.sql
@@ -405,10 +405,10 @@ SELECT ctid, provariadic
FROM pg_catalog.pg_proc fk
WHERE provariadic != 0 AND
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.provariadic);
-SELECT ctid, protransform
+SELECT ctid, prosupport
FROM pg_catalog.pg_proc fk
-WHERE protransform != 0 AND
- NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.protransform);
+WHERE prosupport != 0 AND
+ NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.prosupport);
SELECT ctid, prorettype
FROM pg_catalog.pg_proc fk
WHERE prorettype != 0 AND
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index 8544cbe..e2014fc 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -353,10 +353,10 @@ WHERE proallargtypes IS NOT NULL AND
FROM generate_series(1, array_length(proallargtypes, 1)) g(i)
WHERE proargmodes IS NULL OR proargmodes[i] IN ('i', 'b', 'v'));
--- Check for protransform functions with the wrong signature
+-- Check for prosupport functions with the wrong signature
SELECT p1.oid, p1.proname, p2.oid, p2.proname
FROM pg_proc AS p1, pg_proc AS p2
-WHERE p2.oid = p1.protransform AND
+WHERE p2.oid = p1.prosupport AND
(p2.prorettype != 'internal'::regtype OR p2.proretset OR p2.pronargs != 1
OR p2.proargtypes[0] != 'internal'::regtype);
diff --git a/src/tools/findoidjoins/README b/src/tools/findoidjoins/README
index 305454a..e5fc310 100644
--- a/src/tools/findoidjoins/README
+++ b/src/tools/findoidjoins/README
@@ -161,7 +161,7 @@ Join pg_catalog.pg_proc.pronamespace => pg_catalog.pg_namespace.oid
Join pg_catalog.pg_proc.proowner => pg_catalog.pg_authid.oid
Join pg_catalog.pg_proc.prolang => pg_catalog.pg_language.oid
Join pg_catalog.pg_proc.provariadic => pg_catalog.pg_type.oid
-Join pg_catalog.pg_proc.protransform => pg_catalog.pg_proc.oid
+Join pg_catalog.pg_proc.prosupport => pg_catalog.pg_proc.oid
Join pg_catalog.pg_proc.prorettype => pg_catalog.pg_type.oid
Join pg_catalog.pg_range.rngtypid => pg_catalog.pg_type.oid
Join pg_catalog.pg_range.rngsubtype => pg_catalog.pg_type.oid