Getting rid of SQLValueFunction
Hi all,
I have bumped a few days ago on the fact that COERCE_SQL_SYNTAX
(introduced by 40c24bf) and SQLValueFunction are around to do the
exact same thing, as known as enforcing single-function calls with
dedicated SQL keywords. For example, keywords like SESSION_USER,
CURRENT_DATE, etc. go through SQLValueFunction and rely on the parser
to set a state that gets then used in execExprInterp.c. And it is
rather easy to implement incorrect SQLValueFunctions, as these rely on
more hardcoded assumptions in the parser and executor than the
equivalent FuncCalls (like collation to assign when using a text-like
SQLValueFunctions).
There are two categories of single-value functions:
- The ones returning names, where we enforce a C collation in two
places of the code (current_role, role, current_catalog,
current_schema, current_database, current_user), even if
get_typcollation() should do that for name types.
- The ones working on time, date and timestamps (localtime[stamp],
current_date, current_time[stamp]), for 9 patterns as these accept an
optional typmod.
I have dug into the possibility to unify all that with a single
interface, and finish with the attached patch set which is a reduction
of code, where all the SQLValueFunctions are replaced by a set of
FuncCalls:
25 files changed, 338 insertions(+), 477 deletions(-)
0001 is the move done for the name-related functions, cleaning up two
places in the executor when a C collation is assigned to those
function expressions. 0002 is the remaining cleanup for the
time-related ones, moving a set of parser-side checks to the execution
path within each function, so as all this knowledge is now local to
each file holding the date and timestamp types. Most of the gain is
in 0002, obviously.
The pg_proc entries introduced for the sake of the move use the same
name as the SQL keywords. These should perhaps be prefixed with a
"pg_" at least. There would be an exception with pg_localtime[stamp],
though, where we could use a pg_localtime[stamp]_sql for the function
name for prosrc. I am open to suggestions for these names.
Thoughts?
--
Michael
Attachments:
0001-Remove-from-SQLValueFunctionOp-all-name-based-functi.patchtext/x-diff; charset=us-asciiDownload
From 5eaabb5c306b06df2c3b0d18f075adb96074001f Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Fri, 30 Sep 2022 10:48:22 +0900
Subject: [PATCH 1/2] Remove from SQLValueFunctionOp all name-based functions
This includes six functions, moved to be COERCE_SQL_SYNTAX:
- current_role
- role
- current_catalog
- current_schema
- current_database
- current_user
"user" and "current_role" need specific functions to allow ruleutils.c
to map to the expected SQL grammar these require. SQLValueFunctionOp is
reduced to half its contents.
---
src/include/catalog/pg_proc.dat | 6 ++++
src/include/nodes/primnodes.h | 8 +----
src/backend/executor/execExprInterp.c | 27 -----------------
src/backend/nodes/nodeFuncs.c | 4 +--
src/backend/parser/gram.y | 30 +++++++++++++++----
src/backend/parser/parse_expr.c | 8 -----
src/backend/parser/parse_target.c | 18 ------------
src/backend/utils/adt/ruleutils.c | 36 +++++++++++------------
src/test/regress/expected/create_view.out | 12 ++++++++
src/test/regress/sql/create_view.sql | 6 ++++
10 files changed, 68 insertions(+), 87 deletions(-)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 68bb032d3e..414d752f9d 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -1505,6 +1505,12 @@
{ oid => '745', descr => 'current user name',
proname => 'current_user', provolatile => 's', prorettype => 'name',
proargtypes => '', prosrc => 'current_user' },
+{ oid => '9695', descr => 'current role name',
+ proname => 'current_role', provolatile => 's', prorettype => 'name',
+ proargtypes => '', prosrc => 'current_user' },
+{ oid => '9696', descr => 'user name',
+ proname => 'user', provolatile => 's', prorettype => 'name',
+ proargtypes => '', prosrc => 'current_user' },
{ oid => '746', descr => 'session user name',
proname => 'session_user', provolatile => 's', prorettype => 'name',
proargtypes => '', prosrc => 'session_user' },
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 40661334bb..e818231e15 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1313,13 +1313,7 @@ typedef enum SQLValueFunctionOp
SVFOP_LOCALTIME,
SVFOP_LOCALTIME_N,
SVFOP_LOCALTIMESTAMP,
- SVFOP_LOCALTIMESTAMP_N,
- SVFOP_CURRENT_ROLE,
- SVFOP_CURRENT_USER,
- SVFOP_USER,
- SVFOP_SESSION_USER,
- SVFOP_CURRENT_CATALOG,
- SVFOP_CURRENT_SCHEMA
+ SVFOP_LOCALTIMESTAMP_N
} SQLValueFunctionOp;
typedef struct SQLValueFunction
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 9b9bbf00a9..6ebf5c287e 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -2495,15 +2495,10 @@ ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
void
ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
{
- LOCAL_FCINFO(fcinfo, 0);
SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
*op->resnull = false;
- /*
- * Note: current_schema() can return NULL. current_user() etc currently
- * cannot, but might as well code those cases the same way for safety.
- */
switch (svf->op)
{
case SVFOP_CURRENT_DATE:
@@ -2525,28 +2520,6 @@ ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
case SVFOP_LOCALTIMESTAMP_N:
*op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
break;
- case SVFOP_CURRENT_ROLE:
- case SVFOP_CURRENT_USER:
- case SVFOP_USER:
- InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
- *op->resvalue = current_user(fcinfo);
- *op->resnull = fcinfo->isnull;
- break;
- case SVFOP_SESSION_USER:
- InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
- *op->resvalue = session_user(fcinfo);
- *op->resnull = fcinfo->isnull;
- break;
- case SVFOP_CURRENT_CATALOG:
- InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
- *op->resvalue = current_database(fcinfo);
- *op->resnull = fcinfo->isnull;
- break;
- case SVFOP_CURRENT_SCHEMA:
- InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
- *op->resvalue = current_schema(fcinfo);
- *op->resnull = fcinfo->isnull;
- break;
}
}
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 0a7b22f97e..4f72fc2268 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -1144,9 +1144,7 @@ exprSetCollation(Node *expr, Oid collation)
((MinMaxExpr *) expr)->minmaxcollid = collation;
break;
case T_SQLValueFunction:
- Assert((((SQLValueFunction *) expr)->type == NAMEOID) ?
- (collation == C_COLLATION_OID) :
- (collation == InvalidOid));
+ Assert(collation == InvalidOid);
break;
case T_XmlExpr:
Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ?
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 94d5142a4a..23a49e99ca 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -15229,15 +15229,24 @@ func_expr_common_subexpr:
}
| CURRENT_ROLE
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_ROLE, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_role"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_USER
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_USER, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_user"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| SESSION_USER
{
- $$ = makeSQLValueFunction(SVFOP_SESSION_USER, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("session_user"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| SYSTEM_USER
{
@@ -15248,15 +15257,24 @@ func_expr_common_subexpr:
}
| USER
{
- $$ = makeSQLValueFunction(SVFOP_USER, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("user"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_CATALOG
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_CATALOG, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_database"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_SCHEMA
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_SCHEMA, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_schema"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CAST '(' a_expr AS Typename ')'
{ $$ = makeTypeCast($3, $5, @1); }
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 7aaf1c673f..9bde33b407 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -2231,14 +2231,6 @@ transformSQLValueFunction(ParseState *pstate, SQLValueFunction *svf)
svf->type = TIMESTAMPOID;
svf->typmod = anytimestamp_typmod_check(false, svf->typmod);
break;
- case SVFOP_CURRENT_ROLE:
- case SVFOP_CURRENT_USER:
- case SVFOP_USER:
- case SVFOP_SESSION_USER:
- case SVFOP_CURRENT_CATALOG:
- case SVFOP_CURRENT_SCHEMA:
- svf->type = NAMEOID;
- break;
}
return (Node *) svf;
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index bd8057bc3e..f54591a987 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1895,24 +1895,6 @@ FigureColnameInternal(Node *node, char **name)
case SVFOP_LOCALTIMESTAMP_N:
*name = "localtimestamp";
return 2;
- case SVFOP_CURRENT_ROLE:
- *name = "current_role";
- return 2;
- case SVFOP_CURRENT_USER:
- *name = "current_user";
- return 2;
- case SVFOP_USER:
- *name = "user";
- return 2;
- case SVFOP_SESSION_USER:
- *name = "session_user";
- return 2;
- case SVFOP_CURRENT_CATALOG:
- *name = "current_catalog";
- return 2;
- case SVFOP_CURRENT_SCHEMA:
- *name = "current_schema";
- return 2;
}
break;
case T_XmlExpr:
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index c418403537..9987bca912 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -9198,24 +9198,6 @@ get_rule_expr(Node *node, deparse_context *context,
appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
svf->typmod);
break;
- case SVFOP_CURRENT_ROLE:
- appendStringInfoString(buf, "CURRENT_ROLE");
- break;
- case SVFOP_CURRENT_USER:
- appendStringInfoString(buf, "CURRENT_USER");
- break;
- case SVFOP_USER:
- appendStringInfoString(buf, "USER");
- break;
- case SVFOP_SESSION_USER:
- appendStringInfoString(buf, "SESSION_USER");
- break;
- case SVFOP_CURRENT_CATALOG:
- appendStringInfoString(buf, "CURRENT_CATALOG");
- break;
- case SVFOP_CURRENT_SCHEMA:
- appendStringInfoString(buf, "CURRENT_SCHEMA");
- break;
}
}
break;
@@ -10317,6 +10299,24 @@ get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
appendStringInfoChar(buf, ')');
return true;
+ case F_CURRENT_DATABASE:
+ appendStringInfoString(buf, "CURRENT_CATALOG");
+ return true;
+ case F_CURRENT_ROLE:
+ appendStringInfoString(buf, "CURRENT_ROLE");
+ return true;
+ case F_CURRENT_SCHEMA:
+ appendStringInfoString(buf, "CURRENT_SCHEMA");
+ return true;
+ case F_CURRENT_USER:
+ appendStringInfoString(buf, "CURRENT_USER");
+ return true;
+ case F_USER:
+ appendStringInfoString(buf, "USER");
+ return true;
+ case F_SESSION_USER:
+ appendStringInfoString(buf, "SESSION_USER");
+ return true;
case F_SYSTEM_USER:
appendStringInfoString(buf, "SYSTEM_USER");
return true;
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index bf4ff30d86..77123cecbd 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -1941,6 +1941,12 @@ select
trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea) as btb,
trim(leading E'\\000'::bytea from E'\\000Tom\\000'::bytea) as ltb,
trim(trailing E'\\000'::bytea from E'\\000Tom\\000'::bytea) as rtb,
+ CURRENT_CATALOG as ca,
+ CURRENT_ROLE as cr,
+ CURRENT_SCHEMA as cs,
+ CURRENT_USER as cu,
+ USER as us,
+ SESSION_USER seu,
SYSTEM_USER as su;
select pg_get_viewdef('tt201v', true);
pg_get_viewdef
@@ -1963,6 +1969,12 @@ select pg_get_viewdef('tt201v', true);
TRIM(BOTH '\x00'::bytea FROM '\x00546f6d00'::bytea) AS btb, +
TRIM(LEADING '\x00'::bytea FROM '\x00546f6d00'::bytea) AS ltb, +
TRIM(TRAILING '\x00'::bytea FROM '\x00546f6d00'::bytea) AS rtb, +
+ CURRENT_CATALOG AS ca, +
+ CURRENT_ROLE AS cr, +
+ CURRENT_SCHEMA AS cs, +
+ CURRENT_USER AS cu, +
+ USER AS us, +
+ SESSION_USER AS seu, +
SYSTEM_USER AS su;
(1 row)
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index 913b4ee460..ccaebdc22b 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -722,6 +722,12 @@ select
trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea) as btb,
trim(leading E'\\000'::bytea from E'\\000Tom\\000'::bytea) as ltb,
trim(trailing E'\\000'::bytea from E'\\000Tom\\000'::bytea) as rtb,
+ CURRENT_CATALOG as ca,
+ CURRENT_ROLE as cr,
+ CURRENT_SCHEMA as cs,
+ CURRENT_USER as cu,
+ USER as us,
+ SESSION_USER seu,
SYSTEM_USER as su;
select pg_get_viewdef('tt201v', true);
--
2.37.2
0002-Replace-SQLValueFunction-by-direct-function-calls.patchtext/x-diff; charset=us-asciiDownload
From 92512fd68a8e05b6d7334a8d044fb5037a62c173 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Fri, 30 Sep 2022 14:41:52 +0900
Subject: [PATCH 2/2] Replace SQLValueFunction by direct function calls
This impacts 9 patterns where the SQL grammar takes priority:
- localtime, that can take a typmod.
- localtimestamp, that can take a typmod.
- current_time, that can take a typmod.
- current_timestamp, that can take a typmod.
- current_date.
---
src/include/catalog/pg_proc.dat | 15 +++
src/include/executor/execExpr.h | 8 --
src/include/nodes/primnodes.h | 33 -------
src/include/utils/date.h | 4 -
src/include/utils/timestamp.h | 4 -
src/backend/catalog/system_functions.sql | 26 ++++++
src/backend/executor/execExpr.c | 11 ---
src/backend/executor/execExprInterp.c | 46 ---------
src/backend/jit/llvm/llvmjit_expr.c | 6 --
src/backend/jit/llvm/llvmjit_types.c | 1 -
src/backend/nodes/nodeFuncs.c | 30 +-----
src/backend/optimizer/path/costsize.c | 1 -
src/backend/optimizer/util/clauses.c | 39 ++------
src/backend/parser/gram.y | 59 +++++++-----
src/backend/parser/parse_expr.c | 52 -----------
src/backend/parser/parse_target.c | 25 -----
src/backend/utils/adt/date.c | 81 +++++++++-------
src/backend/utils/adt/ruleutils.c | 109 +++++++++++++---------
src/backend/utils/adt/timestamp.c | 72 ++++++++------
src/backend/utils/misc/queryjumble.c | 9 --
src/test/regress/expected/create_view.out | 18 ++++
src/test/regress/expected/expressions.out | 2 +-
src/test/regress/sql/create_view.sql | 9 ++
src/test/regress/sql/expressions.sql | 2 +-
src/tools/pgindent/typedefs.list | 2 -
25 files changed, 272 insertions(+), 392 deletions(-)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 414d752f9d..ae9f3b83cb 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -1517,6 +1517,21 @@
{ oid => '9977', descr => 'system user name',
proname => 'system_user', provolatile => 's', prorettype => 'text',
proargtypes => '', prosrc => 'system_user' },
+{ oid => '9978', descr => 'current date',
+ proname => 'current_date', provolatile => 's', prorettype => 'date',
+ proargtypes => '', prosrc => 'current_date' },
+{ oid => '9979', descr => 'current time',
+ proname => 'current_time', provolatile => 's', prorettype => 'timetz',
+ proargtypes => 'int4', prosrc => 'current_time', proisstrict => 'f' },
+{ oid => '9980', descr => 'current timestamp',
+ proname => 'current_timestamp', provolatile => 's', prorettype => 'timestamptz',
+ proargtypes => 'int4', prosrc => 'current_timestamp', proisstrict => 'f' },
+{ oid => '9981', descr => 'local time',
+ proname => 'localtime', provolatile => 's', prorettype => 'time',
+ proargtypes => 'int4', prosrc => 'sql_localtime', proisstrict => 'f' },
+{ oid => '9982', descr => 'local timestamp',
+ proname => 'localtimestamp', provolatile => 's', prorettype => 'timestamp',
+ proargtypes => 'int4', prosrc => 'sql_localtimestamp', proisstrict => 'f' },
{ oid => '744',
proname => 'array_eq', prorettype => 'bool',
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index e14f15d435..0557302b92 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -170,7 +170,6 @@ typedef enum ExprEvalOp
EEOP_DISTINCT,
EEOP_NOT_DISTINCT,
EEOP_NULLIF,
- EEOP_SQLVALUEFUNCTION,
EEOP_CURRENTOFEXPR,
EEOP_NEXTVALUEEXPR,
EEOP_ARRAYEXPR,
@@ -416,12 +415,6 @@ typedef struct ExprEvalStep
FunctionCallInfo fcinfo_data_in;
} iocoerce;
- /* for EEOP_SQLVALUEFUNCTION */
- struct
- {
- SQLValueFunction *svf;
- } sqlvaluefunction;
-
/* for EEOP_NEXTVALUEEXPR */
struct
{
@@ -741,7 +734,6 @@ extern void ExecEvalParamExec(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
extern void ExecEvalParamExtern(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
-extern void ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op);
extern void ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op);
extern void ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op);
extern void ExecEvalRowNull(ExprState *state, ExprEvalStep *op,
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index e818231e15..71293185fb 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1292,39 +1292,6 @@ typedef struct MinMaxExpr
int location; /* token location, or -1 if unknown */
} MinMaxExpr;
-/*
- * SQLValueFunction - parameterless functions with special grammar productions
- *
- * The SQL standard categorizes some of these as <datetime value function>
- * and others as <general value specification>. We call 'em SQLValueFunctions
- * for lack of a better term. We store type and typmod of the result so that
- * some code doesn't need to know each function individually, and because
- * we would need to store typmod anyway for some of the datetime functions.
- * Note that currently, all variants return non-collating datatypes, so we do
- * not need a collation field; also, all these functions are stable.
- */
-typedef enum SQLValueFunctionOp
-{
- SVFOP_CURRENT_DATE,
- SVFOP_CURRENT_TIME,
- SVFOP_CURRENT_TIME_N,
- SVFOP_CURRENT_TIMESTAMP,
- SVFOP_CURRENT_TIMESTAMP_N,
- SVFOP_LOCALTIME,
- SVFOP_LOCALTIME_N,
- SVFOP_LOCALTIMESTAMP,
- SVFOP_LOCALTIMESTAMP_N
-} SQLValueFunctionOp;
-
-typedef struct SQLValueFunction
-{
- Expr xpr;
- SQLValueFunctionOp op; /* which function this is */
- Oid type; /* result type/typmod */
- int32 typmod;
- int location; /* token location, or -1 if unknown */
-} SQLValueFunction;
-
/*
* XmlExpr - various SQL/XML functions requiring special grammar productions
*
diff --git a/src/include/utils/date.h b/src/include/utils/date.h
index 0bbe889128..fad4878722 100644
--- a/src/include/utils/date.h
+++ b/src/include/utils/date.h
@@ -96,7 +96,6 @@ TimeTzADTPGetDatum(const TimeTzADT *X)
/* date.c */
-extern int32 anytime_typmod_check(bool istz, int32 typmod);
extern double date2timestamp_no_overflow(DateADT dateVal);
extern Timestamp date2timestamp_opt_overflow(DateADT dateVal, int *overflow);
extern TimestampTz date2timestamptz_opt_overflow(DateADT dateVal, int *overflow);
@@ -104,9 +103,6 @@ extern int32 date_cmp_timestamp_internal(DateADT dateVal, Timestamp dt2);
extern int32 date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2);
extern void EncodeSpecialDate(DateADT dt, char *str);
-extern DateADT GetSQLCurrentDate(void);
-extern TimeTzADT *GetSQLCurrentTime(int32 typmod);
-extern TimeADT GetSQLLocalTime(int32 typmod);
extern int time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec);
extern int timetz2tm(TimeTzADT *time, struct pg_tm *tm, fsec_t *fsec, int *tzp);
extern int tm2time(struct pg_tm *tm, fsec_t fsec, TimeADT *result);
diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h
index 76b7b4a3ca..7fd0b58825 100644
--- a/src/include/utils/timestamp.h
+++ b/src/include/utils/timestamp.h
@@ -93,11 +93,7 @@ extern PGDLLIMPORT TimestampTz PgReloadTime;
/* Internal routines (not fmgr-callable) */
-extern int32 anytimestamp_typmod_check(bool istz, int32 typmod);
-
extern TimestampTz GetCurrentTimestamp(void);
-extern TimestampTz GetSQLCurrentTimestamp(int32 typmod);
-extern Timestamp GetSQLLocalTimestamp(int32 typmod);
extern void TimestampDifference(TimestampTz start_time, TimestampTz stop_time,
long *secs, int *microsecs);
extern long TimestampDifferenceMilliseconds(TimestampTz start_time,
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 30a048f6b0..4c3b4c3f8e 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,32 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+-- Functions with SQL-mandated special syntax and some defaults.
+CREATE OR REPLACE FUNCTION
+ "current_time"(int4 DEFAULT NULL)
+RETURNS timetz
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'current_time';
+CREATE OR REPLACE FUNCTION
+ "current_timestamp"(int4 DEFAULT NULL)
+RETURNS timestamptz
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'current_timestamp';
+CREATE OR REPLACE FUNCTION
+ "localtime"(int4 DEFAULT NULL)
+RETURNS time
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'sql_localtime';
+CREATE OR REPLACE FUNCTION
+ "localtimestamp"(int4 DEFAULT NULL)
+RETURNS timestamp
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'sql_localtimestamp';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 25a94bbaaa..f9bfd79d48 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -2209,17 +2209,6 @@ ExecInitExprRec(Expr *node, ExprState *state,
break;
}
- case T_SQLValueFunction:
- {
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- scratch.opcode = EEOP_SQLVALUEFUNCTION;
- scratch.d.sqlvaluefunction.svf = svf;
-
- ExprEvalPushStep(state, &scratch);
- break;
- }
-
case T_XmlExpr:
{
XmlExpr *xexpr = (XmlExpr *) node;
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6ebf5c287e..1dab2787b7 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -452,7 +452,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
&&CASE_EEOP_DISTINCT,
&&CASE_EEOP_NOT_DISTINCT,
&&CASE_EEOP_NULLIF,
- &&CASE_EEOP_SQLVALUEFUNCTION,
&&CASE_EEOP_CURRENTOFEXPR,
&&CASE_EEOP_NEXTVALUEEXPR,
&&CASE_EEOP_ARRAYEXPR,
@@ -1301,17 +1300,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
EEO_NEXT();
}
- EEO_CASE(EEOP_SQLVALUEFUNCTION)
- {
- /*
- * Doesn't seem worthwhile to have an inline implementation
- * efficiency-wise.
- */
- ExecEvalSQLValueFunction(state, op);
-
- EEO_NEXT();
- }
-
EEO_CASE(EEOP_CURRENTOFEXPR)
{
/* error invocation uses space, and shouldn't ever occur */
@@ -2489,40 +2477,6 @@ ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
errmsg("no value found for parameter %d", paramId)));
}
-/*
- * Evaluate a SQLValueFunction expression.
- */
-void
-ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
-{
- SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
-
- *op->resnull = false;
-
- switch (svf->op)
- {
- case SVFOP_CURRENT_DATE:
- *op->resvalue = DateADTGetDatum(GetSQLCurrentDate());
- break;
- case SVFOP_CURRENT_TIME:
- case SVFOP_CURRENT_TIME_N:
- *op->resvalue = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod));
- break;
- case SVFOP_CURRENT_TIMESTAMP:
- case SVFOP_CURRENT_TIMESTAMP_N:
- *op->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod));
- break;
- case SVFOP_LOCALTIME:
- case SVFOP_LOCALTIME_N:
- *op->resvalue = TimeADTGetDatum(GetSQLLocalTime(svf->typmod));
- break;
- case SVFOP_LOCALTIMESTAMP:
- case SVFOP_LOCALTIMESTAMP_N:
- *op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
- break;
- }
-}
-
/*
* Raise error if a CURRENT OF expression is evaluated.
*
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index 95d0807bdd..f114337f8e 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -1549,12 +1549,6 @@ llvm_compile_expr(ExprState *state)
break;
}
- case EEOP_SQLVALUEFUNCTION:
- build_EvalXFunc(b, mod, "ExecEvalSQLValueFunction",
- v_state, op);
- LLVMBuildBr(b, opblocks[opno + 1]);
- break;
-
case EEOP_CURRENTOFEXPR:
build_EvalXFunc(b, mod, "ExecEvalCurrentOfExpr",
v_state, op);
diff --git a/src/backend/jit/llvm/llvmjit_types.c b/src/backend/jit/llvm/llvmjit_types.c
index 90ac6b83b5..5b416c5642 100644
--- a/src/backend/jit/llvm/llvmjit_types.c
+++ b/src/backend/jit/llvm/llvmjit_types.c
@@ -126,7 +126,6 @@ void *referenced_functions[] =
ExecEvalRow,
ExecEvalRowNotNull,
ExecEvalRowNull,
- ExecEvalSQLValueFunction,
ExecEvalScalarArrayOp,
ExecEvalHashedScalarArrayOp,
ExecEvalSubPlan,
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 4f72fc2268..af8620ceb7 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -210,9 +210,6 @@ exprType(const Node *expr)
case T_MinMaxExpr:
type = ((const MinMaxExpr *) expr)->minmaxtype;
break;
- case T_SQLValueFunction:
- type = ((const SQLValueFunction *) expr)->type;
- break;
case T_XmlExpr:
if (((const XmlExpr *) expr)->op == IS_DOCUMENT)
type = BOOLOID;
@@ -474,8 +471,6 @@ exprTypmod(const Node *expr)
return typmod;
}
break;
- case T_SQLValueFunction:
- return ((const SQLValueFunction *) expr)->typmod;
case T_CoerceToDomain:
return ((const CoerceToDomain *) expr)->resulttypmod;
case T_CoerceToDomainValue:
@@ -916,13 +911,6 @@ exprCollation(const Node *expr)
case T_MinMaxExpr:
coll = ((const MinMaxExpr *) expr)->minmaxcollid;
break;
- case T_SQLValueFunction:
- /* Returns either NAME or a non-collatable type */
- if (((const SQLValueFunction *) expr)->type == NAMEOID)
- coll = C_COLLATION_OID;
- else
- coll = InvalidOid;
- break;
case T_XmlExpr:
/*
@@ -1143,9 +1131,6 @@ exprSetCollation(Node *expr, Oid collation)
case T_MinMaxExpr:
((MinMaxExpr *) expr)->minmaxcollid = collation;
break;
- case T_SQLValueFunction:
- Assert(collation == InvalidOid);
- break;
case T_XmlExpr:
Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ?
(collation == DEFAULT_COLLATION_OID) :
@@ -1429,10 +1414,6 @@ exprLocation(const Node *expr)
/* GREATEST/LEAST keyword should always be the first thing */
loc = ((const MinMaxExpr *) expr)->location;
break;
- case T_SQLValueFunction:
- /* function keyword should always be the first thing */
- loc = ((const SQLValueFunction *) expr)->location;
- break;
case T_XmlExpr:
{
const XmlExpr *xexpr = (const XmlExpr *) expr;
@@ -1720,10 +1701,10 @@ set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
* for themselves, in case additional checks should be made, or because they
* have special rules about which parts of the tree need to be visited.
*
- * Note: we ignore MinMaxExpr, SQLValueFunction, XmlExpr, CoerceToDomain,
- * and NextValueExpr nodes, because they do not contain SQL function OIDs.
- * However, they can invoke SQL-visible functions, so callers should take
- * thought about how to treat them.
+ * Note: we ignore MinMaxExpr, XmlExpr, CoerceToDomain, and NextValueExpr
+ * nodes, because they do not contain SQL function OIDs. However, they can
+ * invoke SQL-visible functions, so callers should take thought about how
+ * to treat them.
*/
bool
check_functions_in_node(Node *node, check_function_callback checker,
@@ -1939,7 +1920,6 @@ expression_tree_walker_impl(Node *node,
case T_Const:
case T_Param:
case T_CaseTestExpr:
- case T_SQLValueFunction:
case T_CoerceToDomainValue:
case T_SetToDefault:
case T_CurrentOfExpr:
@@ -2676,7 +2656,6 @@ expression_tree_mutator_impl(Node *node,
break;
case T_Param:
case T_CaseTestExpr:
- case T_SQLValueFunction:
case T_CoerceToDomainValue:
case T_SetToDefault:
case T_CurrentOfExpr:
@@ -3590,7 +3569,6 @@ raw_expression_tree_walker_impl(Node *node,
{
case T_SetToDefault:
case T_CurrentOfExpr:
- case T_SQLValueFunction:
case T_Integer:
case T_Float:
case T_Boolean:
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index f486d42441..95659ff44a 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -4920,7 +4920,6 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
}
}
else if (IsA(node, MinMaxExpr) ||
- IsA(node, SQLValueFunction) ||
IsA(node, XmlExpr) ||
IsA(node, CoerceToDomain) ||
IsA(node, NextValueExpr))
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index bf3a7cae60..a453bc348e 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -382,12 +382,6 @@ contain_mutable_functions_walker(Node *node, void *context)
context))
return true;
- if (IsA(node, SQLValueFunction))
- {
- /* all variants of SQLValueFunction are stable */
- return true;
- }
-
if (IsA(node, NextValueExpr))
{
/* NextValueExpr is volatile */
@@ -536,8 +530,8 @@ contain_volatile_functions_walker(Node *node, void *context)
/*
* See notes in contain_mutable_functions_walker about why we treat
- * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
- * SQLValueFunction is stable. Hence, none of them are of interest here.
+ * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable. Hence, none
+ * of them are of interest here.
*/
/* Recurse to check arguments */
@@ -582,10 +576,9 @@ contain_volatile_functions_not_nextval_walker(Node *node, void *context)
/*
* See notes in contain_mutable_functions_walker about why we treat
- * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
- * SQLValueFunction is stable. Hence, none of them are of interest here.
- * Also, since we're intentionally ignoring nextval(), presumably we
- * should ignore NextValueExpr.
+ * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable. Hence, none
+ * of them are of interest here. Also, since we're intentionally
+ * ignoring nextval(), presumably we should ignore NextValueExpr.
*/
/* Recurse to check arguments */
@@ -731,8 +724,8 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
* (Note: in principle that's wrong because a domain constraint could
* contain a parallel-unsafe function; but useful constraints probably
* never would have such, and assuming they do would cripple use of
- * parallel query in the presence of domain types.) SQLValueFunction
- * should be safe in all cases. NextValueExpr is parallel-unsafe.
+ * parallel query in the presence of domain types.) NextValueExpr is
+ * parallel-unsafe.
*/
if (IsA(node, CoerceToDomain))
{
@@ -1179,7 +1172,6 @@ contain_leaked_vars_walker(Node *node, void *context)
case T_CaseExpr:
case T_CaseTestExpr:
case T_RowExpr:
- case T_SQLValueFunction:
case T_NullTest:
case T_BooleanTest:
case T_NextValueExpr:
@@ -3149,23 +3141,6 @@ eval_const_expressions_mutator(Node *node,
newcoalesce->location = coalesceexpr->location;
return (Node *) newcoalesce;
}
- case T_SQLValueFunction:
- {
- /*
- * All variants of SQLValueFunction are stable, so if we are
- * estimating the expression's value, we should evaluate the
- * current function value. Otherwise just copy.
- */
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- if (context->estimate)
- return (Node *) evaluate_expr((Expr *) svf,
- svf->type,
- svf->typmod,
- InvalidOid);
- else
- return copyObject((Node *) svf);
- }
case T_FieldSelect:
{
/*
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 23a49e99ca..0e5ccd2ede 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -198,8 +198,6 @@ static Node *makeAndExpr(Node *lexpr, Node *rexpr, int location);
static Node *makeOrExpr(Node *lexpr, Node *rexpr, int location);
static Node *makeNotExpr(Node *expr, int location);
static Node *makeAArrayExpr(List *elements, int location);
-static Node *makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod,
- int location);
static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
List *args, int location);
static List *mergeTableFuncParameters(List *func_args, List *columns);
@@ -15193,39 +15191,66 @@ func_expr_common_subexpr:
}
| CURRENT_DATE
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_DATE, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_date"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIME
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_time"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIME '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_time"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIMESTAMP
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_timestamp"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIMESTAMP '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_timestamp"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIME
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIME, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtime"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIME '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIME_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtime"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIMESTAMP
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtimestamp"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIMESTAMP '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtimestamp"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_ROLE
{
@@ -18164,18 +18189,6 @@ makeAArrayExpr(List *elements, int location)
return (Node *) n;
}
-static Node *
-makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, int location)
-{
- SQLValueFunction *svf = makeNode(SQLValueFunction);
-
- svf->op = op;
- /* svf->type will be filled during parse analysis */
- svf->typmod = typmod;
- svf->location = location;
- return (Node *) svf;
-}
-
static Node *
makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
int location)
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 9bde33b407..6b49d39c94 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -61,8 +61,6 @@ static Node *transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
static Node *transformRowExpr(ParseState *pstate, RowExpr *r, bool allowDefault);
static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c);
static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m);
-static Node *transformSQLValueFunction(ParseState *pstate,
- SQLValueFunction *svf);
static Node *transformXmlExpr(ParseState *pstate, XmlExpr *x);
static Node *transformXmlSerialize(ParseState *pstate, XmlSerialize *xs);
static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
@@ -240,11 +238,6 @@ transformExprRecurse(ParseState *pstate, Node *expr)
result = transformMinMaxExpr(pstate, (MinMaxExpr *) expr);
break;
- case T_SQLValueFunction:
- result = transformSQLValueFunction(pstate,
- (SQLValueFunction *) expr);
- break;
-
case T_XmlExpr:
result = transformXmlExpr(pstate, (XmlExpr *) expr);
break;
@@ -2191,51 +2184,6 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m)
return (Node *) newm;
}
-static Node *
-transformSQLValueFunction(ParseState *pstate, SQLValueFunction *svf)
-{
- /*
- * All we need to do is insert the correct result type and (where needed)
- * validate the typmod, so we just modify the node in-place.
- */
- switch (svf->op)
- {
- case SVFOP_CURRENT_DATE:
- svf->type = DATEOID;
- break;
- case SVFOP_CURRENT_TIME:
- svf->type = TIMETZOID;
- break;
- case SVFOP_CURRENT_TIME_N:
- svf->type = TIMETZOID;
- svf->typmod = anytime_typmod_check(true, svf->typmod);
- break;
- case SVFOP_CURRENT_TIMESTAMP:
- svf->type = TIMESTAMPTZOID;
- break;
- case SVFOP_CURRENT_TIMESTAMP_N:
- svf->type = TIMESTAMPTZOID;
- svf->typmod = anytimestamp_typmod_check(true, svf->typmod);
- break;
- case SVFOP_LOCALTIME:
- svf->type = TIMEOID;
- break;
- case SVFOP_LOCALTIME_N:
- svf->type = TIMEOID;
- svf->typmod = anytime_typmod_check(false, svf->typmod);
- break;
- case SVFOP_LOCALTIMESTAMP:
- svf->type = TIMESTAMPOID;
- break;
- case SVFOP_LOCALTIMESTAMP_N:
- svf->type = TIMESTAMPOID;
- svf->typmod = anytimestamp_typmod_check(false, svf->typmod);
- break;
- }
-
- return (Node *) svf;
-}
-
static Node *
transformXmlExpr(ParseState *pstate, XmlExpr *x)
{
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index f54591a987..8e0d6fd01f 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1872,31 +1872,6 @@ FigureColnameInternal(Node *node, char **name)
return 2;
}
break;
- case T_SQLValueFunction:
- /* make these act like a function or variable */
- switch (((SQLValueFunction *) node)->op)
- {
- case SVFOP_CURRENT_DATE:
- *name = "current_date";
- return 2;
- case SVFOP_CURRENT_TIME:
- case SVFOP_CURRENT_TIME_N:
- *name = "current_time";
- return 2;
- case SVFOP_CURRENT_TIMESTAMP:
- case SVFOP_CURRENT_TIMESTAMP_N:
- *name = "current_timestamp";
- return 2;
- case SVFOP_LOCALTIME:
- case SVFOP_LOCALTIME_N:
- *name = "localtime";
- return 2;
- case SVFOP_LOCALTIMESTAMP:
- case SVFOP_LOCALTIMESTAMP_N:
- *name = "localtimestamp";
- return 2;
- }
- break;
case T_XmlExpr:
/* make SQL/XML functions act like a regular function */
switch (((XmlExpr *) node)->op)
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index a2bdde0459..10c11e00db 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -46,27 +46,6 @@
/* common code for timetypmodin and timetztypmodin */
static int32
-anytime_typmodin(bool istz, ArrayType *ta)
-{
- int32 *tl;
- int n;
-
- tl = ArrayGetIntegerTypmods(ta, &n);
-
- /*
- * we're not too tense about good error message here because grammar
- * shouldn't allow wrong number of modifiers for TIME
- */
- if (n != 1)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("invalid type modifier")));
-
- return anytime_typmod_check(istz, tl[0]);
-}
-
-/* exported so parse_expr.c can use it */
-int32
anytime_typmod_check(bool istz, int32 typmod)
{
if (typmod < 0)
@@ -87,6 +66,26 @@ anytime_typmod_check(bool istz, int32 typmod)
return typmod;
}
+static int32
+anytime_typmodin(bool istz, ArrayType *ta)
+{
+ int32 *tl;
+ int n;
+
+ tl = ArrayGetIntegerTypmods(ta, &n);
+
+ /*
+ * we're not too tense about good error message here because grammar
+ * shouldn't allow wrong number of modifiers for TIME
+ */
+ if (n != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid type modifier")));
+
+ return anytime_typmod_check(istz, tl[0]);
+}
+
/* common code for timetypmodout and timetztypmodout */
static char *
anytime_typmodout(bool istz, int32 typmod)
@@ -296,10 +295,10 @@ EncodeSpecialDate(DateADT dt, char *str)
/*
- * GetSQLCurrentDate -- implements CURRENT_DATE
+ * current_date -- implements CURRENT_DATE
*/
-DateADT
-GetSQLCurrentDate(void)
+Datum
+current_date(PG_FUNCTION_ARGS)
{
struct pg_tm tm;
@@ -325,46 +324,62 @@ GetSQLCurrentDate(void)
cache_mday = tm.tm_mday;
}
- return cache_date;
+ return DateADTGetDatum(cache_date);
}
/*
- * GetSQLCurrentTime -- implements CURRENT_TIME, CURRENT_TIME(n)
+ * current_time -- implements CURRENT_TIME, CURRENT_TIME(n)
*/
-TimeTzADT *
-GetSQLCurrentTime(int32 typmod)
+Datum
+current_time(PG_FUNCTION_ARGS)
{
TimeTzADT *result;
struct pg_tm tt,
*tm = &tt;
fsec_t fsec;
int tz;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytime_typmod_check(true, typmod);
+ }
GetCurrentTimeUsec(tm, &fsec, &tz);
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
tm2timetz(tm, fsec, tz, result);
AdjustTimeForTypmod(&(result->time), typmod);
- return result;
+
+ return TimeTzADTPGetDatum(result);
}
/*
- * GetSQLLocalTime -- implements LOCALTIME, LOCALTIME(n)
+ * sql_localtime -- implements LOCALTIME, LOCALTIME(n)
*/
-TimeADT
-GetSQLLocalTime(int32 typmod)
+Datum
+sql_localtime(PG_FUNCTION_ARGS)
{
TimeADT result;
struct pg_tm tt,
*tm = &tt;
fsec_t fsec;
int tz;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytime_typmod_check(false, typmod);
+ }
GetCurrentTimeUsec(tm, &fsec, &tz);
tm2time(tm, fsec, &result);
AdjustTimeForTypmod(&result, typmod);
- return result;
+
+ return TimeADTGetDatum(result);
}
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 9987bca912..6d6f9ab4fb 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -8179,7 +8179,6 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_RowExpr:
case T_CoalesceExpr:
case T_MinMaxExpr:
- case T_SQLValueFunction:
case T_XmlExpr:
case T_NextValueExpr:
case T_NullIfExpr:
@@ -9159,49 +9158,6 @@ get_rule_expr(Node *node, deparse_context *context,
}
break;
- case T_SQLValueFunction:
- {
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- /*
- * Note: this code knows that typmod for time, timestamp, and
- * timestamptz just prints as integer.
- */
- switch (svf->op)
- {
- case SVFOP_CURRENT_DATE:
- appendStringInfoString(buf, "CURRENT_DATE");
- break;
- case SVFOP_CURRENT_TIME:
- appendStringInfoString(buf, "CURRENT_TIME");
- break;
- case SVFOP_CURRENT_TIME_N:
- appendStringInfo(buf, "CURRENT_TIME(%d)", svf->typmod);
- break;
- case SVFOP_CURRENT_TIMESTAMP:
- appendStringInfoString(buf, "CURRENT_TIMESTAMP");
- break;
- case SVFOP_CURRENT_TIMESTAMP_N:
- appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)",
- svf->typmod);
- break;
- case SVFOP_LOCALTIME:
- appendStringInfoString(buf, "LOCALTIME");
- break;
- case SVFOP_LOCALTIME_N:
- appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod);
- break;
- case SVFOP_LOCALTIMESTAMP:
- appendStringInfoString(buf, "LOCALTIMESTAMP");
- break;
- case SVFOP_LOCALTIMESTAMP_N:
- appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
- svf->typmod);
- break;
- }
- }
- break;
-
case T_XmlExpr:
{
XmlExpr *xexpr = (XmlExpr *) node;
@@ -9727,7 +9683,6 @@ looks_like_function(Node *node)
case T_NullIfExpr:
case T_CoalesceExpr:
case T_MinMaxExpr:
- case T_SQLValueFunction:
case T_XmlExpr:
/* these are all accepted by func_expr_common_subexpr */
return true;
@@ -10321,6 +10276,70 @@ get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
appendStringInfoString(buf, "SYSTEM_USER");
return true;
+ case F_CURRENT_DATE:
+ appendStringInfoString(buf, "CURRENT_DATE");
+ return true;
+ case F_CURRENT_TIME:
+ appendStringInfoString(buf, "CURRENT_TIME");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+ case F_CURRENT_TIMESTAMP:
+ appendStringInfoString(buf, "CURRENT_TIMESTAMP");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+ case F_LOCALTIME:
+ appendStringInfoString(buf, "LOCALTIME");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+ case F_LOCALTIMESTAMP:
+ appendStringInfoString(buf, "LOCALTIMESTAMP");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+
case F_XMLEXISTS:
/* XMLEXISTS ... extra parens because args are c_expr */
appendStringInfoString(buf, "XMLEXISTS((");
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 9799647e1a..80e441f5ce 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -81,27 +81,6 @@ static Timestamp timestamptz2timestamp(TimestampTz timestamp);
/* common code for timestamptypmodin and timestamptztypmodin */
static int32
-anytimestamp_typmodin(bool istz, ArrayType *ta)
-{
- int32 *tl;
- int n;
-
- tl = ArrayGetIntegerTypmods(ta, &n);
-
- /*
- * we're not too tense about good error message here because grammar
- * shouldn't allow wrong number of modifiers for TIMESTAMP
- */
- if (n != 1)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("invalid type modifier")));
-
- return anytimestamp_typmod_check(istz, tl[0]);
-}
-
-/* exported so parse_expr.c can use it */
-int32
anytimestamp_typmod_check(bool istz, int32 typmod)
{
if (typmod < 0)
@@ -122,6 +101,26 @@ anytimestamp_typmod_check(bool istz, int32 typmod)
return typmod;
}
+static int32
+anytimestamp_typmodin(bool istz, ArrayType *ta)
+{
+ int32 *tl;
+ int n;
+
+ tl = ArrayGetIntegerTypmods(ta, &n);
+
+ /*
+ * we're not too tense about good error message here because grammar
+ * shouldn't allow wrong number of modifiers for TIMESTAMP
+ */
+ if (n != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid type modifier")));
+
+ return anytimestamp_typmod_check(istz, tl[0]);
+}
+
/* common code for timestamptypmodout and timestamptztypmodout */
static char *
anytimestamp_typmodout(bool istz, int32 typmod)
@@ -1586,33 +1585,48 @@ GetCurrentTimestamp(void)
}
/*
- * GetSQLCurrentTimestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
+ * current_timestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
*/
-TimestampTz
-GetSQLCurrentTimestamp(int32 typmod)
+Datum
+current_timestamp(PG_FUNCTION_ARGS)
{
TimestampTz ts;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytimestamp_typmod_check(true, typmod);
+ }
ts = GetCurrentTransactionStartTimestamp();
if (typmod >= 0)
AdjustTimestampForTypmod(&ts, typmod);
- return ts;
+ return TimestampTzGetDatum(ts);
}
/*
- * GetSQLLocalTimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
+ * sql_localtimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
*/
-Timestamp
-GetSQLLocalTimestamp(int32 typmod)
+Datum
+sql_localtimestamp(PG_FUNCTION_ARGS)
{
Timestamp ts;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytimestamp_typmod_check(false, typmod);
+ }
ts = timestamptz2timestamp(GetCurrentTransactionStartTimestamp());
if (typmod >= 0)
AdjustTimestampForTypmod(&ts, typmod);
- return ts;
+ return TimestampGetDatum(ts);
}
+
/*
* timeofday(*) -- returns the current time as a text.
*/
diff --git a/src/backend/utils/misc/queryjumble.c b/src/backend/utils/misc/queryjumble.c
index a8508463e7..0ace74de78 100644
--- a/src/backend/utils/misc/queryjumble.c
+++ b/src/backend/utils/misc/queryjumble.c
@@ -606,15 +606,6 @@ JumbleExpr(JumbleState *jstate, Node *node)
JumbleExpr(jstate, (Node *) mmexpr->args);
}
break;
- case T_SQLValueFunction:
- {
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- APP_JUMB(svf->op);
- /* type is fully determined by op */
- APP_JUMB(svf->typmod);
- }
- break;
case T_XmlExpr:
{
XmlExpr *xexpr = (XmlExpr *) node;
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index 77123cecbd..ffb38d80f9 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -1941,6 +1941,15 @@ select
trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea) as btb,
trim(leading E'\\000'::bytea from E'\\000Tom\\000'::bytea) as ltb,
trim(trailing E'\\000'::bytea from E'\\000Tom\\000'::bytea) as rtb,
+ CURRENT_DATE as cd,
+ CURRENT_TIME as ct,
+ CURRENT_TIME (1) as ct2,
+ CURRENT_TIMESTAMP as ct3,
+ CURRENT_TIMESTAMP (1) as ct4,
+ LOCALTIME as lt1,
+ LOCALTIME (1) as lt2,
+ LOCALTIMESTAMP as lt3,
+ LOCALTIMESTAMP (1) as lt4,
CURRENT_CATALOG as ca,
CURRENT_ROLE as cr,
CURRENT_SCHEMA as cs,
@@ -1969,6 +1978,15 @@ select pg_get_viewdef('tt201v', true);
TRIM(BOTH '\x00'::bytea FROM '\x00546f6d00'::bytea) AS btb, +
TRIM(LEADING '\x00'::bytea FROM '\x00546f6d00'::bytea) AS ltb, +
TRIM(TRAILING '\x00'::bytea FROM '\x00546f6d00'::bytea) AS rtb, +
+ CURRENT_DATE AS cd, +
+ CURRENT_TIME AS ct, +
+ CURRENT_TIME(1) AS ct2, +
+ CURRENT_TIMESTAMP AS ct3, +
+ CURRENT_TIMESTAMP(1) AS ct4, +
+ LOCALTIME AS lt1, +
+ LOCALTIME(1) AS lt2, +
+ LOCALTIMESTAMP AS lt3, +
+ LOCALTIMESTAMP(1) AS lt4, +
CURRENT_CATALOG AS ca, +
CURRENT_ROLE AS cr, +
CURRENT_SCHEMA AS cs, +
diff --git a/src/test/regress/expected/expressions.out b/src/test/regress/expected/expressions.out
index 5bf39fd9aa..28a20900f1 100644
--- a/src/test/regress/expected/expressions.out
+++ b/src/test/regress/expected/expressions.out
@@ -2,7 +2,7 @@
-- expression evaluation tests that don't fit into a more specific file
--
--
--- Tests for SQLValueFunction
+-- Tests for various FuncCalls with COERCE_SQL_SYNTAX.
--
-- current_date (always matches because of transactional behaviour)
SELECT date(now())::text = current_date::text;
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index ccaebdc22b..b99c96295d 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -722,6 +722,15 @@ select
trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea) as btb,
trim(leading E'\\000'::bytea from E'\\000Tom\\000'::bytea) as ltb,
trim(trailing E'\\000'::bytea from E'\\000Tom\\000'::bytea) as rtb,
+ CURRENT_DATE as cd,
+ CURRENT_TIME as ct,
+ CURRENT_TIME (1) as ct2,
+ CURRENT_TIMESTAMP as ct3,
+ CURRENT_TIMESTAMP (1) as ct4,
+ LOCALTIME as lt1,
+ LOCALTIME (1) as lt2,
+ LOCALTIMESTAMP as lt3,
+ LOCALTIMESTAMP (1) as lt4,
CURRENT_CATALOG as ca,
CURRENT_ROLE as cr,
CURRENT_SCHEMA as cs,
diff --git a/src/test/regress/sql/expressions.sql b/src/test/regress/sql/expressions.sql
index 0e163cc0d7..f9a0299d17 100644
--- a/src/test/regress/sql/expressions.sql
+++ b/src/test/regress/sql/expressions.sql
@@ -3,7 +3,7 @@
--
--
--- Tests for SQLValueFunction
+-- Tests for various FuncCalls with COERCE_SQL_SYNTAX.
--
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 97c9bc1861..9a04f785cd 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2397,8 +2397,6 @@ SQLFunctionCache
SQLFunctionCachePtr
SQLFunctionParseInfo
SQLFunctionParseInfoPtr
-SQLValueFunction
-SQLValueFunctionOp
SSL
SSLExtensionInfoContext
SSL_CTX
--
2.37.2
On Fri, Sep 30, 2022 at 2:04 AM Michael Paquier <michael@paquier.xyz> wrote:
Hi all,
I have bumped a few days ago on the fact that COERCE_SQL_SYNTAX
(introduced by 40c24bf) and SQLValueFunction are around to do the
exact same thing, as known as enforcing single-function calls with
dedicated SQL keywords. For example, keywords like SESSION_USER,
CURRENT_DATE, etc. go through SQLValueFunction and rely on the parser
to set a state that gets then used in execExprInterp.c. And it is
rather easy to implement incorrect SQLValueFunctions, as these rely on
more hardcoded assumptions in the parser and executor than the
equivalent FuncCalls (like collation to assign when using a text-like
SQLValueFunctions).There are two categories of single-value functions:
- The ones returning names, where we enforce a C collation in two
places of the code (current_role, role, current_catalog,
current_schema, current_database, current_user), even if
get_typcollation() should do that for name types.
- The ones working on time, date and timestamps (localtime[stamp],
current_date, current_time[stamp]), for 9 patterns as these accept an
optional typmod.I have dug into the possibility to unify all that with a single
interface, and finish with the attached patch set which is a reduction
of code, where all the SQLValueFunctions are replaced by a set of
FuncCalls:
25 files changed, 338 insertions(+), 477 deletions(-)0001 is the move done for the name-related functions, cleaning up two
places in the executor when a C collation is assigned to those
function expressions. 0002 is the remaining cleanup for the
time-related ones, moving a set of parser-side checks to the execution
path within each function, so as all this knowledge is now local to
each file holding the date and timestamp types. Most of the gain is
in 0002, obviously.The pg_proc entries introduced for the sake of the move use the same
name as the SQL keywords. These should perhaps be prefixed with a
"pg_" at least. There would be an exception with pg_localtime[stamp],
though, where we could use a pg_localtime[stamp]_sql for the function
name for prosrc. I am open to suggestions for these names.Thoughts?
--
Michael
I like this a lot. Deleted code is debugged code.
Patch applies and passes make check-world.
No trace of SQLValueFunction is left in the codebase, at least according to
`git grep -l`.
I have only one non-nitpick question about the code:
+ /*
+ * we're not too tense about good error message here because grammar
+ * shouldn't allow wrong number of modifiers for TIME
+ */
+ if (n != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid type modifier")));
I agree that we shouldn't spend too much effort on a good error message
here, but perhaps we should have the message mention that it is
date/time-related? A person git-grepping for this error message will get 4
hits in .c files (date.c, timestamp.c, varbit.c, varchar.c) so even a
slight variation in the message could save them some time.
This is an extreme nitpick, but the patchset seems like it should have been
1 file or 3 (remove name functions, remove time functions, remove
SQLValueFunction infrastructure), but that will only matter in the unlikely
case that we find a need for SQLValueFunction but we want to leave the
timestamp function as COERCE_SQL_SYNTAX.
(Adding Tom in CC, in case.)
On Tue, Oct 18, 2022 at 04:35:33PM -0400, Corey Huinker wrote:
I agree that we shouldn't spend too much effort on a good error message
here, but perhaps we should have the message mention that it is
date/time-related? A person git-grepping for this error message will get 4
hits in .c files (date.c, timestamp.c, varbit.c, varchar.c) so even a
slight variation in the message could save them some time.
The message is the same between HEAD and the patch and these have been
around for a long time, except that we would see it at parsing time on
HEAD, and at executor time with the patch. I would not mind changing
if there are better ideas than what's used now, of course ;)
This is an extreme nitpick, but the patchset seems like it should have been
1 file or 3 (remove name functions, remove time functions, remove
SQLValueFunction infrastructure), but that will only matter in the unlikely
case that we find a need for SQLValueFunction but we want to leave the
timestamp function as COERCE_SQL_SYNTAX.
Once the timestamp functions are removed, SQLValueFunction is just
dead code so including its removal in 0002 does not change much in my
opinion.
An other thing I had on my list for this patch was to check its
performance impact. So I have spent some time having a look at the
perf profiles produced on HEAD and with the patch using queries like
SELECT current_role FROM generate_series(1,N) where N > 10M and I have
not noticed any major differences in runtime or in the profiles, at
the difference that we don't have anymore SQLValueFunction() and its
internal functions called, hence they are missing from the stacks, but
that's the whole point of the patch.
With this in mind, would somebody complain if I commit that? That's a
nice reduction in code, while completing the work done in 40c24bf:
25 files changed, 338 insertions(+), 477 deletions(-)
Thanks,
--
Michael
On Wed, Oct 19, 2022 at 03:45:48PM +0900, Michael Paquier wrote:
With this in mind, would somebody complain if I commit that? That's a
nice reduction in code, while completing the work done in 40c24bf:
25 files changed, 338 insertions(+), 477 deletions(-)
On second look, there is something I have underestimated here with
FigureColnameInternal(). This function would create an attribute name
based on the SQL keyword given in input. For example, on HEAD we
would get that:
=# SELECT * FROM CURRENT_CATALOG;
current_catalog
-----------------
postgres
(1 row)
But the patch enforces the attribute name to be the underlying
function name, switching the previous "current_catalog" to
"current_database". For example:
=# SELECT * FROM CURRENT_CATALOG;
current_database
------------------
postgres
(1 row)
I am not sure how much it matters in practice, but this could break
some queries. One way to tackle that is to extend
FigureColnameInternal() so as we use a compatible name when the node
is a T_FuncCall, but that won't be entirely water-proof as long as
there is not a one-one mapping between the SQL keywords and the
underlying function names, aka we would need a current_catalog.
"user" would be also too generic as a catalog function name, so we
should name its proc entry to a pg_user anyway, requiring a shortcut
in FigureColnameInternal(). Or perhaps I am worrying too much and
keeping the code simpler is better? Does the SQL specification
require that the attribute name has to match its SQL keyword when
specified in a FROM clause when there is no aliases?
Thoughts?
--
Michael
Michael Paquier <michael@paquier.xyz> writes:
But the patch enforces the attribute name to be the underlying
function name, switching the previous "current_catalog" to
"current_database".
The entire point of SQLValueFunction IMO was to hide the underlying
implementation(s). Replacing it with something that leaks
implementation details does not seem like a step forward.
regards, tom lane
On Thu, Oct 20, 2022 at 11:10:22PM -0400, Tom Lane wrote:
The entire point of SQLValueFunction IMO was to hide the underlying
implementation(s). Replacing it with something that leaks
implementation details does not seem like a step forward.
Hmm.. Okay, thanks. So this just comes down that I am going to need
one different pg_proc entry per SQL keyword, then, or this won't fly
far. For example, note that on HEAD or with the patch, a view with a
SQL keyword in a FROM clause translates the same way with quotes
applied in the same places, as of:
=# create view test as select (SELECT * FROM CURRENT_USER) as cu;
CREATE VIEW
=# select pg_get_viewdef('test', true);
pg_get_viewdef
---------------------------------------------------------------------
SELECT ( SELECT "current_user"."current_user" +
FROM CURRENT_USER "current_user"("current_user")) AS cu;
(1 row)
A sticky point is that this would need the creation of a pg_proc entry
for "user" which is a generic word, or a shortcut around
FigureColnameInternal(). The code gain overall still looks appealing
in the executor, even if we do all that and the resulting backend code
gets kind of nicer and easier to maintain long-term IMO.
--
Michael
On Fri, Oct 21, 2022 at 12:34:23PM +0900, Michael Paquier wrote:
A sticky point is that this would need the creation of a pg_proc entry
for "user" which is a generic word, or a shortcut around
FigureColnameInternal(). The code gain overall still looks appealing
in the executor, even if we do all that and the resulting backend code
gets kind of nicer and easier to maintain long-term IMO.
I have looked at that, and the attribute mapping remains compatible
with past versions once the appropriate pg_proc entries are added.
The updated patch set attached does that (with a user() function as
well to keep the code a maximum simple), with more tests to cover the
attribute case mentioned upthread.
--
Michael
Attachments:
v2-0001-Remove-from-SQLValueFunction-all-the-entries-usin.patchtext/x-diff; charset=us-asciiDownload
From 8d1a424e44f46f3107a6f0f066da22c19e4e4f3b Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Fri, 21 Oct 2022 14:06:03 +0900
Subject: [PATCH v2 1/2] Remove from SQLValueFunction all the entries using
"name" as return type
This commit changes six SQL keywords to use COERCE_SQL_SYNTAX rather
than SQLValueFunction:
- CURRENT_ROLE
- CURRENT_USER
- USER
- SESSION_USER
- CURRENT_CATALOG
- CURRENT_SCHEMA
Among the six, "user", "current_role" and "current_catalog" require
specific SQL functions to allow ruleutils.c to map them to the SQL
keywords these require when using COERCE_SQL_SYNTAX. Having
pg_proc.proname match with the keyword ensures that the compatibility
remains the same when projecting any of these keywords in a FROM clause
to an attribute name when an alias is not specified. Tests are added to
make sure that the mapping happens from the SQL keyword is correct,
using a view defition that feeds on these keywords in one of the tests
introduced by 40c24bf (both in a SELECT clause and when using each
keyword in a FROM clause).
SQLValueFunction is reduced to half its contents after this change,
simplifying its logic a bit as there is no need to enforce a C collation
anymore. I have made a few performance tests, with a million-ish calls
to these keywords without seeing a difference in run-time or in perf
profiles. The remaining SQLValueFunctions relate to timestamps.
Bump catalog version.
Reviewed-by: Corey Huinker
Discussion: https://postgr.es/m/YzaG3MoryCguUOym@paquier.xyz
---
src/include/catalog/catversion.h | 2 +-
src/include/catalog/pg_proc.dat | 9 ++++++
src/include/nodes/primnodes.h | 8 +----
src/backend/executor/execExprInterp.c | 27 -----------------
src/backend/nodes/nodeFuncs.c | 11 ++-----
src/backend/parser/gram.y | 30 ++++++++++++++----
src/backend/parser/parse_expr.c | 8 -----
src/backend/parser/parse_target.c | 18 -----------
src/backend/utils/adt/ruleutils.c | 36 +++++++++++-----------
src/test/regress/expected/create_view.out | 37 +++++++++++++++++++++--
src/test/regress/sql/create_view.sql | 15 ++++++++-
11 files changed, 105 insertions(+), 96 deletions(-)
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 4c930c189b..032a429345 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -57,6 +57,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202210141
+#define CATALOG_VERSION_NO 202210211
#endif
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 62a5b8e655..241366fc8e 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -1505,6 +1505,15 @@
{ oid => '745', descr => 'current user name',
proname => 'current_user', provolatile => 's', prorettype => 'name',
proargtypes => '', prosrc => 'current_user' },
+{ oid => '9695', descr => 'current role name',
+ proname => 'current_role', provolatile => 's', prorettype => 'name',
+ proargtypes => '', prosrc => 'current_user' },
+{ oid => '9696', descr => 'user name',
+ proname => 'user', provolatile => 's', prorettype => 'name',
+ proargtypes => '', prosrc => 'current_user' },
+{ oid => '9697', descr => 'name of the current database',
+ proname => 'current_catalog', provolatile => 's', prorettype => 'name',
+ proargtypes => '', prosrc => 'current_database' },
{ oid => '746', descr => 'session user name',
proname => 'session_user', provolatile => 's', prorettype => 'name',
proargtypes => '', prosrc => 'session_user' },
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 40661334bb..e818231e15 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1313,13 +1313,7 @@ typedef enum SQLValueFunctionOp
SVFOP_LOCALTIME,
SVFOP_LOCALTIME_N,
SVFOP_LOCALTIMESTAMP,
- SVFOP_LOCALTIMESTAMP_N,
- SVFOP_CURRENT_ROLE,
- SVFOP_CURRENT_USER,
- SVFOP_USER,
- SVFOP_SESSION_USER,
- SVFOP_CURRENT_CATALOG,
- SVFOP_CURRENT_SCHEMA
+ SVFOP_LOCALTIMESTAMP_N
} SQLValueFunctionOp;
typedef struct SQLValueFunction
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 9b9bbf00a9..6ebf5c287e 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -2495,15 +2495,10 @@ ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
void
ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
{
- LOCAL_FCINFO(fcinfo, 0);
SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
*op->resnull = false;
- /*
- * Note: current_schema() can return NULL. current_user() etc currently
- * cannot, but might as well code those cases the same way for safety.
- */
switch (svf->op)
{
case SVFOP_CURRENT_DATE:
@@ -2525,28 +2520,6 @@ ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
case SVFOP_LOCALTIMESTAMP_N:
*op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
break;
- case SVFOP_CURRENT_ROLE:
- case SVFOP_CURRENT_USER:
- case SVFOP_USER:
- InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
- *op->resvalue = current_user(fcinfo);
- *op->resnull = fcinfo->isnull;
- break;
- case SVFOP_SESSION_USER:
- InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
- *op->resvalue = session_user(fcinfo);
- *op->resnull = fcinfo->isnull;
- break;
- case SVFOP_CURRENT_CATALOG:
- InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
- *op->resvalue = current_database(fcinfo);
- *op->resnull = fcinfo->isnull;
- break;
- case SVFOP_CURRENT_SCHEMA:
- InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
- *op->resvalue = current_schema(fcinfo);
- *op->resnull = fcinfo->isnull;
- break;
}
}
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 0a7b22f97e..2585a3175c 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -917,11 +917,8 @@ exprCollation(const Node *expr)
coll = ((const MinMaxExpr *) expr)->minmaxcollid;
break;
case T_SQLValueFunction:
- /* Returns either NAME or a non-collatable type */
- if (((const SQLValueFunction *) expr)->type == NAMEOID)
- coll = C_COLLATION_OID;
- else
- coll = InvalidOid;
+ /* Returns a non-collatable type */
+ coll = InvalidOid;
break;
case T_XmlExpr:
@@ -1144,9 +1141,7 @@ exprSetCollation(Node *expr, Oid collation)
((MinMaxExpr *) expr)->minmaxcollid = collation;
break;
case T_SQLValueFunction:
- Assert((((SQLValueFunction *) expr)->type == NAMEOID) ?
- (collation == C_COLLATION_OID) :
- (collation == InvalidOid));
+ Assert(collation == InvalidOid);
break;
case T_XmlExpr:
Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ?
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 737bd2d06d..605e9ec096 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -15229,15 +15229,24 @@ func_expr_common_subexpr:
}
| CURRENT_ROLE
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_ROLE, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_role"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_USER
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_USER, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_user"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| SESSION_USER
{
- $$ = makeSQLValueFunction(SVFOP_SESSION_USER, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("session_user"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| SYSTEM_USER
{
@@ -15248,15 +15257,24 @@ func_expr_common_subexpr:
}
| USER
{
- $$ = makeSQLValueFunction(SVFOP_USER, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("user"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_CATALOG
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_CATALOG, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_catalog"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_SCHEMA
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_SCHEMA, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_schema"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CAST '(' a_expr AS Typename ')'
{ $$ = makeTypeCast($3, $5, @1); }
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 7aaf1c673f..9bde33b407 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -2231,14 +2231,6 @@ transformSQLValueFunction(ParseState *pstate, SQLValueFunction *svf)
svf->type = TIMESTAMPOID;
svf->typmod = anytimestamp_typmod_check(false, svf->typmod);
break;
- case SVFOP_CURRENT_ROLE:
- case SVFOP_CURRENT_USER:
- case SVFOP_USER:
- case SVFOP_SESSION_USER:
- case SVFOP_CURRENT_CATALOG:
- case SVFOP_CURRENT_SCHEMA:
- svf->type = NAMEOID;
- break;
}
return (Node *) svf;
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index bd8057bc3e..f54591a987 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1895,24 +1895,6 @@ FigureColnameInternal(Node *node, char **name)
case SVFOP_LOCALTIMESTAMP_N:
*name = "localtimestamp";
return 2;
- case SVFOP_CURRENT_ROLE:
- *name = "current_role";
- return 2;
- case SVFOP_CURRENT_USER:
- *name = "current_user";
- return 2;
- case SVFOP_USER:
- *name = "user";
- return 2;
- case SVFOP_SESSION_USER:
- *name = "session_user";
- return 2;
- case SVFOP_CURRENT_CATALOG:
- *name = "current_catalog";
- return 2;
- case SVFOP_CURRENT_SCHEMA:
- *name = "current_schema";
- return 2;
}
break;
case T_XmlExpr:
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 70d723e80c..f95289f11c 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -9199,24 +9199,6 @@ get_rule_expr(Node *node, deparse_context *context,
appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
svf->typmod);
break;
- case SVFOP_CURRENT_ROLE:
- appendStringInfoString(buf, "CURRENT_ROLE");
- break;
- case SVFOP_CURRENT_USER:
- appendStringInfoString(buf, "CURRENT_USER");
- break;
- case SVFOP_USER:
- appendStringInfoString(buf, "USER");
- break;
- case SVFOP_SESSION_USER:
- appendStringInfoString(buf, "SESSION_USER");
- break;
- case SVFOP_CURRENT_CATALOG:
- appendStringInfoString(buf, "CURRENT_CATALOG");
- break;
- case SVFOP_CURRENT_SCHEMA:
- appendStringInfoString(buf, "CURRENT_SCHEMA");
- break;
}
}
break;
@@ -10318,6 +10300,24 @@ get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
appendStringInfoChar(buf, ')');
return true;
+ case F_CURRENT_CATALOG:
+ appendStringInfoString(buf, "CURRENT_CATALOG");
+ return true;
+ case F_CURRENT_ROLE:
+ appendStringInfoString(buf, "CURRENT_ROLE");
+ return true;
+ case F_CURRENT_SCHEMA:
+ appendStringInfoString(buf, "CURRENT_SCHEMA");
+ return true;
+ case F_CURRENT_USER:
+ appendStringInfoString(buf, "CURRENT_USER");
+ return true;
+ case F_USER:
+ appendStringInfoString(buf, "USER");
+ return true;
+ case F_SESSION_USER:
+ appendStringInfoString(buf, "SESSION_USER");
+ return true;
case F_SYSTEM_USER:
appendStringInfoString(buf, "SYSTEM_USER");
return true;
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index bf4ff30d86..e7f7323113 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -1941,7 +1941,20 @@ select
trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea) as btb,
trim(leading E'\\000'::bytea from E'\\000Tom\\000'::bytea) as ltb,
trim(trailing E'\\000'::bytea from E'\\000Tom\\000'::bytea) as rtb,
- SYSTEM_USER as su;
+ CURRENT_CATALOG as ca,
+ (select * from CURRENT_CATALOG) as ca2,
+ CURRENT_ROLE as cr,
+ (select * from CURRENT_ROLE) as cr2,
+ CURRENT_SCHEMA as cs,
+ (select * from CURRENT_SCHEMA) as cs2,
+ CURRENT_USER as cu,
+ (select * from CURRENT_USER) as cu2,
+ USER as us,
+ (select * from USER) as us2,
+ SESSION_USER seu,
+ (select * from SESSION_USER) as seu2,
+ SYSTEM_USER as su,
+ (select * from SYSTEM_USER) as su2;
select pg_get_viewdef('tt201v', true);
pg_get_viewdef
-----------------------------------------------------------------------------------------------
@@ -1963,7 +1976,27 @@ select pg_get_viewdef('tt201v', true);
TRIM(BOTH '\x00'::bytea FROM '\x00546f6d00'::bytea) AS btb, +
TRIM(LEADING '\x00'::bytea FROM '\x00546f6d00'::bytea) AS ltb, +
TRIM(TRAILING '\x00'::bytea FROM '\x00546f6d00'::bytea) AS rtb, +
- SYSTEM_USER AS su;
+ CURRENT_CATALOG AS ca, +
+ ( SELECT "current_catalog"."current_catalog" +
+ FROM CURRENT_CATALOG "current_catalog"("current_catalog")) AS ca2, +
+ CURRENT_ROLE AS cr, +
+ ( SELECT "current_role"."current_role" +
+ FROM CURRENT_ROLE "current_role"("current_role")) AS cr2, +
+ CURRENT_SCHEMA AS cs, +
+ ( SELECT "current_schema"."current_schema" +
+ FROM CURRENT_SCHEMA "current_schema"("current_schema")) AS cs2, +
+ CURRENT_USER AS cu, +
+ ( SELECT "current_user"."current_user" +
+ FROM CURRENT_USER "current_user"("current_user")) AS cu2, +
+ USER AS us, +
+ ( SELECT "user"."user" +
+ FROM USER "user"("user")) AS us2, +
+ SESSION_USER AS seu, +
+ ( SELECT "session_user"."session_user" +
+ FROM SESSION_USER "session_user"("session_user")) AS seu2, +
+ SYSTEM_USER AS su, +
+ ( SELECT "system_user"."system_user" +
+ FROM SYSTEM_USER "system_user"("system_user")) AS su2;
(1 row)
-- corner cases with empty join conditions
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index 913b4ee460..04fc0ba35e 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -722,7 +722,20 @@ select
trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea) as btb,
trim(leading E'\\000'::bytea from E'\\000Tom\\000'::bytea) as ltb,
trim(trailing E'\\000'::bytea from E'\\000Tom\\000'::bytea) as rtb,
- SYSTEM_USER as su;
+ CURRENT_CATALOG as ca,
+ (select * from CURRENT_CATALOG) as ca2,
+ CURRENT_ROLE as cr,
+ (select * from CURRENT_ROLE) as cr2,
+ CURRENT_SCHEMA as cs,
+ (select * from CURRENT_SCHEMA) as cs2,
+ CURRENT_USER as cu,
+ (select * from CURRENT_USER) as cu2,
+ USER as us,
+ (select * from USER) as us2,
+ SESSION_USER seu,
+ (select * from SESSION_USER) as seu2,
+ SYSTEM_USER as su,
+ (select * from SYSTEM_USER) as su2;
select pg_get_viewdef('tt201v', true);
-- corner cases with empty join conditions
--
2.37.2
v2-0002-Replace-SQLValueFunction-by-direct-function-calls.patchtext/x-diff; charset=us-asciiDownload
From 9f5bb5ba425f923ab9286b810594b2c312739ffa Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Fri, 21 Oct 2022 14:19:41 +0900
Subject: [PATCH v2 2/2] Replace SQLValueFunction by direct function calls
This impacts 9 patterns where the SQL grammar takes priority:
- localtime, that can take a typmod.
- localtimestamp, that can take a typmod.
- current_time, that can take a typmod.
- current_timestamp, that can take a typmod.
- current_date.
Five new entries are added to pg_proc to compensate the removal of
SQLValueFunction to keep compatibility (when a keyword is specified in a
SELECT or in a FROM clause without an alias), with tests to cover all
that.
XXX: bump catalog version.
Reviewed-by: Corey Huinker
Discussion: https://postgr.es/m/YzaG3MoryCguUOym@paquier.xyz
---
src/include/catalog/pg_proc.dat | 15 +++
src/include/executor/execExpr.h | 8 --
src/include/nodes/primnodes.h | 33 -------
src/include/utils/date.h | 4 -
src/include/utils/timestamp.h | 4 -
src/backend/catalog/system_functions.sql | 26 ++++++
src/backend/executor/execExpr.c | 11 ---
src/backend/executor/execExprInterp.c | 46 ---------
src/backend/jit/llvm/llvmjit_expr.c | 6 --
src/backend/jit/llvm/llvmjit_types.c | 1 -
src/backend/nodes/nodeFuncs.c | 27 +-----
src/backend/optimizer/path/costsize.c | 1 -
src/backend/optimizer/util/clauses.c | 39 ++------
src/backend/parser/gram.y | 59 +++++++-----
src/backend/parser/parse_expr.c | 52 -----------
src/backend/parser/parse_target.c | 25 -----
src/backend/utils/adt/date.c | 81 +++++++++-------
src/backend/utils/adt/ruleutils.c | 109 +++++++++++++---------
src/backend/utils/adt/timestamp.c | 72 ++++++++------
src/backend/utils/misc/queryjumble.c | 9 --
src/test/regress/expected/create_view.out | 45 +++++++++
src/test/regress/expected/expressions.out | 2 +-
src/test/regress/sql/create_view.sql | 18 ++++
src/test/regress/sql/expressions.sql | 2 +-
src/tools/pgindent/typedefs.list | 2 -
25 files changed, 308 insertions(+), 389 deletions(-)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 241366fc8e..081419d065 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -1520,6 +1520,21 @@
{ oid => '9977', descr => 'system user name',
proname => 'system_user', provolatile => 's', prorettype => 'text',
proargtypes => '', prosrc => 'system_user' },
+{ oid => '9978', descr => 'current date',
+ proname => 'current_date', provolatile => 's', prorettype => 'date',
+ proargtypes => '', prosrc => 'current_date' },
+{ oid => '9979', descr => 'current time',
+ proname => 'current_time', provolatile => 's', prorettype => 'timetz',
+ proargtypes => 'int4', prosrc => 'current_time', proisstrict => 'f' },
+{ oid => '9980', descr => 'current timestamp',
+ proname => 'current_timestamp', provolatile => 's', prorettype => 'timestamptz',
+ proargtypes => 'int4', prosrc => 'current_timestamp', proisstrict => 'f' },
+{ oid => '9981', descr => 'local time',
+ proname => 'localtime', provolatile => 's', prorettype => 'time',
+ proargtypes => 'int4', prosrc => 'sql_localtime', proisstrict => 'f' },
+{ oid => '9982', descr => 'local timestamp',
+ proname => 'localtimestamp', provolatile => 's', prorettype => 'timestamp',
+ proargtypes => 'int4', prosrc => 'sql_localtimestamp', proisstrict => 'f' },
{ oid => '744',
proname => 'array_eq', prorettype => 'bool',
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index e14f15d435..0557302b92 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -170,7 +170,6 @@ typedef enum ExprEvalOp
EEOP_DISTINCT,
EEOP_NOT_DISTINCT,
EEOP_NULLIF,
- EEOP_SQLVALUEFUNCTION,
EEOP_CURRENTOFEXPR,
EEOP_NEXTVALUEEXPR,
EEOP_ARRAYEXPR,
@@ -416,12 +415,6 @@ typedef struct ExprEvalStep
FunctionCallInfo fcinfo_data_in;
} iocoerce;
- /* for EEOP_SQLVALUEFUNCTION */
- struct
- {
- SQLValueFunction *svf;
- } sqlvaluefunction;
-
/* for EEOP_NEXTVALUEEXPR */
struct
{
@@ -741,7 +734,6 @@ extern void ExecEvalParamExec(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
extern void ExecEvalParamExtern(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
-extern void ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op);
extern void ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op);
extern void ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op);
extern void ExecEvalRowNull(ExprState *state, ExprEvalStep *op,
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index e818231e15..71293185fb 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1292,39 +1292,6 @@ typedef struct MinMaxExpr
int location; /* token location, or -1 if unknown */
} MinMaxExpr;
-/*
- * SQLValueFunction - parameterless functions with special grammar productions
- *
- * The SQL standard categorizes some of these as <datetime value function>
- * and others as <general value specification>. We call 'em SQLValueFunctions
- * for lack of a better term. We store type and typmod of the result so that
- * some code doesn't need to know each function individually, and because
- * we would need to store typmod anyway for some of the datetime functions.
- * Note that currently, all variants return non-collating datatypes, so we do
- * not need a collation field; also, all these functions are stable.
- */
-typedef enum SQLValueFunctionOp
-{
- SVFOP_CURRENT_DATE,
- SVFOP_CURRENT_TIME,
- SVFOP_CURRENT_TIME_N,
- SVFOP_CURRENT_TIMESTAMP,
- SVFOP_CURRENT_TIMESTAMP_N,
- SVFOP_LOCALTIME,
- SVFOP_LOCALTIME_N,
- SVFOP_LOCALTIMESTAMP,
- SVFOP_LOCALTIMESTAMP_N
-} SQLValueFunctionOp;
-
-typedef struct SQLValueFunction
-{
- Expr xpr;
- SQLValueFunctionOp op; /* which function this is */
- Oid type; /* result type/typmod */
- int32 typmod;
- int location; /* token location, or -1 if unknown */
-} SQLValueFunction;
-
/*
* XmlExpr - various SQL/XML functions requiring special grammar productions
*
diff --git a/src/include/utils/date.h b/src/include/utils/date.h
index 0bbe889128..fad4878722 100644
--- a/src/include/utils/date.h
+++ b/src/include/utils/date.h
@@ -96,7 +96,6 @@ TimeTzADTPGetDatum(const TimeTzADT *X)
/* date.c */
-extern int32 anytime_typmod_check(bool istz, int32 typmod);
extern double date2timestamp_no_overflow(DateADT dateVal);
extern Timestamp date2timestamp_opt_overflow(DateADT dateVal, int *overflow);
extern TimestampTz date2timestamptz_opt_overflow(DateADT dateVal, int *overflow);
@@ -104,9 +103,6 @@ extern int32 date_cmp_timestamp_internal(DateADT dateVal, Timestamp dt2);
extern int32 date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2);
extern void EncodeSpecialDate(DateADT dt, char *str);
-extern DateADT GetSQLCurrentDate(void);
-extern TimeTzADT *GetSQLCurrentTime(int32 typmod);
-extern TimeADT GetSQLLocalTime(int32 typmod);
extern int time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec);
extern int timetz2tm(TimeTzADT *time, struct pg_tm *tm, fsec_t *fsec, int *tzp);
extern int tm2time(struct pg_tm *tm, fsec_t fsec, TimeADT *result);
diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h
index 76b7b4a3ca..7fd0b58825 100644
--- a/src/include/utils/timestamp.h
+++ b/src/include/utils/timestamp.h
@@ -93,11 +93,7 @@ extern PGDLLIMPORT TimestampTz PgReloadTime;
/* Internal routines (not fmgr-callable) */
-extern int32 anytimestamp_typmod_check(bool istz, int32 typmod);
-
extern TimestampTz GetCurrentTimestamp(void);
-extern TimestampTz GetSQLCurrentTimestamp(int32 typmod);
-extern Timestamp GetSQLLocalTimestamp(int32 typmod);
extern void TimestampDifference(TimestampTz start_time, TimestampTz stop_time,
long *secs, int *microsecs);
extern long TimestampDifferenceMilliseconds(TimestampTz start_time,
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 30a048f6b0..4c3b4c3f8e 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,32 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+-- Functions with SQL-mandated special syntax and some defaults.
+CREATE OR REPLACE FUNCTION
+ "current_time"(int4 DEFAULT NULL)
+RETURNS timetz
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'current_time';
+CREATE OR REPLACE FUNCTION
+ "current_timestamp"(int4 DEFAULT NULL)
+RETURNS timestamptz
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'current_timestamp';
+CREATE OR REPLACE FUNCTION
+ "localtime"(int4 DEFAULT NULL)
+RETURNS time
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'sql_localtime';
+CREATE OR REPLACE FUNCTION
+ "localtimestamp"(int4 DEFAULT NULL)
+RETURNS timestamp
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'sql_localtimestamp';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 25a94bbaaa..f9bfd79d48 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -2209,17 +2209,6 @@ ExecInitExprRec(Expr *node, ExprState *state,
break;
}
- case T_SQLValueFunction:
- {
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- scratch.opcode = EEOP_SQLVALUEFUNCTION;
- scratch.d.sqlvaluefunction.svf = svf;
-
- ExprEvalPushStep(state, &scratch);
- break;
- }
-
case T_XmlExpr:
{
XmlExpr *xexpr = (XmlExpr *) node;
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6ebf5c287e..1dab2787b7 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -452,7 +452,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
&&CASE_EEOP_DISTINCT,
&&CASE_EEOP_NOT_DISTINCT,
&&CASE_EEOP_NULLIF,
- &&CASE_EEOP_SQLVALUEFUNCTION,
&&CASE_EEOP_CURRENTOFEXPR,
&&CASE_EEOP_NEXTVALUEEXPR,
&&CASE_EEOP_ARRAYEXPR,
@@ -1301,17 +1300,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
EEO_NEXT();
}
- EEO_CASE(EEOP_SQLVALUEFUNCTION)
- {
- /*
- * Doesn't seem worthwhile to have an inline implementation
- * efficiency-wise.
- */
- ExecEvalSQLValueFunction(state, op);
-
- EEO_NEXT();
- }
-
EEO_CASE(EEOP_CURRENTOFEXPR)
{
/* error invocation uses space, and shouldn't ever occur */
@@ -2489,40 +2477,6 @@ ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
errmsg("no value found for parameter %d", paramId)));
}
-/*
- * Evaluate a SQLValueFunction expression.
- */
-void
-ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
-{
- SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
-
- *op->resnull = false;
-
- switch (svf->op)
- {
- case SVFOP_CURRENT_DATE:
- *op->resvalue = DateADTGetDatum(GetSQLCurrentDate());
- break;
- case SVFOP_CURRENT_TIME:
- case SVFOP_CURRENT_TIME_N:
- *op->resvalue = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod));
- break;
- case SVFOP_CURRENT_TIMESTAMP:
- case SVFOP_CURRENT_TIMESTAMP_N:
- *op->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod));
- break;
- case SVFOP_LOCALTIME:
- case SVFOP_LOCALTIME_N:
- *op->resvalue = TimeADTGetDatum(GetSQLLocalTime(svf->typmod));
- break;
- case SVFOP_LOCALTIMESTAMP:
- case SVFOP_LOCALTIMESTAMP_N:
- *op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
- break;
- }
-}
-
/*
* Raise error if a CURRENT OF expression is evaluated.
*
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index 95d0807bdd..f114337f8e 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -1549,12 +1549,6 @@ llvm_compile_expr(ExprState *state)
break;
}
- case EEOP_SQLVALUEFUNCTION:
- build_EvalXFunc(b, mod, "ExecEvalSQLValueFunction",
- v_state, op);
- LLVMBuildBr(b, opblocks[opno + 1]);
- break;
-
case EEOP_CURRENTOFEXPR:
build_EvalXFunc(b, mod, "ExecEvalCurrentOfExpr",
v_state, op);
diff --git a/src/backend/jit/llvm/llvmjit_types.c b/src/backend/jit/llvm/llvmjit_types.c
index 90ac6b83b5..5b416c5642 100644
--- a/src/backend/jit/llvm/llvmjit_types.c
+++ b/src/backend/jit/llvm/llvmjit_types.c
@@ -126,7 +126,6 @@ void *referenced_functions[] =
ExecEvalRow,
ExecEvalRowNotNull,
ExecEvalRowNull,
- ExecEvalSQLValueFunction,
ExecEvalScalarArrayOp,
ExecEvalHashedScalarArrayOp,
ExecEvalSubPlan,
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 2585a3175c..af8620ceb7 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -210,9 +210,6 @@ exprType(const Node *expr)
case T_MinMaxExpr:
type = ((const MinMaxExpr *) expr)->minmaxtype;
break;
- case T_SQLValueFunction:
- type = ((const SQLValueFunction *) expr)->type;
- break;
case T_XmlExpr:
if (((const XmlExpr *) expr)->op == IS_DOCUMENT)
type = BOOLOID;
@@ -474,8 +471,6 @@ exprTypmod(const Node *expr)
return typmod;
}
break;
- case T_SQLValueFunction:
- return ((const SQLValueFunction *) expr)->typmod;
case T_CoerceToDomain:
return ((const CoerceToDomain *) expr)->resulttypmod;
case T_CoerceToDomainValue:
@@ -916,10 +911,6 @@ exprCollation(const Node *expr)
case T_MinMaxExpr:
coll = ((const MinMaxExpr *) expr)->minmaxcollid;
break;
- case T_SQLValueFunction:
- /* Returns a non-collatable type */
- coll = InvalidOid;
- break;
case T_XmlExpr:
/*
@@ -1140,9 +1131,6 @@ exprSetCollation(Node *expr, Oid collation)
case T_MinMaxExpr:
((MinMaxExpr *) expr)->minmaxcollid = collation;
break;
- case T_SQLValueFunction:
- Assert(collation == InvalidOid);
- break;
case T_XmlExpr:
Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ?
(collation == DEFAULT_COLLATION_OID) :
@@ -1426,10 +1414,6 @@ exprLocation(const Node *expr)
/* GREATEST/LEAST keyword should always be the first thing */
loc = ((const MinMaxExpr *) expr)->location;
break;
- case T_SQLValueFunction:
- /* function keyword should always be the first thing */
- loc = ((const SQLValueFunction *) expr)->location;
- break;
case T_XmlExpr:
{
const XmlExpr *xexpr = (const XmlExpr *) expr;
@@ -1717,10 +1701,10 @@ set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
* for themselves, in case additional checks should be made, or because they
* have special rules about which parts of the tree need to be visited.
*
- * Note: we ignore MinMaxExpr, SQLValueFunction, XmlExpr, CoerceToDomain,
- * and NextValueExpr nodes, because they do not contain SQL function OIDs.
- * However, they can invoke SQL-visible functions, so callers should take
- * thought about how to treat them.
+ * Note: we ignore MinMaxExpr, XmlExpr, CoerceToDomain, and NextValueExpr
+ * nodes, because they do not contain SQL function OIDs. However, they can
+ * invoke SQL-visible functions, so callers should take thought about how
+ * to treat them.
*/
bool
check_functions_in_node(Node *node, check_function_callback checker,
@@ -1936,7 +1920,6 @@ expression_tree_walker_impl(Node *node,
case T_Const:
case T_Param:
case T_CaseTestExpr:
- case T_SQLValueFunction:
case T_CoerceToDomainValue:
case T_SetToDefault:
case T_CurrentOfExpr:
@@ -2673,7 +2656,6 @@ expression_tree_mutator_impl(Node *node,
break;
case T_Param:
case T_CaseTestExpr:
- case T_SQLValueFunction:
case T_CoerceToDomainValue:
case T_SetToDefault:
case T_CurrentOfExpr:
@@ -3587,7 +3569,6 @@ raw_expression_tree_walker_impl(Node *node,
{
case T_SetToDefault:
case T_CurrentOfExpr:
- case T_SQLValueFunction:
case T_Integer:
case T_Float:
case T_Boolean:
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 4c6b1d1f55..897309d7ec 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -4603,7 +4603,6 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
}
}
else if (IsA(node, MinMaxExpr) ||
- IsA(node, SQLValueFunction) ||
IsA(node, XmlExpr) ||
IsA(node, CoerceToDomain) ||
IsA(node, NextValueExpr))
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 7fb32a0710..5db6574bfb 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -382,12 +382,6 @@ contain_mutable_functions_walker(Node *node, void *context)
context))
return true;
- if (IsA(node, SQLValueFunction))
- {
- /* all variants of SQLValueFunction are stable */
- return true;
- }
-
if (IsA(node, NextValueExpr))
{
/* NextValueExpr is volatile */
@@ -536,8 +530,8 @@ contain_volatile_functions_walker(Node *node, void *context)
/*
* See notes in contain_mutable_functions_walker about why we treat
- * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
- * SQLValueFunction is stable. Hence, none of them are of interest here.
+ * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable. Hence, none
+ * of them are of interest here.
*/
/* Recurse to check arguments */
@@ -582,10 +576,9 @@ contain_volatile_functions_not_nextval_walker(Node *node, void *context)
/*
* See notes in contain_mutable_functions_walker about why we treat
- * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
- * SQLValueFunction is stable. Hence, none of them are of interest here.
- * Also, since we're intentionally ignoring nextval(), presumably we
- * should ignore NextValueExpr.
+ * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable. Hence, none
+ * of them are of interest here. Also, since we're intentionally
+ * ignoring nextval(), presumably we should ignore NextValueExpr.
*/
/* Recurse to check arguments */
@@ -731,8 +724,8 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
* (Note: in principle that's wrong because a domain constraint could
* contain a parallel-unsafe function; but useful constraints probably
* never would have such, and assuming they do would cripple use of
- * parallel query in the presence of domain types.) SQLValueFunction
- * should be safe in all cases. NextValueExpr is parallel-unsafe.
+ * parallel query in the presence of domain types.) NextValueExpr is
+ * parallel-unsafe.
*/
if (IsA(node, CoerceToDomain))
{
@@ -1179,7 +1172,6 @@ contain_leaked_vars_walker(Node *node, void *context)
case T_CaseExpr:
case T_CaseTestExpr:
case T_RowExpr:
- case T_SQLValueFunction:
case T_NullTest:
case T_BooleanTest:
case T_NextValueExpr:
@@ -3149,23 +3141,6 @@ eval_const_expressions_mutator(Node *node,
newcoalesce->location = coalesceexpr->location;
return (Node *) newcoalesce;
}
- case T_SQLValueFunction:
- {
- /*
- * All variants of SQLValueFunction are stable, so if we are
- * estimating the expression's value, we should evaluate the
- * current function value. Otherwise just copy.
- */
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- if (context->estimate)
- return (Node *) evaluate_expr((Expr *) svf,
- svf->type,
- svf->typmod,
- InvalidOid);
- else
- return copyObject((Node *) svf);
- }
case T_FieldSelect:
{
/*
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 605e9ec096..c8f6f942d1 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -198,8 +198,6 @@ static Node *makeAndExpr(Node *lexpr, Node *rexpr, int location);
static Node *makeOrExpr(Node *lexpr, Node *rexpr, int location);
static Node *makeNotExpr(Node *expr, int location);
static Node *makeAArrayExpr(List *elements, int location);
-static Node *makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod,
- int location);
static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
List *args, int location);
static List *mergeTableFuncParameters(List *func_args, List *columns);
@@ -15193,39 +15191,66 @@ func_expr_common_subexpr:
}
| CURRENT_DATE
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_DATE, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_date"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIME
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_time"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIME '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_time"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIMESTAMP
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_timestamp"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIMESTAMP '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_timestamp"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIME
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIME, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtime"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIME '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIME_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtime"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIMESTAMP
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtimestamp"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIMESTAMP '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtimestamp"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_ROLE
{
@@ -18164,18 +18189,6 @@ makeAArrayExpr(List *elements, int location)
return (Node *) n;
}
-static Node *
-makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, int location)
-{
- SQLValueFunction *svf = makeNode(SQLValueFunction);
-
- svf->op = op;
- /* svf->type will be filled during parse analysis */
- svf->typmod = typmod;
- svf->location = location;
- return (Node *) svf;
-}
-
static Node *
makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
int location)
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 9bde33b407..6b49d39c94 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -61,8 +61,6 @@ static Node *transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
static Node *transformRowExpr(ParseState *pstate, RowExpr *r, bool allowDefault);
static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c);
static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m);
-static Node *transformSQLValueFunction(ParseState *pstate,
- SQLValueFunction *svf);
static Node *transformXmlExpr(ParseState *pstate, XmlExpr *x);
static Node *transformXmlSerialize(ParseState *pstate, XmlSerialize *xs);
static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
@@ -240,11 +238,6 @@ transformExprRecurse(ParseState *pstate, Node *expr)
result = transformMinMaxExpr(pstate, (MinMaxExpr *) expr);
break;
- case T_SQLValueFunction:
- result = transformSQLValueFunction(pstate,
- (SQLValueFunction *) expr);
- break;
-
case T_XmlExpr:
result = transformXmlExpr(pstate, (XmlExpr *) expr);
break;
@@ -2191,51 +2184,6 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m)
return (Node *) newm;
}
-static Node *
-transformSQLValueFunction(ParseState *pstate, SQLValueFunction *svf)
-{
- /*
- * All we need to do is insert the correct result type and (where needed)
- * validate the typmod, so we just modify the node in-place.
- */
- switch (svf->op)
- {
- case SVFOP_CURRENT_DATE:
- svf->type = DATEOID;
- break;
- case SVFOP_CURRENT_TIME:
- svf->type = TIMETZOID;
- break;
- case SVFOP_CURRENT_TIME_N:
- svf->type = TIMETZOID;
- svf->typmod = anytime_typmod_check(true, svf->typmod);
- break;
- case SVFOP_CURRENT_TIMESTAMP:
- svf->type = TIMESTAMPTZOID;
- break;
- case SVFOP_CURRENT_TIMESTAMP_N:
- svf->type = TIMESTAMPTZOID;
- svf->typmod = anytimestamp_typmod_check(true, svf->typmod);
- break;
- case SVFOP_LOCALTIME:
- svf->type = TIMEOID;
- break;
- case SVFOP_LOCALTIME_N:
- svf->type = TIMEOID;
- svf->typmod = anytime_typmod_check(false, svf->typmod);
- break;
- case SVFOP_LOCALTIMESTAMP:
- svf->type = TIMESTAMPOID;
- break;
- case SVFOP_LOCALTIMESTAMP_N:
- svf->type = TIMESTAMPOID;
- svf->typmod = anytimestamp_typmod_check(false, svf->typmod);
- break;
- }
-
- return (Node *) svf;
-}
-
static Node *
transformXmlExpr(ParseState *pstate, XmlExpr *x)
{
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index f54591a987..8e0d6fd01f 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1872,31 +1872,6 @@ FigureColnameInternal(Node *node, char **name)
return 2;
}
break;
- case T_SQLValueFunction:
- /* make these act like a function or variable */
- switch (((SQLValueFunction *) node)->op)
- {
- case SVFOP_CURRENT_DATE:
- *name = "current_date";
- return 2;
- case SVFOP_CURRENT_TIME:
- case SVFOP_CURRENT_TIME_N:
- *name = "current_time";
- return 2;
- case SVFOP_CURRENT_TIMESTAMP:
- case SVFOP_CURRENT_TIMESTAMP_N:
- *name = "current_timestamp";
- return 2;
- case SVFOP_LOCALTIME:
- case SVFOP_LOCALTIME_N:
- *name = "localtime";
- return 2;
- case SVFOP_LOCALTIMESTAMP:
- case SVFOP_LOCALTIMESTAMP_N:
- *name = "localtimestamp";
- return 2;
- }
- break;
case T_XmlExpr:
/* make SQL/XML functions act like a regular function */
switch (((XmlExpr *) node)->op)
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index a2bdde0459..10c11e00db 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -46,27 +46,6 @@
/* common code for timetypmodin and timetztypmodin */
static int32
-anytime_typmodin(bool istz, ArrayType *ta)
-{
- int32 *tl;
- int n;
-
- tl = ArrayGetIntegerTypmods(ta, &n);
-
- /*
- * we're not too tense about good error message here because grammar
- * shouldn't allow wrong number of modifiers for TIME
- */
- if (n != 1)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("invalid type modifier")));
-
- return anytime_typmod_check(istz, tl[0]);
-}
-
-/* exported so parse_expr.c can use it */
-int32
anytime_typmod_check(bool istz, int32 typmod)
{
if (typmod < 0)
@@ -87,6 +66,26 @@ anytime_typmod_check(bool istz, int32 typmod)
return typmod;
}
+static int32
+anytime_typmodin(bool istz, ArrayType *ta)
+{
+ int32 *tl;
+ int n;
+
+ tl = ArrayGetIntegerTypmods(ta, &n);
+
+ /*
+ * we're not too tense about good error message here because grammar
+ * shouldn't allow wrong number of modifiers for TIME
+ */
+ if (n != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid type modifier")));
+
+ return anytime_typmod_check(istz, tl[0]);
+}
+
/* common code for timetypmodout and timetztypmodout */
static char *
anytime_typmodout(bool istz, int32 typmod)
@@ -296,10 +295,10 @@ EncodeSpecialDate(DateADT dt, char *str)
/*
- * GetSQLCurrentDate -- implements CURRENT_DATE
+ * current_date -- implements CURRENT_DATE
*/
-DateADT
-GetSQLCurrentDate(void)
+Datum
+current_date(PG_FUNCTION_ARGS)
{
struct pg_tm tm;
@@ -325,46 +324,62 @@ GetSQLCurrentDate(void)
cache_mday = tm.tm_mday;
}
- return cache_date;
+ return DateADTGetDatum(cache_date);
}
/*
- * GetSQLCurrentTime -- implements CURRENT_TIME, CURRENT_TIME(n)
+ * current_time -- implements CURRENT_TIME, CURRENT_TIME(n)
*/
-TimeTzADT *
-GetSQLCurrentTime(int32 typmod)
+Datum
+current_time(PG_FUNCTION_ARGS)
{
TimeTzADT *result;
struct pg_tm tt,
*tm = &tt;
fsec_t fsec;
int tz;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytime_typmod_check(true, typmod);
+ }
GetCurrentTimeUsec(tm, &fsec, &tz);
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
tm2timetz(tm, fsec, tz, result);
AdjustTimeForTypmod(&(result->time), typmod);
- return result;
+
+ return TimeTzADTPGetDatum(result);
}
/*
- * GetSQLLocalTime -- implements LOCALTIME, LOCALTIME(n)
+ * sql_localtime -- implements LOCALTIME, LOCALTIME(n)
*/
-TimeADT
-GetSQLLocalTime(int32 typmod)
+Datum
+sql_localtime(PG_FUNCTION_ARGS)
{
TimeADT result;
struct pg_tm tt,
*tm = &tt;
fsec_t fsec;
int tz;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytime_typmod_check(false, typmod);
+ }
GetCurrentTimeUsec(tm, &fsec, &tz);
tm2time(tm, fsec, &result);
AdjustTimeForTypmod(&result, typmod);
- return result;
+
+ return TimeADTGetDatum(result);
}
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index f95289f11c..48ad54ecf1 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -8180,7 +8180,6 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_RowExpr:
case T_CoalesceExpr:
case T_MinMaxExpr:
- case T_SQLValueFunction:
case T_XmlExpr:
case T_NextValueExpr:
case T_NullIfExpr:
@@ -9160,49 +9159,6 @@ get_rule_expr(Node *node, deparse_context *context,
}
break;
- case T_SQLValueFunction:
- {
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- /*
- * Note: this code knows that typmod for time, timestamp, and
- * timestamptz just prints as integer.
- */
- switch (svf->op)
- {
- case SVFOP_CURRENT_DATE:
- appendStringInfoString(buf, "CURRENT_DATE");
- break;
- case SVFOP_CURRENT_TIME:
- appendStringInfoString(buf, "CURRENT_TIME");
- break;
- case SVFOP_CURRENT_TIME_N:
- appendStringInfo(buf, "CURRENT_TIME(%d)", svf->typmod);
- break;
- case SVFOP_CURRENT_TIMESTAMP:
- appendStringInfoString(buf, "CURRENT_TIMESTAMP");
- break;
- case SVFOP_CURRENT_TIMESTAMP_N:
- appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)",
- svf->typmod);
- break;
- case SVFOP_LOCALTIME:
- appendStringInfoString(buf, "LOCALTIME");
- break;
- case SVFOP_LOCALTIME_N:
- appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod);
- break;
- case SVFOP_LOCALTIMESTAMP:
- appendStringInfoString(buf, "LOCALTIMESTAMP");
- break;
- case SVFOP_LOCALTIMESTAMP_N:
- appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
- svf->typmod);
- break;
- }
- }
- break;
-
case T_XmlExpr:
{
XmlExpr *xexpr = (XmlExpr *) node;
@@ -9728,7 +9684,6 @@ looks_like_function(Node *node)
case T_NullIfExpr:
case T_CoalesceExpr:
case T_MinMaxExpr:
- case T_SQLValueFunction:
case T_XmlExpr:
/* these are all accepted by func_expr_common_subexpr */
return true;
@@ -10322,6 +10277,70 @@ get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
appendStringInfoString(buf, "SYSTEM_USER");
return true;
+ case F_CURRENT_DATE:
+ appendStringInfoString(buf, "CURRENT_DATE");
+ return true;
+ case F_CURRENT_TIME:
+ appendStringInfoString(buf, "CURRENT_TIME");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+ case F_CURRENT_TIMESTAMP:
+ appendStringInfoString(buf, "CURRENT_TIMESTAMP");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+ case F_LOCALTIME:
+ appendStringInfoString(buf, "LOCALTIME");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+ case F_LOCALTIMESTAMP:
+ appendStringInfoString(buf, "LOCALTIMESTAMP");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+
case F_XMLEXISTS:
/* XMLEXISTS ... extra parens because args are c_expr */
appendStringInfoString(buf, "XMLEXISTS((");
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index d8552a1f18..ef92323fd0 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -81,27 +81,6 @@ static Timestamp timestamptz2timestamp(TimestampTz timestamp);
/* common code for timestamptypmodin and timestamptztypmodin */
static int32
-anytimestamp_typmodin(bool istz, ArrayType *ta)
-{
- int32 *tl;
- int n;
-
- tl = ArrayGetIntegerTypmods(ta, &n);
-
- /*
- * we're not too tense about good error message here because grammar
- * shouldn't allow wrong number of modifiers for TIMESTAMP
- */
- if (n != 1)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("invalid type modifier")));
-
- return anytimestamp_typmod_check(istz, tl[0]);
-}
-
-/* exported so parse_expr.c can use it */
-int32
anytimestamp_typmod_check(bool istz, int32 typmod)
{
if (typmod < 0)
@@ -122,6 +101,26 @@ anytimestamp_typmod_check(bool istz, int32 typmod)
return typmod;
}
+static int32
+anytimestamp_typmodin(bool istz, ArrayType *ta)
+{
+ int32 *tl;
+ int n;
+
+ tl = ArrayGetIntegerTypmods(ta, &n);
+
+ /*
+ * we're not too tense about good error message here because grammar
+ * shouldn't allow wrong number of modifiers for TIMESTAMP
+ */
+ if (n != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid type modifier")));
+
+ return anytimestamp_typmod_check(istz, tl[0]);
+}
+
/* common code for timestamptypmodout and timestamptztypmodout */
static char *
anytimestamp_typmodout(bool istz, int32 typmod)
@@ -1586,33 +1585,48 @@ GetCurrentTimestamp(void)
}
/*
- * GetSQLCurrentTimestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
+ * current_timestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
*/
-TimestampTz
-GetSQLCurrentTimestamp(int32 typmod)
+Datum
+current_timestamp(PG_FUNCTION_ARGS)
{
TimestampTz ts;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytimestamp_typmod_check(true, typmod);
+ }
ts = GetCurrentTransactionStartTimestamp();
if (typmod >= 0)
AdjustTimestampForTypmod(&ts, typmod);
- return ts;
+ return TimestampTzGetDatum(ts);
}
/*
- * GetSQLLocalTimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
+ * sql_localtimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
*/
-Timestamp
-GetSQLLocalTimestamp(int32 typmod)
+Datum
+sql_localtimestamp(PG_FUNCTION_ARGS)
{
Timestamp ts;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytimestamp_typmod_check(false, typmod);
+ }
ts = timestamptz2timestamp(GetCurrentTransactionStartTimestamp());
if (typmod >= 0)
AdjustTimestampForTypmod(&ts, typmod);
- return ts;
+ return TimestampGetDatum(ts);
}
+
/*
* timeofday(*) -- returns the current time as a text.
*/
diff --git a/src/backend/utils/misc/queryjumble.c b/src/backend/utils/misc/queryjumble.c
index a8508463e7..0ace74de78 100644
--- a/src/backend/utils/misc/queryjumble.c
+++ b/src/backend/utils/misc/queryjumble.c
@@ -606,15 +606,6 @@ JumbleExpr(JumbleState *jstate, Node *node)
JumbleExpr(jstate, (Node *) mmexpr->args);
}
break;
- case T_SQLValueFunction:
- {
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- APP_JUMB(svf->op);
- /* type is fully determined by op */
- APP_JUMB(svf->typmod);
- }
- break;
case T_XmlExpr:
{
XmlExpr *xexpr = (XmlExpr *) node;
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index e7f7323113..f9bbad00df 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -1941,6 +1941,24 @@ select
trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea) as btb,
trim(leading E'\\000'::bytea from E'\\000Tom\\000'::bytea) as ltb,
trim(trailing E'\\000'::bytea from E'\\000Tom\\000'::bytea) as rtb,
+ CURRENT_DATE as cd,
+ (select * from CURRENT_DATE) as cd2,
+ CURRENT_TIME as ct,
+ (select * from CURRENT_TIME) as ct2,
+ CURRENT_TIME (1) as ct3,
+ (select * from CURRENT_TIME (1)) as ct4,
+ CURRENT_TIMESTAMP as ct5,
+ (select * from CURRENT_TIMESTAMP) as ct6,
+ CURRENT_TIMESTAMP (1) as ct7,
+ (select * from CURRENT_TIMESTAMP (1)) as ct8,
+ LOCALTIME as lt1,
+ (select * from LOCALTIME) as lt2,
+ LOCALTIME (1) as lt3,
+ (select * from LOCALTIME (1)) as lt4,
+ LOCALTIMESTAMP as lt5,
+ (select * from LOCALTIMESTAMP) as lt6,
+ LOCALTIMESTAMP (1) as lt7,
+ (select * from LOCALTIMESTAMP (1)) as lt8,
CURRENT_CATALOG as ca,
(select * from CURRENT_CATALOG) as ca2,
CURRENT_ROLE as cr,
@@ -1976,6 +1994,33 @@ select pg_get_viewdef('tt201v', true);
TRIM(BOTH '\x00'::bytea FROM '\x00546f6d00'::bytea) AS btb, +
TRIM(LEADING '\x00'::bytea FROM '\x00546f6d00'::bytea) AS ltb, +
TRIM(TRAILING '\x00'::bytea FROM '\x00546f6d00'::bytea) AS rtb, +
+ CURRENT_DATE AS cd, +
+ ( SELECT "current_date"."current_date" +
+ FROM CURRENT_DATE "current_date"("current_date")) AS cd2, +
+ CURRENT_TIME AS ct, +
+ ( SELECT "current_time"."current_time" +
+ FROM CURRENT_TIME "current_time"("current_time")) AS ct2, +
+ CURRENT_TIME(1) AS ct3, +
+ ( SELECT "current_time"."current_time" +
+ FROM CURRENT_TIME(1) "current_time"("current_time")) AS ct4, +
+ CURRENT_TIMESTAMP AS ct5, +
+ ( SELECT "current_timestamp"."current_timestamp" +
+ FROM CURRENT_TIMESTAMP "current_timestamp"("current_timestamp")) AS ct6, +
+ CURRENT_TIMESTAMP(1) AS ct7, +
+ ( SELECT "current_timestamp"."current_timestamp" +
+ FROM CURRENT_TIMESTAMP(1) "current_timestamp"("current_timestamp")) AS ct8, +
+ LOCALTIME AS lt1, +
+ ( SELECT "localtime"."localtime" +
+ FROM LOCALTIME "localtime"("localtime")) AS lt2, +
+ LOCALTIME(1) AS lt3, +
+ ( SELECT "localtime"."localtime" +
+ FROM LOCALTIME(1) "localtime"("localtime")) AS lt4, +
+ LOCALTIMESTAMP AS lt5, +
+ ( SELECT "localtimestamp"."localtimestamp" +
+ FROM LOCALTIMESTAMP "localtimestamp"("localtimestamp")) AS lt6, +
+ LOCALTIMESTAMP(1) AS lt7, +
+ ( SELECT "localtimestamp"."localtimestamp" +
+ FROM LOCALTIMESTAMP(1) "localtimestamp"("localtimestamp")) AS lt8, +
CURRENT_CATALOG AS ca, +
( SELECT "current_catalog"."current_catalog" +
FROM CURRENT_CATALOG "current_catalog"("current_catalog")) AS ca2, +
diff --git a/src/test/regress/expected/expressions.out b/src/test/regress/expected/expressions.out
index 5bf39fd9aa..28a20900f1 100644
--- a/src/test/regress/expected/expressions.out
+++ b/src/test/regress/expected/expressions.out
@@ -2,7 +2,7 @@
-- expression evaluation tests that don't fit into a more specific file
--
--
--- Tests for SQLValueFunction
+-- Tests for various FuncCalls with COERCE_SQL_SYNTAX.
--
-- current_date (always matches because of transactional behaviour)
SELECT date(now())::text = current_date::text;
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index 04fc0ba35e..bd189b2209 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -722,6 +722,24 @@ select
trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea) as btb,
trim(leading E'\\000'::bytea from E'\\000Tom\\000'::bytea) as ltb,
trim(trailing E'\\000'::bytea from E'\\000Tom\\000'::bytea) as rtb,
+ CURRENT_DATE as cd,
+ (select * from CURRENT_DATE) as cd2,
+ CURRENT_TIME as ct,
+ (select * from CURRENT_TIME) as ct2,
+ CURRENT_TIME (1) as ct3,
+ (select * from CURRENT_TIME (1)) as ct4,
+ CURRENT_TIMESTAMP as ct5,
+ (select * from CURRENT_TIMESTAMP) as ct6,
+ CURRENT_TIMESTAMP (1) as ct7,
+ (select * from CURRENT_TIMESTAMP (1)) as ct8,
+ LOCALTIME as lt1,
+ (select * from LOCALTIME) as lt2,
+ LOCALTIME (1) as lt3,
+ (select * from LOCALTIME (1)) as lt4,
+ LOCALTIMESTAMP as lt5,
+ (select * from LOCALTIMESTAMP) as lt6,
+ LOCALTIMESTAMP (1) as lt7,
+ (select * from LOCALTIMESTAMP (1)) as lt8,
CURRENT_CATALOG as ca,
(select * from CURRENT_CATALOG) as ca2,
CURRENT_ROLE as cr,
diff --git a/src/test/regress/sql/expressions.sql b/src/test/regress/sql/expressions.sql
index 0e163cc0d7..f9a0299d17 100644
--- a/src/test/regress/sql/expressions.sql
+++ b/src/test/regress/sql/expressions.sql
@@ -3,7 +3,7 @@
--
--
--- Tests for SQLValueFunction
+-- Tests for various FuncCalls with COERCE_SQL_SYNTAX.
--
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index d9b839c979..5ec61b26b4 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2397,8 +2397,6 @@ SQLFunctionCache
SQLFunctionCachePtr
SQLFunctionParseInfo
SQLFunctionParseInfoPtr
-SQLValueFunction
-SQLValueFunctionOp
SSL
SSLExtensionInfoContext
SSL_CTX
--
2.37.2
On Fri, Oct 21, 2022 at 02:27:07PM +0900, Michael Paquier wrote:
I have looked at that, and the attribute mapping remains compatible
with past versions once the appropriate pg_proc entries are added.
The updated patch set attached does that (with a user() function as
well to keep the code a maximum simple), with more tests to cover the
attribute case mentioned upthread.
Attached is a rebased patch set, as of the conflicts from 2e0d80c.
--
Michael
Attachments:
v3-0001-Remove-from-SQLValueFunction-all-the-entries-usin.patchtext/x-diff; charset=us-asciiDownload
From 1d2d6e4803f3ab3e9d2c29efcc8dee0f8a53d699 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Tue, 25 Oct 2022 14:15:14 +0900
Subject: [PATCH v3 1/2] Remove from SQLValueFunction all the entries using
"name" as return type
This commit changes six SQL keywords to use COERCE_SQL_SYNTAX rather
than SQLValueFunction:
- CURRENT_ROLE
- CURRENT_USER
- USER
- SESSION_USER
- CURRENT_CATALOG
- CURRENT_SCHEMA
Among the six, "user", "current_role" and "current_catalog" require
specific SQL functions to allow ruleutils.c to map them to the SQL
keywords these require when using COERCE_SQL_SYNTAX. Having
pg_proc.proname match with the keyword ensures that the compatibility
remains the same when projecting any of these keywords in a FROM clause
to an attribute name when an alias is not specified. Tests are added to
make sure that the mapping happens from the SQL keyword is correct,
using a view defition that feeds on these keywords in one of the tests
introduced by 40c24bf (both in a SELECT clause and when using each
keyword in a FROM clause).
SQLValueFunction is reduced to half its contents after this change,
simplifying its logic a bit as there is no need to enforce a C collation
anymore. I have made a few performance tests, with a million-ish calls
to these keywords without seeing a difference in run-time or in perf
profiles. The remaining SQLValueFunctions relate to timestamps.
Bump catalog version.
Reviewed-by: Corey Huinker
Discussion: https://postgr.es/m/YzaG3MoryCguUOym@paquier.xyz
---
src/include/catalog/pg_proc.dat | 9 +++++++
src/include/nodes/primnodes.h | 8 +-----
src/backend/executor/execExprInterp.c | 27 --------------------
src/backend/nodes/nodeFuncs.c | 11 +++-----
src/backend/parser/gram.y | 30 +++++++++++++++++-----
src/backend/parser/parse_expr.c | 8 ------
src/backend/parser/parse_target.c | 18 --------------
src/backend/utils/adt/ruleutils.c | 36 +++++++++++++--------------
8 files changed, 55 insertions(+), 92 deletions(-)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 62a5b8e655..241366fc8e 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -1505,6 +1505,15 @@
{ oid => '745', descr => 'current user name',
proname => 'current_user', provolatile => 's', prorettype => 'name',
proargtypes => '', prosrc => 'current_user' },
+{ oid => '9695', descr => 'current role name',
+ proname => 'current_role', provolatile => 's', prorettype => 'name',
+ proargtypes => '', prosrc => 'current_user' },
+{ oid => '9696', descr => 'user name',
+ proname => 'user', provolatile => 's', prorettype => 'name',
+ proargtypes => '', prosrc => 'current_user' },
+{ oid => '9697', descr => 'name of the current database',
+ proname => 'current_catalog', provolatile => 's', prorettype => 'name',
+ proargtypes => '', prosrc => 'current_database' },
{ oid => '746', descr => 'session user name',
proname => 'session_user', provolatile => 's', prorettype => 'name',
proargtypes => '', prosrc => 'session_user' },
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index f71f551782..f6dd27edcc 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1313,13 +1313,7 @@ typedef enum SQLValueFunctionOp
SVFOP_LOCALTIME,
SVFOP_LOCALTIME_N,
SVFOP_LOCALTIMESTAMP,
- SVFOP_LOCALTIMESTAMP_N,
- SVFOP_CURRENT_ROLE,
- SVFOP_CURRENT_USER,
- SVFOP_USER,
- SVFOP_SESSION_USER,
- SVFOP_CURRENT_CATALOG,
- SVFOP_CURRENT_SCHEMA
+ SVFOP_LOCALTIMESTAMP_N
} SQLValueFunctionOp;
typedef struct SQLValueFunction
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 9b9bbf00a9..6ebf5c287e 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -2495,15 +2495,10 @@ ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
void
ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
{
- LOCAL_FCINFO(fcinfo, 0);
SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
*op->resnull = false;
- /*
- * Note: current_schema() can return NULL. current_user() etc currently
- * cannot, but might as well code those cases the same way for safety.
- */
switch (svf->op)
{
case SVFOP_CURRENT_DATE:
@@ -2525,28 +2520,6 @@ ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
case SVFOP_LOCALTIMESTAMP_N:
*op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
break;
- case SVFOP_CURRENT_ROLE:
- case SVFOP_CURRENT_USER:
- case SVFOP_USER:
- InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
- *op->resvalue = current_user(fcinfo);
- *op->resnull = fcinfo->isnull;
- break;
- case SVFOP_SESSION_USER:
- InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
- *op->resvalue = session_user(fcinfo);
- *op->resnull = fcinfo->isnull;
- break;
- case SVFOP_CURRENT_CATALOG:
- InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
- *op->resvalue = current_database(fcinfo);
- *op->resnull = fcinfo->isnull;
- break;
- case SVFOP_CURRENT_SCHEMA:
- InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
- *op->resvalue = current_schema(fcinfo);
- *op->resnull = fcinfo->isnull;
- break;
}
}
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 0a7b22f97e..2585a3175c 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -917,11 +917,8 @@ exprCollation(const Node *expr)
coll = ((const MinMaxExpr *) expr)->minmaxcollid;
break;
case T_SQLValueFunction:
- /* Returns either NAME or a non-collatable type */
- if (((const SQLValueFunction *) expr)->type == NAMEOID)
- coll = C_COLLATION_OID;
- else
- coll = InvalidOid;
+ /* Returns a non-collatable type */
+ coll = InvalidOid;
break;
case T_XmlExpr:
@@ -1144,9 +1141,7 @@ exprSetCollation(Node *expr, Oid collation)
((MinMaxExpr *) expr)->minmaxcollid = collation;
break;
case T_SQLValueFunction:
- Assert((((SQLValueFunction *) expr)->type == NAMEOID) ?
- (collation == C_COLLATION_OID) :
- (collation == InvalidOid));
+ Assert(collation == InvalidOid);
break;
case T_XmlExpr:
Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ?
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 737bd2d06d..605e9ec096 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -15229,15 +15229,24 @@ func_expr_common_subexpr:
}
| CURRENT_ROLE
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_ROLE, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_role"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_USER
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_USER, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_user"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| SESSION_USER
{
- $$ = makeSQLValueFunction(SVFOP_SESSION_USER, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("session_user"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| SYSTEM_USER
{
@@ -15248,15 +15257,24 @@ func_expr_common_subexpr:
}
| USER
{
- $$ = makeSQLValueFunction(SVFOP_USER, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("user"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_CATALOG
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_CATALOG, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_catalog"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_SCHEMA
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_SCHEMA, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_schema"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CAST '(' a_expr AS Typename ')'
{ $$ = makeTypeCast($3, $5, @1); }
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index e5fc708c8a..0fdbf82f3a 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -2231,14 +2231,6 @@ transformSQLValueFunction(ParseState *pstate, SQLValueFunction *svf)
svf->type = TIMESTAMPOID;
svf->typmod = anytimestamp_typmod_check(false, svf->typmod);
break;
- case SVFOP_CURRENT_ROLE:
- case SVFOP_CURRENT_USER:
- case SVFOP_USER:
- case SVFOP_SESSION_USER:
- case SVFOP_CURRENT_CATALOG:
- case SVFOP_CURRENT_SCHEMA:
- svf->type = NAMEOID;
- break;
}
return (Node *) svf;
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index bd8057bc3e..f54591a987 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1895,24 +1895,6 @@ FigureColnameInternal(Node *node, char **name)
case SVFOP_LOCALTIMESTAMP_N:
*name = "localtimestamp";
return 2;
- case SVFOP_CURRENT_ROLE:
- *name = "current_role";
- return 2;
- case SVFOP_CURRENT_USER:
- *name = "current_user";
- return 2;
- case SVFOP_USER:
- *name = "user";
- return 2;
- case SVFOP_SESSION_USER:
- *name = "session_user";
- return 2;
- case SVFOP_CURRENT_CATALOG:
- *name = "current_catalog";
- return 2;
- case SVFOP_CURRENT_SCHEMA:
- *name = "current_schema";
- return 2;
}
break;
case T_XmlExpr:
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 70d723e80c..f95289f11c 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -9199,24 +9199,6 @@ get_rule_expr(Node *node, deparse_context *context,
appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
svf->typmod);
break;
- case SVFOP_CURRENT_ROLE:
- appendStringInfoString(buf, "CURRENT_ROLE");
- break;
- case SVFOP_CURRENT_USER:
- appendStringInfoString(buf, "CURRENT_USER");
- break;
- case SVFOP_USER:
- appendStringInfoString(buf, "USER");
- break;
- case SVFOP_SESSION_USER:
- appendStringInfoString(buf, "SESSION_USER");
- break;
- case SVFOP_CURRENT_CATALOG:
- appendStringInfoString(buf, "CURRENT_CATALOG");
- break;
- case SVFOP_CURRENT_SCHEMA:
- appendStringInfoString(buf, "CURRENT_SCHEMA");
- break;
}
}
break;
@@ -10318,6 +10300,24 @@ get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
appendStringInfoChar(buf, ')');
return true;
+ case F_CURRENT_CATALOG:
+ appendStringInfoString(buf, "CURRENT_CATALOG");
+ return true;
+ case F_CURRENT_ROLE:
+ appendStringInfoString(buf, "CURRENT_ROLE");
+ return true;
+ case F_CURRENT_SCHEMA:
+ appendStringInfoString(buf, "CURRENT_SCHEMA");
+ return true;
+ case F_CURRENT_USER:
+ appendStringInfoString(buf, "CURRENT_USER");
+ return true;
+ case F_USER:
+ appendStringInfoString(buf, "USER");
+ return true;
+ case F_SESSION_USER:
+ appendStringInfoString(buf, "SESSION_USER");
+ return true;
case F_SYSTEM_USER:
appendStringInfoString(buf, "SYSTEM_USER");
return true;
--
2.37.2
v3-0002-Replace-SQLValueFunction-by-direct-function-calls.patchtext/x-diff; charset=us-asciiDownload
From 208c5e9c3021bbb6b9ab929a66adb404fd0088c6 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Fri, 21 Oct 2022 14:19:41 +0900
Subject: [PATCH v3 2/2] Replace SQLValueFunction by direct function calls
This impacts 9 patterns where the SQL grammar takes priority:
- localtime, that can take a typmod.
- localtimestamp, that can take a typmod.
- current_time, that can take a typmod.
- current_timestamp, that can take a typmod.
- current_date.
Five new entries are added to pg_proc to compensate the removal of
SQLValueFunction to keep compatibility (when a keyword is specified in a
SELECT or in a FROM clause without an alias), with tests to cover all
that.
XXX: bump catalog version.
Reviewed-by: Corey Huinker
Discussion: https://postgr.es/m/YzaG3MoryCguUOym@paquier.xyz
---
src/include/catalog/pg_proc.dat | 15 +++
src/include/executor/execExpr.h | 8 --
src/include/nodes/primnodes.h | 33 -------
src/include/utils/date.h | 4 -
src/include/utils/timestamp.h | 4 -
src/backend/catalog/system_functions.sql | 26 ++++++
src/backend/executor/execExpr.c | 11 ---
src/backend/executor/execExprInterp.c | 46 ---------
src/backend/jit/llvm/llvmjit_expr.c | 6 --
src/backend/jit/llvm/llvmjit_types.c | 1 -
src/backend/nodes/nodeFuncs.c | 27 +-----
src/backend/optimizer/path/costsize.c | 1 -
src/backend/optimizer/util/clauses.c | 39 ++------
src/backend/parser/gram.y | 59 +++++++-----
src/backend/parser/parse_expr.c | 52 -----------
src/backend/parser/parse_target.c | 25 -----
src/backend/utils/adt/date.c | 81 +++++++++-------
src/backend/utils/adt/ruleutils.c | 109 +++++++++++++---------
src/backend/utils/adt/timestamp.c | 72 ++++++++------
src/backend/utils/misc/queryjumble.c | 9 --
src/test/regress/expected/expressions.out | 2 +-
src/test/regress/sql/expressions.sql | 2 +-
src/tools/pgindent/typedefs.list | 2 -
23 files changed, 245 insertions(+), 389 deletions(-)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 241366fc8e..081419d065 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -1520,6 +1520,21 @@
{ oid => '9977', descr => 'system user name',
proname => 'system_user', provolatile => 's', prorettype => 'text',
proargtypes => '', prosrc => 'system_user' },
+{ oid => '9978', descr => 'current date',
+ proname => 'current_date', provolatile => 's', prorettype => 'date',
+ proargtypes => '', prosrc => 'current_date' },
+{ oid => '9979', descr => 'current time',
+ proname => 'current_time', provolatile => 's', prorettype => 'timetz',
+ proargtypes => 'int4', prosrc => 'current_time', proisstrict => 'f' },
+{ oid => '9980', descr => 'current timestamp',
+ proname => 'current_timestamp', provolatile => 's', prorettype => 'timestamptz',
+ proargtypes => 'int4', prosrc => 'current_timestamp', proisstrict => 'f' },
+{ oid => '9981', descr => 'local time',
+ proname => 'localtime', provolatile => 's', prorettype => 'time',
+ proargtypes => 'int4', prosrc => 'sql_localtime', proisstrict => 'f' },
+{ oid => '9982', descr => 'local timestamp',
+ proname => 'localtimestamp', provolatile => 's', prorettype => 'timestamp',
+ proargtypes => 'int4', prosrc => 'sql_localtimestamp', proisstrict => 'f' },
{ oid => '744',
proname => 'array_eq', prorettype => 'bool',
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index e14f15d435..0557302b92 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -170,7 +170,6 @@ typedef enum ExprEvalOp
EEOP_DISTINCT,
EEOP_NOT_DISTINCT,
EEOP_NULLIF,
- EEOP_SQLVALUEFUNCTION,
EEOP_CURRENTOFEXPR,
EEOP_NEXTVALUEEXPR,
EEOP_ARRAYEXPR,
@@ -416,12 +415,6 @@ typedef struct ExprEvalStep
FunctionCallInfo fcinfo_data_in;
} iocoerce;
- /* for EEOP_SQLVALUEFUNCTION */
- struct
- {
- SQLValueFunction *svf;
- } sqlvaluefunction;
-
/* for EEOP_NEXTVALUEEXPR */
struct
{
@@ -741,7 +734,6 @@ extern void ExecEvalParamExec(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
extern void ExecEvalParamExtern(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
-extern void ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op);
extern void ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op);
extern void ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op);
extern void ExecEvalRowNull(ExprState *state, ExprEvalStep *op,
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index f6dd27edcc..74f228d959 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1292,39 +1292,6 @@ typedef struct MinMaxExpr
int location; /* token location, or -1 if unknown */
} MinMaxExpr;
-/*
- * SQLValueFunction - parameterless functions with special grammar productions
- *
- * The SQL standard categorizes some of these as <datetime value function>
- * and others as <general value specification>. We call 'em SQLValueFunctions
- * for lack of a better term. We store type and typmod of the result so that
- * some code doesn't need to know each function individually, and because
- * we would need to store typmod anyway for some of the datetime functions.
- * Note that currently, all variants return non-collating datatypes, so we do
- * not need a collation field; also, all these functions are stable.
- */
-typedef enum SQLValueFunctionOp
-{
- SVFOP_CURRENT_DATE,
- SVFOP_CURRENT_TIME,
- SVFOP_CURRENT_TIME_N,
- SVFOP_CURRENT_TIMESTAMP,
- SVFOP_CURRENT_TIMESTAMP_N,
- SVFOP_LOCALTIME,
- SVFOP_LOCALTIME_N,
- SVFOP_LOCALTIMESTAMP,
- SVFOP_LOCALTIMESTAMP_N
-} SQLValueFunctionOp;
-
-typedef struct SQLValueFunction
-{
- Expr xpr;
- SQLValueFunctionOp op; /* which function this is */
- Oid type; /* result type/typmod */
- int32 typmod;
- int location; /* token location, or -1 if unknown */
-} SQLValueFunction;
-
/*
* XmlExpr - various SQL/XML functions requiring special grammar productions
*
diff --git a/src/include/utils/date.h b/src/include/utils/date.h
index 0bbe889128..fad4878722 100644
--- a/src/include/utils/date.h
+++ b/src/include/utils/date.h
@@ -96,7 +96,6 @@ TimeTzADTPGetDatum(const TimeTzADT *X)
/* date.c */
-extern int32 anytime_typmod_check(bool istz, int32 typmod);
extern double date2timestamp_no_overflow(DateADT dateVal);
extern Timestamp date2timestamp_opt_overflow(DateADT dateVal, int *overflow);
extern TimestampTz date2timestamptz_opt_overflow(DateADT dateVal, int *overflow);
@@ -104,9 +103,6 @@ extern int32 date_cmp_timestamp_internal(DateADT dateVal, Timestamp dt2);
extern int32 date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2);
extern void EncodeSpecialDate(DateADT dt, char *str);
-extern DateADT GetSQLCurrentDate(void);
-extern TimeTzADT *GetSQLCurrentTime(int32 typmod);
-extern TimeADT GetSQLLocalTime(int32 typmod);
extern int time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec);
extern int timetz2tm(TimeTzADT *time, struct pg_tm *tm, fsec_t *fsec, int *tzp);
extern int tm2time(struct pg_tm *tm, fsec_t fsec, TimeADT *result);
diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h
index 76b7b4a3ca..7fd0b58825 100644
--- a/src/include/utils/timestamp.h
+++ b/src/include/utils/timestamp.h
@@ -93,11 +93,7 @@ extern PGDLLIMPORT TimestampTz PgReloadTime;
/* Internal routines (not fmgr-callable) */
-extern int32 anytimestamp_typmod_check(bool istz, int32 typmod);
-
extern TimestampTz GetCurrentTimestamp(void);
-extern TimestampTz GetSQLCurrentTimestamp(int32 typmod);
-extern Timestamp GetSQLLocalTimestamp(int32 typmod);
extern void TimestampDifference(TimestampTz start_time, TimestampTz stop_time,
long *secs, int *microsecs);
extern long TimestampDifferenceMilliseconds(TimestampTz start_time,
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 30a048f6b0..4c3b4c3f8e 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,32 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+-- Functions with SQL-mandated special syntax and some defaults.
+CREATE OR REPLACE FUNCTION
+ "current_time"(int4 DEFAULT NULL)
+RETURNS timetz
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'current_time';
+CREATE OR REPLACE FUNCTION
+ "current_timestamp"(int4 DEFAULT NULL)
+RETURNS timestamptz
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'current_timestamp';
+CREATE OR REPLACE FUNCTION
+ "localtime"(int4 DEFAULT NULL)
+RETURNS time
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'sql_localtime';
+CREATE OR REPLACE FUNCTION
+ "localtimestamp"(int4 DEFAULT NULL)
+RETURNS timestamp
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'sql_localtimestamp';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 25a94bbaaa..f9bfd79d48 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -2209,17 +2209,6 @@ ExecInitExprRec(Expr *node, ExprState *state,
break;
}
- case T_SQLValueFunction:
- {
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- scratch.opcode = EEOP_SQLVALUEFUNCTION;
- scratch.d.sqlvaluefunction.svf = svf;
-
- ExprEvalPushStep(state, &scratch);
- break;
- }
-
case T_XmlExpr:
{
XmlExpr *xexpr = (XmlExpr *) node;
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6ebf5c287e..1dab2787b7 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -452,7 +452,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
&&CASE_EEOP_DISTINCT,
&&CASE_EEOP_NOT_DISTINCT,
&&CASE_EEOP_NULLIF,
- &&CASE_EEOP_SQLVALUEFUNCTION,
&&CASE_EEOP_CURRENTOFEXPR,
&&CASE_EEOP_NEXTVALUEEXPR,
&&CASE_EEOP_ARRAYEXPR,
@@ -1301,17 +1300,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
EEO_NEXT();
}
- EEO_CASE(EEOP_SQLVALUEFUNCTION)
- {
- /*
- * Doesn't seem worthwhile to have an inline implementation
- * efficiency-wise.
- */
- ExecEvalSQLValueFunction(state, op);
-
- EEO_NEXT();
- }
-
EEO_CASE(EEOP_CURRENTOFEXPR)
{
/* error invocation uses space, and shouldn't ever occur */
@@ -2489,40 +2477,6 @@ ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
errmsg("no value found for parameter %d", paramId)));
}
-/*
- * Evaluate a SQLValueFunction expression.
- */
-void
-ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
-{
- SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
-
- *op->resnull = false;
-
- switch (svf->op)
- {
- case SVFOP_CURRENT_DATE:
- *op->resvalue = DateADTGetDatum(GetSQLCurrentDate());
- break;
- case SVFOP_CURRENT_TIME:
- case SVFOP_CURRENT_TIME_N:
- *op->resvalue = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod));
- break;
- case SVFOP_CURRENT_TIMESTAMP:
- case SVFOP_CURRENT_TIMESTAMP_N:
- *op->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod));
- break;
- case SVFOP_LOCALTIME:
- case SVFOP_LOCALTIME_N:
- *op->resvalue = TimeADTGetDatum(GetSQLLocalTime(svf->typmod));
- break;
- case SVFOP_LOCALTIMESTAMP:
- case SVFOP_LOCALTIMESTAMP_N:
- *op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
- break;
- }
-}
-
/*
* Raise error if a CURRENT OF expression is evaluated.
*
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index 95d0807bdd..f114337f8e 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -1549,12 +1549,6 @@ llvm_compile_expr(ExprState *state)
break;
}
- case EEOP_SQLVALUEFUNCTION:
- build_EvalXFunc(b, mod, "ExecEvalSQLValueFunction",
- v_state, op);
- LLVMBuildBr(b, opblocks[opno + 1]);
- break;
-
case EEOP_CURRENTOFEXPR:
build_EvalXFunc(b, mod, "ExecEvalCurrentOfExpr",
v_state, op);
diff --git a/src/backend/jit/llvm/llvmjit_types.c b/src/backend/jit/llvm/llvmjit_types.c
index 90ac6b83b5..5b416c5642 100644
--- a/src/backend/jit/llvm/llvmjit_types.c
+++ b/src/backend/jit/llvm/llvmjit_types.c
@@ -126,7 +126,6 @@ void *referenced_functions[] =
ExecEvalRow,
ExecEvalRowNotNull,
ExecEvalRowNull,
- ExecEvalSQLValueFunction,
ExecEvalScalarArrayOp,
ExecEvalHashedScalarArrayOp,
ExecEvalSubPlan,
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 2585a3175c..af8620ceb7 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -210,9 +210,6 @@ exprType(const Node *expr)
case T_MinMaxExpr:
type = ((const MinMaxExpr *) expr)->minmaxtype;
break;
- case T_SQLValueFunction:
- type = ((const SQLValueFunction *) expr)->type;
- break;
case T_XmlExpr:
if (((const XmlExpr *) expr)->op == IS_DOCUMENT)
type = BOOLOID;
@@ -474,8 +471,6 @@ exprTypmod(const Node *expr)
return typmod;
}
break;
- case T_SQLValueFunction:
- return ((const SQLValueFunction *) expr)->typmod;
case T_CoerceToDomain:
return ((const CoerceToDomain *) expr)->resulttypmod;
case T_CoerceToDomainValue:
@@ -916,10 +911,6 @@ exprCollation(const Node *expr)
case T_MinMaxExpr:
coll = ((const MinMaxExpr *) expr)->minmaxcollid;
break;
- case T_SQLValueFunction:
- /* Returns a non-collatable type */
- coll = InvalidOid;
- break;
case T_XmlExpr:
/*
@@ -1140,9 +1131,6 @@ exprSetCollation(Node *expr, Oid collation)
case T_MinMaxExpr:
((MinMaxExpr *) expr)->minmaxcollid = collation;
break;
- case T_SQLValueFunction:
- Assert(collation == InvalidOid);
- break;
case T_XmlExpr:
Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ?
(collation == DEFAULT_COLLATION_OID) :
@@ -1426,10 +1414,6 @@ exprLocation(const Node *expr)
/* GREATEST/LEAST keyword should always be the first thing */
loc = ((const MinMaxExpr *) expr)->location;
break;
- case T_SQLValueFunction:
- /* function keyword should always be the first thing */
- loc = ((const SQLValueFunction *) expr)->location;
- break;
case T_XmlExpr:
{
const XmlExpr *xexpr = (const XmlExpr *) expr;
@@ -1717,10 +1701,10 @@ set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
* for themselves, in case additional checks should be made, or because they
* have special rules about which parts of the tree need to be visited.
*
- * Note: we ignore MinMaxExpr, SQLValueFunction, XmlExpr, CoerceToDomain,
- * and NextValueExpr nodes, because they do not contain SQL function OIDs.
- * However, they can invoke SQL-visible functions, so callers should take
- * thought about how to treat them.
+ * Note: we ignore MinMaxExpr, XmlExpr, CoerceToDomain, and NextValueExpr
+ * nodes, because they do not contain SQL function OIDs. However, they can
+ * invoke SQL-visible functions, so callers should take thought about how
+ * to treat them.
*/
bool
check_functions_in_node(Node *node, check_function_callback checker,
@@ -1936,7 +1920,6 @@ expression_tree_walker_impl(Node *node,
case T_Const:
case T_Param:
case T_CaseTestExpr:
- case T_SQLValueFunction:
case T_CoerceToDomainValue:
case T_SetToDefault:
case T_CurrentOfExpr:
@@ -2673,7 +2656,6 @@ expression_tree_mutator_impl(Node *node,
break;
case T_Param:
case T_CaseTestExpr:
- case T_SQLValueFunction:
case T_CoerceToDomainValue:
case T_SetToDefault:
case T_CurrentOfExpr:
@@ -3587,7 +3569,6 @@ raw_expression_tree_walker_impl(Node *node,
{
case T_SetToDefault:
case T_CurrentOfExpr:
- case T_SQLValueFunction:
case T_Integer:
case T_Float:
case T_Boolean:
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 4c6b1d1f55..897309d7ec 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -4603,7 +4603,6 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
}
}
else if (IsA(node, MinMaxExpr) ||
- IsA(node, SQLValueFunction) ||
IsA(node, XmlExpr) ||
IsA(node, CoerceToDomain) ||
IsA(node, NextValueExpr))
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 7fb32a0710..5db6574bfb 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -382,12 +382,6 @@ contain_mutable_functions_walker(Node *node, void *context)
context))
return true;
- if (IsA(node, SQLValueFunction))
- {
- /* all variants of SQLValueFunction are stable */
- return true;
- }
-
if (IsA(node, NextValueExpr))
{
/* NextValueExpr is volatile */
@@ -536,8 +530,8 @@ contain_volatile_functions_walker(Node *node, void *context)
/*
* See notes in contain_mutable_functions_walker about why we treat
- * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
- * SQLValueFunction is stable. Hence, none of them are of interest here.
+ * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable. Hence, none
+ * of them are of interest here.
*/
/* Recurse to check arguments */
@@ -582,10 +576,9 @@ contain_volatile_functions_not_nextval_walker(Node *node, void *context)
/*
* See notes in contain_mutable_functions_walker about why we treat
- * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
- * SQLValueFunction is stable. Hence, none of them are of interest here.
- * Also, since we're intentionally ignoring nextval(), presumably we
- * should ignore NextValueExpr.
+ * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable. Hence, none
+ * of them are of interest here. Also, since we're intentionally
+ * ignoring nextval(), presumably we should ignore NextValueExpr.
*/
/* Recurse to check arguments */
@@ -731,8 +724,8 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
* (Note: in principle that's wrong because a domain constraint could
* contain a parallel-unsafe function; but useful constraints probably
* never would have such, and assuming they do would cripple use of
- * parallel query in the presence of domain types.) SQLValueFunction
- * should be safe in all cases. NextValueExpr is parallel-unsafe.
+ * parallel query in the presence of domain types.) NextValueExpr is
+ * parallel-unsafe.
*/
if (IsA(node, CoerceToDomain))
{
@@ -1179,7 +1172,6 @@ contain_leaked_vars_walker(Node *node, void *context)
case T_CaseExpr:
case T_CaseTestExpr:
case T_RowExpr:
- case T_SQLValueFunction:
case T_NullTest:
case T_BooleanTest:
case T_NextValueExpr:
@@ -3149,23 +3141,6 @@ eval_const_expressions_mutator(Node *node,
newcoalesce->location = coalesceexpr->location;
return (Node *) newcoalesce;
}
- case T_SQLValueFunction:
- {
- /*
- * All variants of SQLValueFunction are stable, so if we are
- * estimating the expression's value, we should evaluate the
- * current function value. Otherwise just copy.
- */
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- if (context->estimate)
- return (Node *) evaluate_expr((Expr *) svf,
- svf->type,
- svf->typmod,
- InvalidOid);
- else
- return copyObject((Node *) svf);
- }
case T_FieldSelect:
{
/*
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 605e9ec096..c8f6f942d1 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -198,8 +198,6 @@ static Node *makeAndExpr(Node *lexpr, Node *rexpr, int location);
static Node *makeOrExpr(Node *lexpr, Node *rexpr, int location);
static Node *makeNotExpr(Node *expr, int location);
static Node *makeAArrayExpr(List *elements, int location);
-static Node *makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod,
- int location);
static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
List *args, int location);
static List *mergeTableFuncParameters(List *func_args, List *columns);
@@ -15193,39 +15191,66 @@ func_expr_common_subexpr:
}
| CURRENT_DATE
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_DATE, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_date"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIME
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_time"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIME '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_time"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIMESTAMP
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_timestamp"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIMESTAMP '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_timestamp"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIME
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIME, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtime"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIME '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIME_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtime"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIMESTAMP
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtimestamp"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIMESTAMP '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtimestamp"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_ROLE
{
@@ -18164,18 +18189,6 @@ makeAArrayExpr(List *elements, int location)
return (Node *) n;
}
-static Node *
-makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, int location)
-{
- SQLValueFunction *svf = makeNode(SQLValueFunction);
-
- svf->op = op;
- /* svf->type will be filled during parse analysis */
- svf->typmod = typmod;
- svf->location = location;
- return (Node *) svf;
-}
-
static Node *
makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
int location)
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 0fdbf82f3a..150a8099c2 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -61,8 +61,6 @@ static Node *transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
static Node *transformRowExpr(ParseState *pstate, RowExpr *r, bool allowDefault);
static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c);
static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m);
-static Node *transformSQLValueFunction(ParseState *pstate,
- SQLValueFunction *svf);
static Node *transformXmlExpr(ParseState *pstate, XmlExpr *x);
static Node *transformXmlSerialize(ParseState *pstate, XmlSerialize *xs);
static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
@@ -240,11 +238,6 @@ transformExprRecurse(ParseState *pstate, Node *expr)
result = transformMinMaxExpr(pstate, (MinMaxExpr *) expr);
break;
- case T_SQLValueFunction:
- result = transformSQLValueFunction(pstate,
- (SQLValueFunction *) expr);
- break;
-
case T_XmlExpr:
result = transformXmlExpr(pstate, (XmlExpr *) expr);
break;
@@ -2191,51 +2184,6 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m)
return (Node *) newm;
}
-static Node *
-transformSQLValueFunction(ParseState *pstate, SQLValueFunction *svf)
-{
- /*
- * All we need to do is insert the correct result type and (where needed)
- * validate the typmod, so we just modify the node in-place.
- */
- switch (svf->op)
- {
- case SVFOP_CURRENT_DATE:
- svf->type = DATEOID;
- break;
- case SVFOP_CURRENT_TIME:
- svf->type = TIMETZOID;
- break;
- case SVFOP_CURRENT_TIME_N:
- svf->type = TIMETZOID;
- svf->typmod = anytime_typmod_check(true, svf->typmod);
- break;
- case SVFOP_CURRENT_TIMESTAMP:
- svf->type = TIMESTAMPTZOID;
- break;
- case SVFOP_CURRENT_TIMESTAMP_N:
- svf->type = TIMESTAMPTZOID;
- svf->typmod = anytimestamp_typmod_check(true, svf->typmod);
- break;
- case SVFOP_LOCALTIME:
- svf->type = TIMEOID;
- break;
- case SVFOP_LOCALTIME_N:
- svf->type = TIMEOID;
- svf->typmod = anytime_typmod_check(false, svf->typmod);
- break;
- case SVFOP_LOCALTIMESTAMP:
- svf->type = TIMESTAMPOID;
- break;
- case SVFOP_LOCALTIMESTAMP_N:
- svf->type = TIMESTAMPOID;
- svf->typmod = anytimestamp_typmod_check(false, svf->typmod);
- break;
- }
-
- return (Node *) svf;
-}
-
static Node *
transformXmlExpr(ParseState *pstate, XmlExpr *x)
{
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index f54591a987..8e0d6fd01f 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1872,31 +1872,6 @@ FigureColnameInternal(Node *node, char **name)
return 2;
}
break;
- case T_SQLValueFunction:
- /* make these act like a function or variable */
- switch (((SQLValueFunction *) node)->op)
- {
- case SVFOP_CURRENT_DATE:
- *name = "current_date";
- return 2;
- case SVFOP_CURRENT_TIME:
- case SVFOP_CURRENT_TIME_N:
- *name = "current_time";
- return 2;
- case SVFOP_CURRENT_TIMESTAMP:
- case SVFOP_CURRENT_TIMESTAMP_N:
- *name = "current_timestamp";
- return 2;
- case SVFOP_LOCALTIME:
- case SVFOP_LOCALTIME_N:
- *name = "localtime";
- return 2;
- case SVFOP_LOCALTIMESTAMP:
- case SVFOP_LOCALTIMESTAMP_N:
- *name = "localtimestamp";
- return 2;
- }
- break;
case T_XmlExpr:
/* make SQL/XML functions act like a regular function */
switch (((XmlExpr *) node)->op)
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index a2bdde0459..10c11e00db 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -46,27 +46,6 @@
/* common code for timetypmodin and timetztypmodin */
static int32
-anytime_typmodin(bool istz, ArrayType *ta)
-{
- int32 *tl;
- int n;
-
- tl = ArrayGetIntegerTypmods(ta, &n);
-
- /*
- * we're not too tense about good error message here because grammar
- * shouldn't allow wrong number of modifiers for TIME
- */
- if (n != 1)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("invalid type modifier")));
-
- return anytime_typmod_check(istz, tl[0]);
-}
-
-/* exported so parse_expr.c can use it */
-int32
anytime_typmod_check(bool istz, int32 typmod)
{
if (typmod < 0)
@@ -87,6 +66,26 @@ anytime_typmod_check(bool istz, int32 typmod)
return typmod;
}
+static int32
+anytime_typmodin(bool istz, ArrayType *ta)
+{
+ int32 *tl;
+ int n;
+
+ tl = ArrayGetIntegerTypmods(ta, &n);
+
+ /*
+ * we're not too tense about good error message here because grammar
+ * shouldn't allow wrong number of modifiers for TIME
+ */
+ if (n != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid type modifier")));
+
+ return anytime_typmod_check(istz, tl[0]);
+}
+
/* common code for timetypmodout and timetztypmodout */
static char *
anytime_typmodout(bool istz, int32 typmod)
@@ -296,10 +295,10 @@ EncodeSpecialDate(DateADT dt, char *str)
/*
- * GetSQLCurrentDate -- implements CURRENT_DATE
+ * current_date -- implements CURRENT_DATE
*/
-DateADT
-GetSQLCurrentDate(void)
+Datum
+current_date(PG_FUNCTION_ARGS)
{
struct pg_tm tm;
@@ -325,46 +324,62 @@ GetSQLCurrentDate(void)
cache_mday = tm.tm_mday;
}
- return cache_date;
+ return DateADTGetDatum(cache_date);
}
/*
- * GetSQLCurrentTime -- implements CURRENT_TIME, CURRENT_TIME(n)
+ * current_time -- implements CURRENT_TIME, CURRENT_TIME(n)
*/
-TimeTzADT *
-GetSQLCurrentTime(int32 typmod)
+Datum
+current_time(PG_FUNCTION_ARGS)
{
TimeTzADT *result;
struct pg_tm tt,
*tm = &tt;
fsec_t fsec;
int tz;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytime_typmod_check(true, typmod);
+ }
GetCurrentTimeUsec(tm, &fsec, &tz);
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
tm2timetz(tm, fsec, tz, result);
AdjustTimeForTypmod(&(result->time), typmod);
- return result;
+
+ return TimeTzADTPGetDatum(result);
}
/*
- * GetSQLLocalTime -- implements LOCALTIME, LOCALTIME(n)
+ * sql_localtime -- implements LOCALTIME, LOCALTIME(n)
*/
-TimeADT
-GetSQLLocalTime(int32 typmod)
+Datum
+sql_localtime(PG_FUNCTION_ARGS)
{
TimeADT result;
struct pg_tm tt,
*tm = &tt;
fsec_t fsec;
int tz;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytime_typmod_check(false, typmod);
+ }
GetCurrentTimeUsec(tm, &fsec, &tz);
tm2time(tm, fsec, &result);
AdjustTimeForTypmod(&result, typmod);
- return result;
+
+ return TimeADTGetDatum(result);
}
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index f95289f11c..48ad54ecf1 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -8180,7 +8180,6 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_RowExpr:
case T_CoalesceExpr:
case T_MinMaxExpr:
- case T_SQLValueFunction:
case T_XmlExpr:
case T_NextValueExpr:
case T_NullIfExpr:
@@ -9160,49 +9159,6 @@ get_rule_expr(Node *node, deparse_context *context,
}
break;
- case T_SQLValueFunction:
- {
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- /*
- * Note: this code knows that typmod for time, timestamp, and
- * timestamptz just prints as integer.
- */
- switch (svf->op)
- {
- case SVFOP_CURRENT_DATE:
- appendStringInfoString(buf, "CURRENT_DATE");
- break;
- case SVFOP_CURRENT_TIME:
- appendStringInfoString(buf, "CURRENT_TIME");
- break;
- case SVFOP_CURRENT_TIME_N:
- appendStringInfo(buf, "CURRENT_TIME(%d)", svf->typmod);
- break;
- case SVFOP_CURRENT_TIMESTAMP:
- appendStringInfoString(buf, "CURRENT_TIMESTAMP");
- break;
- case SVFOP_CURRENT_TIMESTAMP_N:
- appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)",
- svf->typmod);
- break;
- case SVFOP_LOCALTIME:
- appendStringInfoString(buf, "LOCALTIME");
- break;
- case SVFOP_LOCALTIME_N:
- appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod);
- break;
- case SVFOP_LOCALTIMESTAMP:
- appendStringInfoString(buf, "LOCALTIMESTAMP");
- break;
- case SVFOP_LOCALTIMESTAMP_N:
- appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
- svf->typmod);
- break;
- }
- }
- break;
-
case T_XmlExpr:
{
XmlExpr *xexpr = (XmlExpr *) node;
@@ -9728,7 +9684,6 @@ looks_like_function(Node *node)
case T_NullIfExpr:
case T_CoalesceExpr:
case T_MinMaxExpr:
- case T_SQLValueFunction:
case T_XmlExpr:
/* these are all accepted by func_expr_common_subexpr */
return true;
@@ -10322,6 +10277,70 @@ get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
appendStringInfoString(buf, "SYSTEM_USER");
return true;
+ case F_CURRENT_DATE:
+ appendStringInfoString(buf, "CURRENT_DATE");
+ return true;
+ case F_CURRENT_TIME:
+ appendStringInfoString(buf, "CURRENT_TIME");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+ case F_CURRENT_TIMESTAMP:
+ appendStringInfoString(buf, "CURRENT_TIMESTAMP");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+ case F_LOCALTIME:
+ appendStringInfoString(buf, "LOCALTIME");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+ case F_LOCALTIMESTAMP:
+ appendStringInfoString(buf, "LOCALTIMESTAMP");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+
case F_XMLEXISTS:
/* XMLEXISTS ... extra parens because args are c_expr */
appendStringInfoString(buf, "XMLEXISTS((");
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index d8552a1f18..ef92323fd0 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -81,27 +81,6 @@ static Timestamp timestamptz2timestamp(TimestampTz timestamp);
/* common code for timestamptypmodin and timestamptztypmodin */
static int32
-anytimestamp_typmodin(bool istz, ArrayType *ta)
-{
- int32 *tl;
- int n;
-
- tl = ArrayGetIntegerTypmods(ta, &n);
-
- /*
- * we're not too tense about good error message here because grammar
- * shouldn't allow wrong number of modifiers for TIMESTAMP
- */
- if (n != 1)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("invalid type modifier")));
-
- return anytimestamp_typmod_check(istz, tl[0]);
-}
-
-/* exported so parse_expr.c can use it */
-int32
anytimestamp_typmod_check(bool istz, int32 typmod)
{
if (typmod < 0)
@@ -122,6 +101,26 @@ anytimestamp_typmod_check(bool istz, int32 typmod)
return typmod;
}
+static int32
+anytimestamp_typmodin(bool istz, ArrayType *ta)
+{
+ int32 *tl;
+ int n;
+
+ tl = ArrayGetIntegerTypmods(ta, &n);
+
+ /*
+ * we're not too tense about good error message here because grammar
+ * shouldn't allow wrong number of modifiers for TIMESTAMP
+ */
+ if (n != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid type modifier")));
+
+ return anytimestamp_typmod_check(istz, tl[0]);
+}
+
/* common code for timestamptypmodout and timestamptztypmodout */
static char *
anytimestamp_typmodout(bool istz, int32 typmod)
@@ -1586,33 +1585,48 @@ GetCurrentTimestamp(void)
}
/*
- * GetSQLCurrentTimestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
+ * current_timestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
*/
-TimestampTz
-GetSQLCurrentTimestamp(int32 typmod)
+Datum
+current_timestamp(PG_FUNCTION_ARGS)
{
TimestampTz ts;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytimestamp_typmod_check(true, typmod);
+ }
ts = GetCurrentTransactionStartTimestamp();
if (typmod >= 0)
AdjustTimestampForTypmod(&ts, typmod);
- return ts;
+ return TimestampTzGetDatum(ts);
}
/*
- * GetSQLLocalTimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
+ * sql_localtimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
*/
-Timestamp
-GetSQLLocalTimestamp(int32 typmod)
+Datum
+sql_localtimestamp(PG_FUNCTION_ARGS)
{
Timestamp ts;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytimestamp_typmod_check(false, typmod);
+ }
ts = timestamptz2timestamp(GetCurrentTransactionStartTimestamp());
if (typmod >= 0)
AdjustTimestampForTypmod(&ts, typmod);
- return ts;
+ return TimestampGetDatum(ts);
}
+
/*
* timeofday(*) -- returns the current time as a text.
*/
diff --git a/src/backend/utils/misc/queryjumble.c b/src/backend/utils/misc/queryjumble.c
index a8508463e7..0ace74de78 100644
--- a/src/backend/utils/misc/queryjumble.c
+++ b/src/backend/utils/misc/queryjumble.c
@@ -606,15 +606,6 @@ JumbleExpr(JumbleState *jstate, Node *node)
JumbleExpr(jstate, (Node *) mmexpr->args);
}
break;
- case T_SQLValueFunction:
- {
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- APP_JUMB(svf->op);
- /* type is fully determined by op */
- APP_JUMB(svf->typmod);
- }
- break;
case T_XmlExpr:
{
XmlExpr *xexpr = (XmlExpr *) node;
diff --git a/src/test/regress/expected/expressions.out b/src/test/regress/expected/expressions.out
index 5bf39fd9aa..28a20900f1 100644
--- a/src/test/regress/expected/expressions.out
+++ b/src/test/regress/expected/expressions.out
@@ -2,7 +2,7 @@
-- expression evaluation tests that don't fit into a more specific file
--
--
--- Tests for SQLValueFunction
+-- Tests for various FuncCalls with COERCE_SQL_SYNTAX.
--
-- current_date (always matches because of transactional behaviour)
SELECT date(now())::text = current_date::text;
diff --git a/src/test/regress/sql/expressions.sql b/src/test/regress/sql/expressions.sql
index 0e163cc0d7..f9a0299d17 100644
--- a/src/test/regress/sql/expressions.sql
+++ b/src/test/regress/sql/expressions.sql
@@ -3,7 +3,7 @@
--
--
--- Tests for SQLValueFunction
+-- Tests for various FuncCalls with COERCE_SQL_SYNTAX.
--
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 2f02cc8f42..e45a14b60c 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2397,8 +2397,6 @@ SQLFunctionCache
SQLFunctionCachePtr
SQLFunctionParseInfo
SQLFunctionParseInfoPtr
-SQLValueFunction
-SQLValueFunctionOp
SSL
SSLExtensionInfoContext
SSL_CTX
--
2.37.2
On Tue, Oct 25, 2022 at 02:20:12PM +0900, Michael Paquier wrote:
Attached is a rebased patch set, as of the conflicts from 2e0d80c.
So, this patch set has been sitting in the CF app for a few weeks now,
and I would like to apply them to remove a bit of code from the
executor.
Please note that in order to avoid tweaks when choosing the attribute
name of function call, this needs a total of 8 new catalog functions
mapping to the SQL keywords, which is what the test added by 2e0d80c
is about:
- current_role
- user
- current_catalog
- current_date
- current_time
- current_timestamp
- localtime
- localtimestamp
Any objections?
--
Michael
On Fri, Nov 18, 2022 at 10:23:58AM +0900, Michael Paquier wrote:
Please note that in order to avoid tweaks when choosing the attribute
name of function call, this needs a total of 8 new catalog functions
mapping to the SQL keywords, which is what the test added by 2e0d80c
is about:
- current_role
- user
- current_catalog
- current_date
- current_time
- current_timestamp
- localtime
- localtimestampAny objections?
Hearing nothing, I have gone through 0001 again and applied it as
fb32748 to remove the dependency between names and SQLValueFunction.
Attached is 0002, to bring back the CI to a green state.
--
Michael
Attachments:
v4-0001-Replace-SQLValueFunction-by-direct-function-calls.patchtext/x-diff; charset=us-asciiDownload
From 3611cfa6f0171dcd65eeb88461f4c48989cd3f1a Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Sun, 20 Nov 2022 11:53:28 +0900
Subject: [PATCH v4] Replace SQLValueFunction by direct function calls
This impacts 9 patterns where the SQL grammar takes priority:
- localtime, that can take a typmod.
- localtimestamp, that can take a typmod.
- current_time, that can take a typmod.
- current_timestamp, that can take a typmod.
- current_date.
Five new entries are added to pg_proc to compensate the removal of
SQLValueFunction to keep compatibility (when a keyword is specified in a
SELECT or in a FROM clause without an alias), with tests to cover all
that.
XXX: bump catalog version.
Reviewed-by: Corey Huinker
Discussion: https://postgr.es/m/YzaG3MoryCguUOym@paquier.xyz
---
src/include/catalog/pg_proc.dat | 15 +++
src/include/executor/execExpr.h | 8 --
src/include/nodes/primnodes.h | 33 -------
src/include/utils/date.h | 4 -
src/include/utils/timestamp.h | 4 -
src/backend/catalog/system_functions.sql | 26 ++++++
src/backend/executor/execExpr.c | 11 ---
src/backend/executor/execExprInterp.c | 46 ---------
src/backend/jit/llvm/llvmjit_expr.c | 6 --
src/backend/jit/llvm/llvmjit_types.c | 1 -
src/backend/nodes/nodeFuncs.c | 27 +-----
src/backend/optimizer/path/costsize.c | 1 -
src/backend/optimizer/util/clauses.c | 39 ++------
src/backend/parser/gram.y | 59 +++++++-----
src/backend/parser/parse_expr.c | 52 -----------
src/backend/parser/parse_target.c | 25 -----
src/backend/utils/adt/date.c | 81 +++++++++-------
src/backend/utils/adt/ruleutils.c | 109 +++++++++++++---------
src/backend/utils/adt/timestamp.c | 72 ++++++++------
src/backend/utils/misc/queryjumble.c | 9 --
src/test/regress/expected/expressions.out | 2 +-
src/test/regress/sql/expressions.sql | 2 +-
src/tools/pgindent/typedefs.list | 2 -
23 files changed, 245 insertions(+), 389 deletions(-)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index fd2559442e..35dc369728 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -1520,6 +1520,21 @@
{ oid => '9977', descr => 'system user name',
proname => 'system_user', provolatile => 's', prorettype => 'text',
proargtypes => '', prosrc => 'system_user' },
+{ oid => '9978', descr => 'current date',
+ proname => 'current_date', provolatile => 's', prorettype => 'date',
+ proargtypes => '', prosrc => 'current_date' },
+{ oid => '9979', descr => 'current time',
+ proname => 'current_time', provolatile => 's', prorettype => 'timetz',
+ proargtypes => 'int4', prosrc => 'current_time', proisstrict => 'f' },
+{ oid => '9980', descr => 'current timestamp',
+ proname => 'current_timestamp', provolatile => 's', prorettype => 'timestamptz',
+ proargtypes => 'int4', prosrc => 'current_timestamp', proisstrict => 'f' },
+{ oid => '9981', descr => 'local time',
+ proname => 'localtime', provolatile => 's', prorettype => 'time',
+ proargtypes => 'int4', prosrc => 'sql_localtime', proisstrict => 'f' },
+{ oid => '9982', descr => 'local timestamp',
+ proname => 'localtimestamp', provolatile => 's', prorettype => 'timestamp',
+ proargtypes => 'int4', prosrc => 'sql_localtimestamp', proisstrict => 'f' },
{ oid => '744',
proname => 'array_eq', prorettype => 'bool',
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index e14f15d435..0557302b92 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -170,7 +170,6 @@ typedef enum ExprEvalOp
EEOP_DISTINCT,
EEOP_NOT_DISTINCT,
EEOP_NULLIF,
- EEOP_SQLVALUEFUNCTION,
EEOP_CURRENTOFEXPR,
EEOP_NEXTVALUEEXPR,
EEOP_ARRAYEXPR,
@@ -416,12 +415,6 @@ typedef struct ExprEvalStep
FunctionCallInfo fcinfo_data_in;
} iocoerce;
- /* for EEOP_SQLVALUEFUNCTION */
- struct
- {
- SQLValueFunction *svf;
- } sqlvaluefunction;
-
/* for EEOP_NEXTVALUEEXPR */
struct
{
@@ -741,7 +734,6 @@ extern void ExecEvalParamExec(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
extern void ExecEvalParamExtern(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
-extern void ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op);
extern void ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op);
extern void ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op);
extern void ExecEvalRowNull(ExprState *state, ExprEvalStep *op,
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index f6dd27edcc..74f228d959 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1292,39 +1292,6 @@ typedef struct MinMaxExpr
int location; /* token location, or -1 if unknown */
} MinMaxExpr;
-/*
- * SQLValueFunction - parameterless functions with special grammar productions
- *
- * The SQL standard categorizes some of these as <datetime value function>
- * and others as <general value specification>. We call 'em SQLValueFunctions
- * for lack of a better term. We store type and typmod of the result so that
- * some code doesn't need to know each function individually, and because
- * we would need to store typmod anyway for some of the datetime functions.
- * Note that currently, all variants return non-collating datatypes, so we do
- * not need a collation field; also, all these functions are stable.
- */
-typedef enum SQLValueFunctionOp
-{
- SVFOP_CURRENT_DATE,
- SVFOP_CURRENT_TIME,
- SVFOP_CURRENT_TIME_N,
- SVFOP_CURRENT_TIMESTAMP,
- SVFOP_CURRENT_TIMESTAMP_N,
- SVFOP_LOCALTIME,
- SVFOP_LOCALTIME_N,
- SVFOP_LOCALTIMESTAMP,
- SVFOP_LOCALTIMESTAMP_N
-} SQLValueFunctionOp;
-
-typedef struct SQLValueFunction
-{
- Expr xpr;
- SQLValueFunctionOp op; /* which function this is */
- Oid type; /* result type/typmod */
- int32 typmod;
- int location; /* token location, or -1 if unknown */
-} SQLValueFunction;
-
/*
* XmlExpr - various SQL/XML functions requiring special grammar productions
*
diff --git a/src/include/utils/date.h b/src/include/utils/date.h
index 0bbe889128..fad4878722 100644
--- a/src/include/utils/date.h
+++ b/src/include/utils/date.h
@@ -96,7 +96,6 @@ TimeTzADTPGetDatum(const TimeTzADT *X)
/* date.c */
-extern int32 anytime_typmod_check(bool istz, int32 typmod);
extern double date2timestamp_no_overflow(DateADT dateVal);
extern Timestamp date2timestamp_opt_overflow(DateADT dateVal, int *overflow);
extern TimestampTz date2timestamptz_opt_overflow(DateADT dateVal, int *overflow);
@@ -104,9 +103,6 @@ extern int32 date_cmp_timestamp_internal(DateADT dateVal, Timestamp dt2);
extern int32 date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2);
extern void EncodeSpecialDate(DateADT dt, char *str);
-extern DateADT GetSQLCurrentDate(void);
-extern TimeTzADT *GetSQLCurrentTime(int32 typmod);
-extern TimeADT GetSQLLocalTime(int32 typmod);
extern int time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec);
extern int timetz2tm(TimeTzADT *time, struct pg_tm *tm, fsec_t *fsec, int *tzp);
extern int tm2time(struct pg_tm *tm, fsec_t fsec, TimeADT *result);
diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h
index 76b7b4a3ca..7fd0b58825 100644
--- a/src/include/utils/timestamp.h
+++ b/src/include/utils/timestamp.h
@@ -93,11 +93,7 @@ extern PGDLLIMPORT TimestampTz PgReloadTime;
/* Internal routines (not fmgr-callable) */
-extern int32 anytimestamp_typmod_check(bool istz, int32 typmod);
-
extern TimestampTz GetCurrentTimestamp(void);
-extern TimestampTz GetSQLCurrentTimestamp(int32 typmod);
-extern Timestamp GetSQLLocalTimestamp(int32 typmod);
extern void TimestampDifference(TimestampTz start_time, TimestampTz stop_time,
long *secs, int *microsecs);
extern long TimestampDifferenceMilliseconds(TimestampTz start_time,
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 30a048f6b0..4c3b4c3f8e 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,32 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+-- Functions with SQL-mandated special syntax and some defaults.
+CREATE OR REPLACE FUNCTION
+ "current_time"(int4 DEFAULT NULL)
+RETURNS timetz
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'current_time';
+CREATE OR REPLACE FUNCTION
+ "current_timestamp"(int4 DEFAULT NULL)
+RETURNS timestamptz
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'current_timestamp';
+CREATE OR REPLACE FUNCTION
+ "localtime"(int4 DEFAULT NULL)
+RETURNS time
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'sql_localtime';
+CREATE OR REPLACE FUNCTION
+ "localtimestamp"(int4 DEFAULT NULL)
+RETURNS timestamp
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'sql_localtimestamp';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 0ecb2f8610..81429b9f05 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -2210,17 +2210,6 @@ ExecInitExprRec(Expr *node, ExprState *state,
break;
}
- case T_SQLValueFunction:
- {
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- scratch.opcode = EEOP_SQLVALUEFUNCTION;
- scratch.d.sqlvaluefunction.svf = svf;
-
- ExprEvalPushStep(state, &scratch);
- break;
- }
-
case T_XmlExpr:
{
XmlExpr *xexpr = (XmlExpr *) node;
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6ebf5c287e..1dab2787b7 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -452,7 +452,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
&&CASE_EEOP_DISTINCT,
&&CASE_EEOP_NOT_DISTINCT,
&&CASE_EEOP_NULLIF,
- &&CASE_EEOP_SQLVALUEFUNCTION,
&&CASE_EEOP_CURRENTOFEXPR,
&&CASE_EEOP_NEXTVALUEEXPR,
&&CASE_EEOP_ARRAYEXPR,
@@ -1301,17 +1300,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
EEO_NEXT();
}
- EEO_CASE(EEOP_SQLVALUEFUNCTION)
- {
- /*
- * Doesn't seem worthwhile to have an inline implementation
- * efficiency-wise.
- */
- ExecEvalSQLValueFunction(state, op);
-
- EEO_NEXT();
- }
-
EEO_CASE(EEOP_CURRENTOFEXPR)
{
/* error invocation uses space, and shouldn't ever occur */
@@ -2489,40 +2477,6 @@ ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
errmsg("no value found for parameter %d", paramId)));
}
-/*
- * Evaluate a SQLValueFunction expression.
- */
-void
-ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
-{
- SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
-
- *op->resnull = false;
-
- switch (svf->op)
- {
- case SVFOP_CURRENT_DATE:
- *op->resvalue = DateADTGetDatum(GetSQLCurrentDate());
- break;
- case SVFOP_CURRENT_TIME:
- case SVFOP_CURRENT_TIME_N:
- *op->resvalue = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod));
- break;
- case SVFOP_CURRENT_TIMESTAMP:
- case SVFOP_CURRENT_TIMESTAMP_N:
- *op->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod));
- break;
- case SVFOP_LOCALTIME:
- case SVFOP_LOCALTIME_N:
- *op->resvalue = TimeADTGetDatum(GetSQLLocalTime(svf->typmod));
- break;
- case SVFOP_LOCALTIMESTAMP:
- case SVFOP_LOCALTIMESTAMP_N:
- *op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
- break;
- }
-}
-
/*
* Raise error if a CURRENT OF expression is evaluated.
*
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index 95d0807bdd..f114337f8e 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -1549,12 +1549,6 @@ llvm_compile_expr(ExprState *state)
break;
}
- case EEOP_SQLVALUEFUNCTION:
- build_EvalXFunc(b, mod, "ExecEvalSQLValueFunction",
- v_state, op);
- LLVMBuildBr(b, opblocks[opno + 1]);
- break;
-
case EEOP_CURRENTOFEXPR:
build_EvalXFunc(b, mod, "ExecEvalCurrentOfExpr",
v_state, op);
diff --git a/src/backend/jit/llvm/llvmjit_types.c b/src/backend/jit/llvm/llvmjit_types.c
index 90ac6b83b5..5b416c5642 100644
--- a/src/backend/jit/llvm/llvmjit_types.c
+++ b/src/backend/jit/llvm/llvmjit_types.c
@@ -126,7 +126,6 @@ void *referenced_functions[] =
ExecEvalRow,
ExecEvalRowNotNull,
ExecEvalRowNull,
- ExecEvalSQLValueFunction,
ExecEvalScalarArrayOp,
ExecEvalHashedScalarArrayOp,
ExecEvalSubPlan,
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 2585a3175c..af8620ceb7 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -210,9 +210,6 @@ exprType(const Node *expr)
case T_MinMaxExpr:
type = ((const MinMaxExpr *) expr)->minmaxtype;
break;
- case T_SQLValueFunction:
- type = ((const SQLValueFunction *) expr)->type;
- break;
case T_XmlExpr:
if (((const XmlExpr *) expr)->op == IS_DOCUMENT)
type = BOOLOID;
@@ -474,8 +471,6 @@ exprTypmod(const Node *expr)
return typmod;
}
break;
- case T_SQLValueFunction:
- return ((const SQLValueFunction *) expr)->typmod;
case T_CoerceToDomain:
return ((const CoerceToDomain *) expr)->resulttypmod;
case T_CoerceToDomainValue:
@@ -916,10 +911,6 @@ exprCollation(const Node *expr)
case T_MinMaxExpr:
coll = ((const MinMaxExpr *) expr)->minmaxcollid;
break;
- case T_SQLValueFunction:
- /* Returns a non-collatable type */
- coll = InvalidOid;
- break;
case T_XmlExpr:
/*
@@ -1140,9 +1131,6 @@ exprSetCollation(Node *expr, Oid collation)
case T_MinMaxExpr:
((MinMaxExpr *) expr)->minmaxcollid = collation;
break;
- case T_SQLValueFunction:
- Assert(collation == InvalidOid);
- break;
case T_XmlExpr:
Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ?
(collation == DEFAULT_COLLATION_OID) :
@@ -1426,10 +1414,6 @@ exprLocation(const Node *expr)
/* GREATEST/LEAST keyword should always be the first thing */
loc = ((const MinMaxExpr *) expr)->location;
break;
- case T_SQLValueFunction:
- /* function keyword should always be the first thing */
- loc = ((const SQLValueFunction *) expr)->location;
- break;
case T_XmlExpr:
{
const XmlExpr *xexpr = (const XmlExpr *) expr;
@@ -1717,10 +1701,10 @@ set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
* for themselves, in case additional checks should be made, or because they
* have special rules about which parts of the tree need to be visited.
*
- * Note: we ignore MinMaxExpr, SQLValueFunction, XmlExpr, CoerceToDomain,
- * and NextValueExpr nodes, because they do not contain SQL function OIDs.
- * However, they can invoke SQL-visible functions, so callers should take
- * thought about how to treat them.
+ * Note: we ignore MinMaxExpr, XmlExpr, CoerceToDomain, and NextValueExpr
+ * nodes, because they do not contain SQL function OIDs. However, they can
+ * invoke SQL-visible functions, so callers should take thought about how
+ * to treat them.
*/
bool
check_functions_in_node(Node *node, check_function_callback checker,
@@ -1936,7 +1920,6 @@ expression_tree_walker_impl(Node *node,
case T_Const:
case T_Param:
case T_CaseTestExpr:
- case T_SQLValueFunction:
case T_CoerceToDomainValue:
case T_SetToDefault:
case T_CurrentOfExpr:
@@ -2673,7 +2656,6 @@ expression_tree_mutator_impl(Node *node,
break;
case T_Param:
case T_CaseTestExpr:
- case T_SQLValueFunction:
case T_CoerceToDomainValue:
case T_SetToDefault:
case T_CurrentOfExpr:
@@ -3587,7 +3569,6 @@ raw_expression_tree_walker_impl(Node *node,
{
case T_SetToDefault:
case T_CurrentOfExpr:
- case T_SQLValueFunction:
case T_Integer:
case T_Float:
case T_Boolean:
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 4c6b1d1f55..897309d7ec 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -4603,7 +4603,6 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
}
}
else if (IsA(node, MinMaxExpr) ||
- IsA(node, SQLValueFunction) ||
IsA(node, XmlExpr) ||
IsA(node, CoerceToDomain) ||
IsA(node, NextValueExpr))
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 33790a4f46..c61d9c68a0 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -383,12 +383,6 @@ contain_mutable_functions_walker(Node *node, void *context)
context))
return true;
- if (IsA(node, SQLValueFunction))
- {
- /* all variants of SQLValueFunction are stable */
- return true;
- }
-
if (IsA(node, NextValueExpr))
{
/* NextValueExpr is volatile */
@@ -537,8 +531,8 @@ contain_volatile_functions_walker(Node *node, void *context)
/*
* See notes in contain_mutable_functions_walker about why we treat
- * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
- * SQLValueFunction is stable. Hence, none of them are of interest here.
+ * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable. Hence, none
+ * of them are of interest here.
*/
/* Recurse to check arguments */
@@ -583,10 +577,9 @@ contain_volatile_functions_not_nextval_walker(Node *node, void *context)
/*
* See notes in contain_mutable_functions_walker about why we treat
- * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
- * SQLValueFunction is stable. Hence, none of them are of interest here.
- * Also, since we're intentionally ignoring nextval(), presumably we
- * should ignore NextValueExpr.
+ * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable. Hence, none
+ * of them are of interest here. Also, since we're intentionally
+ * ignoring nextval(), presumably we should ignore NextValueExpr.
*/
/* Recurse to check arguments */
@@ -732,8 +725,8 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
* (Note: in principle that's wrong because a domain constraint could
* contain a parallel-unsafe function; but useful constraints probably
* never would have such, and assuming they do would cripple use of
- * parallel query in the presence of domain types.) SQLValueFunction
- * should be safe in all cases. NextValueExpr is parallel-unsafe.
+ * parallel query in the presence of domain types.) NextValueExpr is
+ * parallel-unsafe.
*/
if (IsA(node, CoerceToDomain))
{
@@ -1180,7 +1173,6 @@ contain_leaked_vars_walker(Node *node, void *context)
case T_CaseExpr:
case T_CaseTestExpr:
case T_RowExpr:
- case T_SQLValueFunction:
case T_NullTest:
case T_BooleanTest:
case T_NextValueExpr:
@@ -3194,23 +3186,6 @@ eval_const_expressions_mutator(Node *node,
newcoalesce->location = coalesceexpr->location;
return (Node *) newcoalesce;
}
- case T_SQLValueFunction:
- {
- /*
- * All variants of SQLValueFunction are stable, so if we are
- * estimating the expression's value, we should evaluate the
- * current function value. Otherwise just copy.
- */
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- if (context->estimate)
- return (Node *) evaluate_expr((Expr *) svf,
- svf->type,
- svf->typmod,
- InvalidOid);
- else
- return copyObject((Node *) svf);
- }
case T_FieldSelect:
{
/*
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 9054742427..9384214942 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -198,8 +198,6 @@ static Node *makeAndExpr(Node *lexpr, Node *rexpr, int location);
static Node *makeOrExpr(Node *lexpr, Node *rexpr, int location);
static Node *makeNotExpr(Node *expr, int location);
static Node *makeAArrayExpr(List *elements, int location);
-static Node *makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod,
- int location);
static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
List *args, int location);
static List *mergeTableFuncParameters(List *func_args, List *columns);
@@ -15195,39 +15193,66 @@ func_expr_common_subexpr:
}
| CURRENT_DATE
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_DATE, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_date"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIME
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_time"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIME '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_time"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIMESTAMP
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_timestamp"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIMESTAMP '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_timestamp"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIME
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIME, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtime"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIME '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIME_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtime"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIMESTAMP
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtimestamp"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIMESTAMP '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtimestamp"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_ROLE
{
@@ -18166,18 +18191,6 @@ makeAArrayExpr(List *elements, int location)
return (Node *) n;
}
-static Node *
-makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, int location)
-{
- SQLValueFunction *svf = makeNode(SQLValueFunction);
-
- svf->op = op;
- /* svf->type will be filled during parse analysis */
- svf->typmod = typmod;
- svf->location = location;
- return (Node *) svf;
-}
-
static Node *
makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
int location)
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 0fdbf82f3a..150a8099c2 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -61,8 +61,6 @@ static Node *transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
static Node *transformRowExpr(ParseState *pstate, RowExpr *r, bool allowDefault);
static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c);
static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m);
-static Node *transformSQLValueFunction(ParseState *pstate,
- SQLValueFunction *svf);
static Node *transformXmlExpr(ParseState *pstate, XmlExpr *x);
static Node *transformXmlSerialize(ParseState *pstate, XmlSerialize *xs);
static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
@@ -240,11 +238,6 @@ transformExprRecurse(ParseState *pstate, Node *expr)
result = transformMinMaxExpr(pstate, (MinMaxExpr *) expr);
break;
- case T_SQLValueFunction:
- result = transformSQLValueFunction(pstate,
- (SQLValueFunction *) expr);
- break;
-
case T_XmlExpr:
result = transformXmlExpr(pstate, (XmlExpr *) expr);
break;
@@ -2191,51 +2184,6 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m)
return (Node *) newm;
}
-static Node *
-transformSQLValueFunction(ParseState *pstate, SQLValueFunction *svf)
-{
- /*
- * All we need to do is insert the correct result type and (where needed)
- * validate the typmod, so we just modify the node in-place.
- */
- switch (svf->op)
- {
- case SVFOP_CURRENT_DATE:
- svf->type = DATEOID;
- break;
- case SVFOP_CURRENT_TIME:
- svf->type = TIMETZOID;
- break;
- case SVFOP_CURRENT_TIME_N:
- svf->type = TIMETZOID;
- svf->typmod = anytime_typmod_check(true, svf->typmod);
- break;
- case SVFOP_CURRENT_TIMESTAMP:
- svf->type = TIMESTAMPTZOID;
- break;
- case SVFOP_CURRENT_TIMESTAMP_N:
- svf->type = TIMESTAMPTZOID;
- svf->typmod = anytimestamp_typmod_check(true, svf->typmod);
- break;
- case SVFOP_LOCALTIME:
- svf->type = TIMEOID;
- break;
- case SVFOP_LOCALTIME_N:
- svf->type = TIMEOID;
- svf->typmod = anytime_typmod_check(false, svf->typmod);
- break;
- case SVFOP_LOCALTIMESTAMP:
- svf->type = TIMESTAMPOID;
- break;
- case SVFOP_LOCALTIMESTAMP_N:
- svf->type = TIMESTAMPOID;
- svf->typmod = anytimestamp_typmod_check(false, svf->typmod);
- break;
- }
-
- return (Node *) svf;
-}
-
static Node *
transformXmlExpr(ParseState *pstate, XmlExpr *x)
{
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index f54591a987..8e0d6fd01f 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1872,31 +1872,6 @@ FigureColnameInternal(Node *node, char **name)
return 2;
}
break;
- case T_SQLValueFunction:
- /* make these act like a function or variable */
- switch (((SQLValueFunction *) node)->op)
- {
- case SVFOP_CURRENT_DATE:
- *name = "current_date";
- return 2;
- case SVFOP_CURRENT_TIME:
- case SVFOP_CURRENT_TIME_N:
- *name = "current_time";
- return 2;
- case SVFOP_CURRENT_TIMESTAMP:
- case SVFOP_CURRENT_TIMESTAMP_N:
- *name = "current_timestamp";
- return 2;
- case SVFOP_LOCALTIME:
- case SVFOP_LOCALTIME_N:
- *name = "localtime";
- return 2;
- case SVFOP_LOCALTIMESTAMP:
- case SVFOP_LOCALTIMESTAMP_N:
- *name = "localtimestamp";
- return 2;
- }
- break;
case T_XmlExpr:
/* make SQL/XML functions act like a regular function */
switch (((XmlExpr *) node)->op)
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index a2bdde0459..10c11e00db 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -46,27 +46,6 @@
/* common code for timetypmodin and timetztypmodin */
static int32
-anytime_typmodin(bool istz, ArrayType *ta)
-{
- int32 *tl;
- int n;
-
- tl = ArrayGetIntegerTypmods(ta, &n);
-
- /*
- * we're not too tense about good error message here because grammar
- * shouldn't allow wrong number of modifiers for TIME
- */
- if (n != 1)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("invalid type modifier")));
-
- return anytime_typmod_check(istz, tl[0]);
-}
-
-/* exported so parse_expr.c can use it */
-int32
anytime_typmod_check(bool istz, int32 typmod)
{
if (typmod < 0)
@@ -87,6 +66,26 @@ anytime_typmod_check(bool istz, int32 typmod)
return typmod;
}
+static int32
+anytime_typmodin(bool istz, ArrayType *ta)
+{
+ int32 *tl;
+ int n;
+
+ tl = ArrayGetIntegerTypmods(ta, &n);
+
+ /*
+ * we're not too tense about good error message here because grammar
+ * shouldn't allow wrong number of modifiers for TIME
+ */
+ if (n != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid type modifier")));
+
+ return anytime_typmod_check(istz, tl[0]);
+}
+
/* common code for timetypmodout and timetztypmodout */
static char *
anytime_typmodout(bool istz, int32 typmod)
@@ -296,10 +295,10 @@ EncodeSpecialDate(DateADT dt, char *str)
/*
- * GetSQLCurrentDate -- implements CURRENT_DATE
+ * current_date -- implements CURRENT_DATE
*/
-DateADT
-GetSQLCurrentDate(void)
+Datum
+current_date(PG_FUNCTION_ARGS)
{
struct pg_tm tm;
@@ -325,46 +324,62 @@ GetSQLCurrentDate(void)
cache_mday = tm.tm_mday;
}
- return cache_date;
+ return DateADTGetDatum(cache_date);
}
/*
- * GetSQLCurrentTime -- implements CURRENT_TIME, CURRENT_TIME(n)
+ * current_time -- implements CURRENT_TIME, CURRENT_TIME(n)
*/
-TimeTzADT *
-GetSQLCurrentTime(int32 typmod)
+Datum
+current_time(PG_FUNCTION_ARGS)
{
TimeTzADT *result;
struct pg_tm tt,
*tm = &tt;
fsec_t fsec;
int tz;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytime_typmod_check(true, typmod);
+ }
GetCurrentTimeUsec(tm, &fsec, &tz);
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
tm2timetz(tm, fsec, tz, result);
AdjustTimeForTypmod(&(result->time), typmod);
- return result;
+
+ return TimeTzADTPGetDatum(result);
}
/*
- * GetSQLLocalTime -- implements LOCALTIME, LOCALTIME(n)
+ * sql_localtime -- implements LOCALTIME, LOCALTIME(n)
*/
-TimeADT
-GetSQLLocalTime(int32 typmod)
+Datum
+sql_localtime(PG_FUNCTION_ARGS)
{
TimeADT result;
struct pg_tm tt,
*tm = &tt;
fsec_t fsec;
int tz;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytime_typmod_check(false, typmod);
+ }
GetCurrentTimeUsec(tm, &fsec, &tz);
tm2time(tm, fsec, &result);
AdjustTimeForTypmod(&result, typmod);
- return result;
+
+ return TimeADTGetDatum(result);
}
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 129f3333fb..c00dc5e32e 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -8150,7 +8150,6 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_RowExpr:
case T_CoalesceExpr:
case T_MinMaxExpr:
- case T_SQLValueFunction:
case T_XmlExpr:
case T_NextValueExpr:
case T_NullIfExpr:
@@ -9130,49 +9129,6 @@ get_rule_expr(Node *node, deparse_context *context,
}
break;
- case T_SQLValueFunction:
- {
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- /*
- * Note: this code knows that typmod for time, timestamp, and
- * timestamptz just prints as integer.
- */
- switch (svf->op)
- {
- case SVFOP_CURRENT_DATE:
- appendStringInfoString(buf, "CURRENT_DATE");
- break;
- case SVFOP_CURRENT_TIME:
- appendStringInfoString(buf, "CURRENT_TIME");
- break;
- case SVFOP_CURRENT_TIME_N:
- appendStringInfo(buf, "CURRENT_TIME(%d)", svf->typmod);
- break;
- case SVFOP_CURRENT_TIMESTAMP:
- appendStringInfoString(buf, "CURRENT_TIMESTAMP");
- break;
- case SVFOP_CURRENT_TIMESTAMP_N:
- appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)",
- svf->typmod);
- break;
- case SVFOP_LOCALTIME:
- appendStringInfoString(buf, "LOCALTIME");
- break;
- case SVFOP_LOCALTIME_N:
- appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod);
- break;
- case SVFOP_LOCALTIMESTAMP:
- appendStringInfoString(buf, "LOCALTIMESTAMP");
- break;
- case SVFOP_LOCALTIMESTAMP_N:
- appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
- svf->typmod);
- break;
- }
- }
- break;
-
case T_XmlExpr:
{
XmlExpr *xexpr = (XmlExpr *) node;
@@ -9698,7 +9654,6 @@ looks_like_function(Node *node)
case T_NullIfExpr:
case T_CoalesceExpr:
case T_MinMaxExpr:
- case T_SQLValueFunction:
case T_XmlExpr:
/* these are all accepted by func_expr_common_subexpr */
return true;
@@ -10292,6 +10247,70 @@ get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
appendStringInfoString(buf, "SYSTEM_USER");
return true;
+ case F_CURRENT_DATE:
+ appendStringInfoString(buf, "CURRENT_DATE");
+ return true;
+ case F_CURRENT_TIME:
+ appendStringInfoString(buf, "CURRENT_TIME");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+ case F_CURRENT_TIMESTAMP:
+ appendStringInfoString(buf, "CURRENT_TIMESTAMP");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+ case F_LOCALTIME:
+ appendStringInfoString(buf, "LOCALTIME");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+ case F_LOCALTIMESTAMP:
+ appendStringInfoString(buf, "LOCALTIMESTAMP");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+
case F_XMLEXISTS:
/* XMLEXISTS ... extra parens because args are c_expr */
appendStringInfoString(buf, "XMLEXISTS((");
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index d8552a1f18..ef92323fd0 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -81,27 +81,6 @@ static Timestamp timestamptz2timestamp(TimestampTz timestamp);
/* common code for timestamptypmodin and timestamptztypmodin */
static int32
-anytimestamp_typmodin(bool istz, ArrayType *ta)
-{
- int32 *tl;
- int n;
-
- tl = ArrayGetIntegerTypmods(ta, &n);
-
- /*
- * we're not too tense about good error message here because grammar
- * shouldn't allow wrong number of modifiers for TIMESTAMP
- */
- if (n != 1)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("invalid type modifier")));
-
- return anytimestamp_typmod_check(istz, tl[0]);
-}
-
-/* exported so parse_expr.c can use it */
-int32
anytimestamp_typmod_check(bool istz, int32 typmod)
{
if (typmod < 0)
@@ -122,6 +101,26 @@ anytimestamp_typmod_check(bool istz, int32 typmod)
return typmod;
}
+static int32
+anytimestamp_typmodin(bool istz, ArrayType *ta)
+{
+ int32 *tl;
+ int n;
+
+ tl = ArrayGetIntegerTypmods(ta, &n);
+
+ /*
+ * we're not too tense about good error message here because grammar
+ * shouldn't allow wrong number of modifiers for TIMESTAMP
+ */
+ if (n != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid type modifier")));
+
+ return anytimestamp_typmod_check(istz, tl[0]);
+}
+
/* common code for timestamptypmodout and timestamptztypmodout */
static char *
anytimestamp_typmodout(bool istz, int32 typmod)
@@ -1586,33 +1585,48 @@ GetCurrentTimestamp(void)
}
/*
- * GetSQLCurrentTimestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
+ * current_timestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
*/
-TimestampTz
-GetSQLCurrentTimestamp(int32 typmod)
+Datum
+current_timestamp(PG_FUNCTION_ARGS)
{
TimestampTz ts;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytimestamp_typmod_check(true, typmod);
+ }
ts = GetCurrentTransactionStartTimestamp();
if (typmod >= 0)
AdjustTimestampForTypmod(&ts, typmod);
- return ts;
+ return TimestampTzGetDatum(ts);
}
/*
- * GetSQLLocalTimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
+ * sql_localtimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
*/
-Timestamp
-GetSQLLocalTimestamp(int32 typmod)
+Datum
+sql_localtimestamp(PG_FUNCTION_ARGS)
{
Timestamp ts;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytimestamp_typmod_check(false, typmod);
+ }
ts = timestamptz2timestamp(GetCurrentTransactionStartTimestamp());
if (typmod >= 0)
AdjustTimestampForTypmod(&ts, typmod);
- return ts;
+ return TimestampGetDatum(ts);
}
+
/*
* timeofday(*) -- returns the current time as a text.
*/
diff --git a/src/backend/utils/misc/queryjumble.c b/src/backend/utils/misc/queryjumble.c
index a8508463e7..0ace74de78 100644
--- a/src/backend/utils/misc/queryjumble.c
+++ b/src/backend/utils/misc/queryjumble.c
@@ -606,15 +606,6 @@ JumbleExpr(JumbleState *jstate, Node *node)
JumbleExpr(jstate, (Node *) mmexpr->args);
}
break;
- case T_SQLValueFunction:
- {
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- APP_JUMB(svf->op);
- /* type is fully determined by op */
- APP_JUMB(svf->typmod);
- }
- break;
case T_XmlExpr:
{
XmlExpr *xexpr = (XmlExpr *) node;
diff --git a/src/test/regress/expected/expressions.out b/src/test/regress/expected/expressions.out
index 5bf39fd9aa..28a20900f1 100644
--- a/src/test/regress/expected/expressions.out
+++ b/src/test/regress/expected/expressions.out
@@ -2,7 +2,7 @@
-- expression evaluation tests that don't fit into a more specific file
--
--
--- Tests for SQLValueFunction
+-- Tests for various FuncCalls with COERCE_SQL_SYNTAX.
--
-- current_date (always matches because of transactional behaviour)
SELECT date(now())::text = current_date::text;
diff --git a/src/test/regress/sql/expressions.sql b/src/test/regress/sql/expressions.sql
index 0e163cc0d7..f9a0299d17 100644
--- a/src/test/regress/sql/expressions.sql
+++ b/src/test/regress/sql/expressions.sql
@@ -3,7 +3,7 @@
--
--
--- Tests for SQLValueFunction
+-- Tests for various FuncCalls with COERCE_SQL_SYNTAX.
--
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index f8302f1ed1..2f5802195d 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2397,8 +2397,6 @@ SQLFunctionCache
SQLFunctionCachePtr
SQLFunctionParseInfo
SQLFunctionParseInfoPtr
-SQLValueFunction
-SQLValueFunctionOp
SSL
SSLExtensionInfoContext
SSL_CTX
--
2.38.1
On Sat, Nov 19, 2022 at 7:01 PM Michael Paquier <michael@paquier.xyz> wrote:
On Fri, Nov 18, 2022 at 10:23:58AM +0900, Michael Paquier wrote:
Please note that in order to avoid tweaks when choosing the attribute
name of function call, this needs a total of 8 new catalog functions
mapping to the SQL keywords, which is what the test added by 2e0d80c
is about:
- current_role
- user
- current_catalog
- current_date
- current_time
- current_timestamp
- localtime
- localtimestampAny objections?
Hearing nothing, I have gone through 0001 again and applied it as
fb32748 to remove the dependency between names and SQLValueFunction.
Attached is 0002, to bring back the CI to a green state.
--
Michael
Hi,
For get_func_sql_syntax(), the code for cases
of F_CURRENT_TIME, F_CURRENT_TIMESTAMP, F_LOCALTIME and F_LOCALTIMESTAMP is
mostly the same.
Maybe we can introduce a helper so that code duplication is reduced.
Cheers
On Sun, Nov 20, 2022 at 08:21:10AM -0800, Ted Yu wrote:
For get_func_sql_syntax(), the code for cases
of F_CURRENT_TIME, F_CURRENT_TIMESTAMP, F_LOCALTIME and F_LOCALTIMESTAMP is
mostly the same.
Maybe we can introduce a helper so that code duplication is reduced.
It would. Thanks for the suggestion.
Do you like something like the patch 0002 attached? This reduces a
bit the overall size of the patch. Both ought to be merged in the
same commit, still it is easier to see the simplification created.
--
Michael
Attachments:
v5-0001-Replace-SQLValueFunction-by-direct-function-calls.patchtext/x-diff; charset=us-asciiDownload
From 3611cfa6f0171dcd65eeb88461f4c48989cd3f1a Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Sun, 20 Nov 2022 11:53:28 +0900
Subject: [PATCH v5 1/2] Replace SQLValueFunction by direct function calls
This impacts 9 patterns where the SQL grammar takes priority:
- localtime, that can take a typmod.
- localtimestamp, that can take a typmod.
- current_time, that can take a typmod.
- current_timestamp, that can take a typmod.
- current_date.
Five new entries are added to pg_proc to compensate the removal of
SQLValueFunction to keep compatibility (when a keyword is specified in a
SELECT or in a FROM clause without an alias), with tests to cover all
that.
XXX: bump catalog version.
Reviewed-by: Corey Huinker
Discussion: https://postgr.es/m/YzaG3MoryCguUOym@paquier.xyz
---
src/include/catalog/pg_proc.dat | 15 +++
src/include/executor/execExpr.h | 8 --
src/include/nodes/primnodes.h | 33 -------
src/include/utils/date.h | 4 -
src/include/utils/timestamp.h | 4 -
src/backend/catalog/system_functions.sql | 26 ++++++
src/backend/executor/execExpr.c | 11 ---
src/backend/executor/execExprInterp.c | 46 ---------
src/backend/jit/llvm/llvmjit_expr.c | 6 --
src/backend/jit/llvm/llvmjit_types.c | 1 -
src/backend/nodes/nodeFuncs.c | 27 +-----
src/backend/optimizer/path/costsize.c | 1 -
src/backend/optimizer/util/clauses.c | 39 ++------
src/backend/parser/gram.y | 59 +++++++-----
src/backend/parser/parse_expr.c | 52 -----------
src/backend/parser/parse_target.c | 25 -----
src/backend/utils/adt/date.c | 81 +++++++++-------
src/backend/utils/adt/ruleutils.c | 109 +++++++++++++---------
src/backend/utils/adt/timestamp.c | 72 ++++++++------
src/backend/utils/misc/queryjumble.c | 9 --
src/test/regress/expected/expressions.out | 2 +-
src/test/regress/sql/expressions.sql | 2 +-
src/tools/pgindent/typedefs.list | 2 -
23 files changed, 245 insertions(+), 389 deletions(-)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index fd2559442e..35dc369728 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -1520,6 +1520,21 @@
{ oid => '9977', descr => 'system user name',
proname => 'system_user', provolatile => 's', prorettype => 'text',
proargtypes => '', prosrc => 'system_user' },
+{ oid => '9978', descr => 'current date',
+ proname => 'current_date', provolatile => 's', prorettype => 'date',
+ proargtypes => '', prosrc => 'current_date' },
+{ oid => '9979', descr => 'current time',
+ proname => 'current_time', provolatile => 's', prorettype => 'timetz',
+ proargtypes => 'int4', prosrc => 'current_time', proisstrict => 'f' },
+{ oid => '9980', descr => 'current timestamp',
+ proname => 'current_timestamp', provolatile => 's', prorettype => 'timestamptz',
+ proargtypes => 'int4', prosrc => 'current_timestamp', proisstrict => 'f' },
+{ oid => '9981', descr => 'local time',
+ proname => 'localtime', provolatile => 's', prorettype => 'time',
+ proargtypes => 'int4', prosrc => 'sql_localtime', proisstrict => 'f' },
+{ oid => '9982', descr => 'local timestamp',
+ proname => 'localtimestamp', provolatile => 's', prorettype => 'timestamp',
+ proargtypes => 'int4', prosrc => 'sql_localtimestamp', proisstrict => 'f' },
{ oid => '744',
proname => 'array_eq', prorettype => 'bool',
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index e14f15d435..0557302b92 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -170,7 +170,6 @@ typedef enum ExprEvalOp
EEOP_DISTINCT,
EEOP_NOT_DISTINCT,
EEOP_NULLIF,
- EEOP_SQLVALUEFUNCTION,
EEOP_CURRENTOFEXPR,
EEOP_NEXTVALUEEXPR,
EEOP_ARRAYEXPR,
@@ -416,12 +415,6 @@ typedef struct ExprEvalStep
FunctionCallInfo fcinfo_data_in;
} iocoerce;
- /* for EEOP_SQLVALUEFUNCTION */
- struct
- {
- SQLValueFunction *svf;
- } sqlvaluefunction;
-
/* for EEOP_NEXTVALUEEXPR */
struct
{
@@ -741,7 +734,6 @@ extern void ExecEvalParamExec(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
extern void ExecEvalParamExtern(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
-extern void ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op);
extern void ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op);
extern void ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op);
extern void ExecEvalRowNull(ExprState *state, ExprEvalStep *op,
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index f6dd27edcc..74f228d959 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1292,39 +1292,6 @@ typedef struct MinMaxExpr
int location; /* token location, or -1 if unknown */
} MinMaxExpr;
-/*
- * SQLValueFunction - parameterless functions with special grammar productions
- *
- * The SQL standard categorizes some of these as <datetime value function>
- * and others as <general value specification>. We call 'em SQLValueFunctions
- * for lack of a better term. We store type and typmod of the result so that
- * some code doesn't need to know each function individually, and because
- * we would need to store typmod anyway for some of the datetime functions.
- * Note that currently, all variants return non-collating datatypes, so we do
- * not need a collation field; also, all these functions are stable.
- */
-typedef enum SQLValueFunctionOp
-{
- SVFOP_CURRENT_DATE,
- SVFOP_CURRENT_TIME,
- SVFOP_CURRENT_TIME_N,
- SVFOP_CURRENT_TIMESTAMP,
- SVFOP_CURRENT_TIMESTAMP_N,
- SVFOP_LOCALTIME,
- SVFOP_LOCALTIME_N,
- SVFOP_LOCALTIMESTAMP,
- SVFOP_LOCALTIMESTAMP_N
-} SQLValueFunctionOp;
-
-typedef struct SQLValueFunction
-{
- Expr xpr;
- SQLValueFunctionOp op; /* which function this is */
- Oid type; /* result type/typmod */
- int32 typmod;
- int location; /* token location, or -1 if unknown */
-} SQLValueFunction;
-
/*
* XmlExpr - various SQL/XML functions requiring special grammar productions
*
diff --git a/src/include/utils/date.h b/src/include/utils/date.h
index 0bbe889128..fad4878722 100644
--- a/src/include/utils/date.h
+++ b/src/include/utils/date.h
@@ -96,7 +96,6 @@ TimeTzADTPGetDatum(const TimeTzADT *X)
/* date.c */
-extern int32 anytime_typmod_check(bool istz, int32 typmod);
extern double date2timestamp_no_overflow(DateADT dateVal);
extern Timestamp date2timestamp_opt_overflow(DateADT dateVal, int *overflow);
extern TimestampTz date2timestamptz_opt_overflow(DateADT dateVal, int *overflow);
@@ -104,9 +103,6 @@ extern int32 date_cmp_timestamp_internal(DateADT dateVal, Timestamp dt2);
extern int32 date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2);
extern void EncodeSpecialDate(DateADT dt, char *str);
-extern DateADT GetSQLCurrentDate(void);
-extern TimeTzADT *GetSQLCurrentTime(int32 typmod);
-extern TimeADT GetSQLLocalTime(int32 typmod);
extern int time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec);
extern int timetz2tm(TimeTzADT *time, struct pg_tm *tm, fsec_t *fsec, int *tzp);
extern int tm2time(struct pg_tm *tm, fsec_t fsec, TimeADT *result);
diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h
index 76b7b4a3ca..7fd0b58825 100644
--- a/src/include/utils/timestamp.h
+++ b/src/include/utils/timestamp.h
@@ -93,11 +93,7 @@ extern PGDLLIMPORT TimestampTz PgReloadTime;
/* Internal routines (not fmgr-callable) */
-extern int32 anytimestamp_typmod_check(bool istz, int32 typmod);
-
extern TimestampTz GetCurrentTimestamp(void);
-extern TimestampTz GetSQLCurrentTimestamp(int32 typmod);
-extern Timestamp GetSQLLocalTimestamp(int32 typmod);
extern void TimestampDifference(TimestampTz start_time, TimestampTz stop_time,
long *secs, int *microsecs);
extern long TimestampDifferenceMilliseconds(TimestampTz start_time,
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 30a048f6b0..4c3b4c3f8e 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,32 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+-- Functions with SQL-mandated special syntax and some defaults.
+CREATE OR REPLACE FUNCTION
+ "current_time"(int4 DEFAULT NULL)
+RETURNS timetz
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'current_time';
+CREATE OR REPLACE FUNCTION
+ "current_timestamp"(int4 DEFAULT NULL)
+RETURNS timestamptz
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'current_timestamp';
+CREATE OR REPLACE FUNCTION
+ "localtime"(int4 DEFAULT NULL)
+RETURNS time
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'sql_localtime';
+CREATE OR REPLACE FUNCTION
+ "localtimestamp"(int4 DEFAULT NULL)
+RETURNS timestamp
+LANGUAGE internal
+STABLE PARALLEL SAFE
+AS 'sql_localtimestamp';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 0ecb2f8610..81429b9f05 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -2210,17 +2210,6 @@ ExecInitExprRec(Expr *node, ExprState *state,
break;
}
- case T_SQLValueFunction:
- {
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- scratch.opcode = EEOP_SQLVALUEFUNCTION;
- scratch.d.sqlvaluefunction.svf = svf;
-
- ExprEvalPushStep(state, &scratch);
- break;
- }
-
case T_XmlExpr:
{
XmlExpr *xexpr = (XmlExpr *) node;
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6ebf5c287e..1dab2787b7 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -452,7 +452,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
&&CASE_EEOP_DISTINCT,
&&CASE_EEOP_NOT_DISTINCT,
&&CASE_EEOP_NULLIF,
- &&CASE_EEOP_SQLVALUEFUNCTION,
&&CASE_EEOP_CURRENTOFEXPR,
&&CASE_EEOP_NEXTVALUEEXPR,
&&CASE_EEOP_ARRAYEXPR,
@@ -1301,17 +1300,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
EEO_NEXT();
}
- EEO_CASE(EEOP_SQLVALUEFUNCTION)
- {
- /*
- * Doesn't seem worthwhile to have an inline implementation
- * efficiency-wise.
- */
- ExecEvalSQLValueFunction(state, op);
-
- EEO_NEXT();
- }
-
EEO_CASE(EEOP_CURRENTOFEXPR)
{
/* error invocation uses space, and shouldn't ever occur */
@@ -2489,40 +2477,6 @@ ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
errmsg("no value found for parameter %d", paramId)));
}
-/*
- * Evaluate a SQLValueFunction expression.
- */
-void
-ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
-{
- SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
-
- *op->resnull = false;
-
- switch (svf->op)
- {
- case SVFOP_CURRENT_DATE:
- *op->resvalue = DateADTGetDatum(GetSQLCurrentDate());
- break;
- case SVFOP_CURRENT_TIME:
- case SVFOP_CURRENT_TIME_N:
- *op->resvalue = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod));
- break;
- case SVFOP_CURRENT_TIMESTAMP:
- case SVFOP_CURRENT_TIMESTAMP_N:
- *op->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod));
- break;
- case SVFOP_LOCALTIME:
- case SVFOP_LOCALTIME_N:
- *op->resvalue = TimeADTGetDatum(GetSQLLocalTime(svf->typmod));
- break;
- case SVFOP_LOCALTIMESTAMP:
- case SVFOP_LOCALTIMESTAMP_N:
- *op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
- break;
- }
-}
-
/*
* Raise error if a CURRENT OF expression is evaluated.
*
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index 95d0807bdd..f114337f8e 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -1549,12 +1549,6 @@ llvm_compile_expr(ExprState *state)
break;
}
- case EEOP_SQLVALUEFUNCTION:
- build_EvalXFunc(b, mod, "ExecEvalSQLValueFunction",
- v_state, op);
- LLVMBuildBr(b, opblocks[opno + 1]);
- break;
-
case EEOP_CURRENTOFEXPR:
build_EvalXFunc(b, mod, "ExecEvalCurrentOfExpr",
v_state, op);
diff --git a/src/backend/jit/llvm/llvmjit_types.c b/src/backend/jit/llvm/llvmjit_types.c
index 90ac6b83b5..5b416c5642 100644
--- a/src/backend/jit/llvm/llvmjit_types.c
+++ b/src/backend/jit/llvm/llvmjit_types.c
@@ -126,7 +126,6 @@ void *referenced_functions[] =
ExecEvalRow,
ExecEvalRowNotNull,
ExecEvalRowNull,
- ExecEvalSQLValueFunction,
ExecEvalScalarArrayOp,
ExecEvalHashedScalarArrayOp,
ExecEvalSubPlan,
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 2585a3175c..af8620ceb7 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -210,9 +210,6 @@ exprType(const Node *expr)
case T_MinMaxExpr:
type = ((const MinMaxExpr *) expr)->minmaxtype;
break;
- case T_SQLValueFunction:
- type = ((const SQLValueFunction *) expr)->type;
- break;
case T_XmlExpr:
if (((const XmlExpr *) expr)->op == IS_DOCUMENT)
type = BOOLOID;
@@ -474,8 +471,6 @@ exprTypmod(const Node *expr)
return typmod;
}
break;
- case T_SQLValueFunction:
- return ((const SQLValueFunction *) expr)->typmod;
case T_CoerceToDomain:
return ((const CoerceToDomain *) expr)->resulttypmod;
case T_CoerceToDomainValue:
@@ -916,10 +911,6 @@ exprCollation(const Node *expr)
case T_MinMaxExpr:
coll = ((const MinMaxExpr *) expr)->minmaxcollid;
break;
- case T_SQLValueFunction:
- /* Returns a non-collatable type */
- coll = InvalidOid;
- break;
case T_XmlExpr:
/*
@@ -1140,9 +1131,6 @@ exprSetCollation(Node *expr, Oid collation)
case T_MinMaxExpr:
((MinMaxExpr *) expr)->minmaxcollid = collation;
break;
- case T_SQLValueFunction:
- Assert(collation == InvalidOid);
- break;
case T_XmlExpr:
Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ?
(collation == DEFAULT_COLLATION_OID) :
@@ -1426,10 +1414,6 @@ exprLocation(const Node *expr)
/* GREATEST/LEAST keyword should always be the first thing */
loc = ((const MinMaxExpr *) expr)->location;
break;
- case T_SQLValueFunction:
- /* function keyword should always be the first thing */
- loc = ((const SQLValueFunction *) expr)->location;
- break;
case T_XmlExpr:
{
const XmlExpr *xexpr = (const XmlExpr *) expr;
@@ -1717,10 +1701,10 @@ set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
* for themselves, in case additional checks should be made, or because they
* have special rules about which parts of the tree need to be visited.
*
- * Note: we ignore MinMaxExpr, SQLValueFunction, XmlExpr, CoerceToDomain,
- * and NextValueExpr nodes, because they do not contain SQL function OIDs.
- * However, they can invoke SQL-visible functions, so callers should take
- * thought about how to treat them.
+ * Note: we ignore MinMaxExpr, XmlExpr, CoerceToDomain, and NextValueExpr
+ * nodes, because they do not contain SQL function OIDs. However, they can
+ * invoke SQL-visible functions, so callers should take thought about how
+ * to treat them.
*/
bool
check_functions_in_node(Node *node, check_function_callback checker,
@@ -1936,7 +1920,6 @@ expression_tree_walker_impl(Node *node,
case T_Const:
case T_Param:
case T_CaseTestExpr:
- case T_SQLValueFunction:
case T_CoerceToDomainValue:
case T_SetToDefault:
case T_CurrentOfExpr:
@@ -2673,7 +2656,6 @@ expression_tree_mutator_impl(Node *node,
break;
case T_Param:
case T_CaseTestExpr:
- case T_SQLValueFunction:
case T_CoerceToDomainValue:
case T_SetToDefault:
case T_CurrentOfExpr:
@@ -3587,7 +3569,6 @@ raw_expression_tree_walker_impl(Node *node,
{
case T_SetToDefault:
case T_CurrentOfExpr:
- case T_SQLValueFunction:
case T_Integer:
case T_Float:
case T_Boolean:
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 4c6b1d1f55..897309d7ec 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -4603,7 +4603,6 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
}
}
else if (IsA(node, MinMaxExpr) ||
- IsA(node, SQLValueFunction) ||
IsA(node, XmlExpr) ||
IsA(node, CoerceToDomain) ||
IsA(node, NextValueExpr))
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 33790a4f46..c61d9c68a0 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -383,12 +383,6 @@ contain_mutable_functions_walker(Node *node, void *context)
context))
return true;
- if (IsA(node, SQLValueFunction))
- {
- /* all variants of SQLValueFunction are stable */
- return true;
- }
-
if (IsA(node, NextValueExpr))
{
/* NextValueExpr is volatile */
@@ -537,8 +531,8 @@ contain_volatile_functions_walker(Node *node, void *context)
/*
* See notes in contain_mutable_functions_walker about why we treat
- * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
- * SQLValueFunction is stable. Hence, none of them are of interest here.
+ * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable. Hence, none
+ * of them are of interest here.
*/
/* Recurse to check arguments */
@@ -583,10 +577,9 @@ contain_volatile_functions_not_nextval_walker(Node *node, void *context)
/*
* See notes in contain_mutable_functions_walker about why we treat
- * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
- * SQLValueFunction is stable. Hence, none of them are of interest here.
- * Also, since we're intentionally ignoring nextval(), presumably we
- * should ignore NextValueExpr.
+ * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable. Hence, none
+ * of them are of interest here. Also, since we're intentionally
+ * ignoring nextval(), presumably we should ignore NextValueExpr.
*/
/* Recurse to check arguments */
@@ -732,8 +725,8 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
* (Note: in principle that's wrong because a domain constraint could
* contain a parallel-unsafe function; but useful constraints probably
* never would have such, and assuming they do would cripple use of
- * parallel query in the presence of domain types.) SQLValueFunction
- * should be safe in all cases. NextValueExpr is parallel-unsafe.
+ * parallel query in the presence of domain types.) NextValueExpr is
+ * parallel-unsafe.
*/
if (IsA(node, CoerceToDomain))
{
@@ -1180,7 +1173,6 @@ contain_leaked_vars_walker(Node *node, void *context)
case T_CaseExpr:
case T_CaseTestExpr:
case T_RowExpr:
- case T_SQLValueFunction:
case T_NullTest:
case T_BooleanTest:
case T_NextValueExpr:
@@ -3194,23 +3186,6 @@ eval_const_expressions_mutator(Node *node,
newcoalesce->location = coalesceexpr->location;
return (Node *) newcoalesce;
}
- case T_SQLValueFunction:
- {
- /*
- * All variants of SQLValueFunction are stable, so if we are
- * estimating the expression's value, we should evaluate the
- * current function value. Otherwise just copy.
- */
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- if (context->estimate)
- return (Node *) evaluate_expr((Expr *) svf,
- svf->type,
- svf->typmod,
- InvalidOid);
- else
- return copyObject((Node *) svf);
- }
case T_FieldSelect:
{
/*
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 9054742427..9384214942 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -198,8 +198,6 @@ static Node *makeAndExpr(Node *lexpr, Node *rexpr, int location);
static Node *makeOrExpr(Node *lexpr, Node *rexpr, int location);
static Node *makeNotExpr(Node *expr, int location);
static Node *makeAArrayExpr(List *elements, int location);
-static Node *makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod,
- int location);
static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
List *args, int location);
static List *mergeTableFuncParameters(List *func_args, List *columns);
@@ -15195,39 +15193,66 @@ func_expr_common_subexpr:
}
| CURRENT_DATE
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_DATE, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_date"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIME
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_time"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIME '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_time"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIMESTAMP
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_timestamp"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_TIMESTAMP '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_timestamp"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIME
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIME, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtime"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIME '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIME_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtime"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIMESTAMP
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP, -1, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtimestamp"),
+ NIL,
+ COERCE_SQL_SYNTAX,
+ @1);
}
| LOCALTIMESTAMP '(' Iconst ')'
{
- $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP_N, $3, @1);
+ $$ = (Node *) makeFuncCall(SystemFuncName("localtimestamp"),
+ list_make1(makeIntConst($3, @3)),
+ COERCE_SQL_SYNTAX,
+ @1);
}
| CURRENT_ROLE
{
@@ -18166,18 +18191,6 @@ makeAArrayExpr(List *elements, int location)
return (Node *) n;
}
-static Node *
-makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, int location)
-{
- SQLValueFunction *svf = makeNode(SQLValueFunction);
-
- svf->op = op;
- /* svf->type will be filled during parse analysis */
- svf->typmod = typmod;
- svf->location = location;
- return (Node *) svf;
-}
-
static Node *
makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
int location)
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 0fdbf82f3a..150a8099c2 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -61,8 +61,6 @@ static Node *transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
static Node *transformRowExpr(ParseState *pstate, RowExpr *r, bool allowDefault);
static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c);
static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m);
-static Node *transformSQLValueFunction(ParseState *pstate,
- SQLValueFunction *svf);
static Node *transformXmlExpr(ParseState *pstate, XmlExpr *x);
static Node *transformXmlSerialize(ParseState *pstate, XmlSerialize *xs);
static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
@@ -240,11 +238,6 @@ transformExprRecurse(ParseState *pstate, Node *expr)
result = transformMinMaxExpr(pstate, (MinMaxExpr *) expr);
break;
- case T_SQLValueFunction:
- result = transformSQLValueFunction(pstate,
- (SQLValueFunction *) expr);
- break;
-
case T_XmlExpr:
result = transformXmlExpr(pstate, (XmlExpr *) expr);
break;
@@ -2191,51 +2184,6 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m)
return (Node *) newm;
}
-static Node *
-transformSQLValueFunction(ParseState *pstate, SQLValueFunction *svf)
-{
- /*
- * All we need to do is insert the correct result type and (where needed)
- * validate the typmod, so we just modify the node in-place.
- */
- switch (svf->op)
- {
- case SVFOP_CURRENT_DATE:
- svf->type = DATEOID;
- break;
- case SVFOP_CURRENT_TIME:
- svf->type = TIMETZOID;
- break;
- case SVFOP_CURRENT_TIME_N:
- svf->type = TIMETZOID;
- svf->typmod = anytime_typmod_check(true, svf->typmod);
- break;
- case SVFOP_CURRENT_TIMESTAMP:
- svf->type = TIMESTAMPTZOID;
- break;
- case SVFOP_CURRENT_TIMESTAMP_N:
- svf->type = TIMESTAMPTZOID;
- svf->typmod = anytimestamp_typmod_check(true, svf->typmod);
- break;
- case SVFOP_LOCALTIME:
- svf->type = TIMEOID;
- break;
- case SVFOP_LOCALTIME_N:
- svf->type = TIMEOID;
- svf->typmod = anytime_typmod_check(false, svf->typmod);
- break;
- case SVFOP_LOCALTIMESTAMP:
- svf->type = TIMESTAMPOID;
- break;
- case SVFOP_LOCALTIMESTAMP_N:
- svf->type = TIMESTAMPOID;
- svf->typmod = anytimestamp_typmod_check(false, svf->typmod);
- break;
- }
-
- return (Node *) svf;
-}
-
static Node *
transformXmlExpr(ParseState *pstate, XmlExpr *x)
{
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index f54591a987..8e0d6fd01f 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1872,31 +1872,6 @@ FigureColnameInternal(Node *node, char **name)
return 2;
}
break;
- case T_SQLValueFunction:
- /* make these act like a function or variable */
- switch (((SQLValueFunction *) node)->op)
- {
- case SVFOP_CURRENT_DATE:
- *name = "current_date";
- return 2;
- case SVFOP_CURRENT_TIME:
- case SVFOP_CURRENT_TIME_N:
- *name = "current_time";
- return 2;
- case SVFOP_CURRENT_TIMESTAMP:
- case SVFOP_CURRENT_TIMESTAMP_N:
- *name = "current_timestamp";
- return 2;
- case SVFOP_LOCALTIME:
- case SVFOP_LOCALTIME_N:
- *name = "localtime";
- return 2;
- case SVFOP_LOCALTIMESTAMP:
- case SVFOP_LOCALTIMESTAMP_N:
- *name = "localtimestamp";
- return 2;
- }
- break;
case T_XmlExpr:
/* make SQL/XML functions act like a regular function */
switch (((XmlExpr *) node)->op)
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index a2bdde0459..10c11e00db 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -46,27 +46,6 @@
/* common code for timetypmodin and timetztypmodin */
static int32
-anytime_typmodin(bool istz, ArrayType *ta)
-{
- int32 *tl;
- int n;
-
- tl = ArrayGetIntegerTypmods(ta, &n);
-
- /*
- * we're not too tense about good error message here because grammar
- * shouldn't allow wrong number of modifiers for TIME
- */
- if (n != 1)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("invalid type modifier")));
-
- return anytime_typmod_check(istz, tl[0]);
-}
-
-/* exported so parse_expr.c can use it */
-int32
anytime_typmod_check(bool istz, int32 typmod)
{
if (typmod < 0)
@@ -87,6 +66,26 @@ anytime_typmod_check(bool istz, int32 typmod)
return typmod;
}
+static int32
+anytime_typmodin(bool istz, ArrayType *ta)
+{
+ int32 *tl;
+ int n;
+
+ tl = ArrayGetIntegerTypmods(ta, &n);
+
+ /*
+ * we're not too tense about good error message here because grammar
+ * shouldn't allow wrong number of modifiers for TIME
+ */
+ if (n != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid type modifier")));
+
+ return anytime_typmod_check(istz, tl[0]);
+}
+
/* common code for timetypmodout and timetztypmodout */
static char *
anytime_typmodout(bool istz, int32 typmod)
@@ -296,10 +295,10 @@ EncodeSpecialDate(DateADT dt, char *str)
/*
- * GetSQLCurrentDate -- implements CURRENT_DATE
+ * current_date -- implements CURRENT_DATE
*/
-DateADT
-GetSQLCurrentDate(void)
+Datum
+current_date(PG_FUNCTION_ARGS)
{
struct pg_tm tm;
@@ -325,46 +324,62 @@ GetSQLCurrentDate(void)
cache_mday = tm.tm_mday;
}
- return cache_date;
+ return DateADTGetDatum(cache_date);
}
/*
- * GetSQLCurrentTime -- implements CURRENT_TIME, CURRENT_TIME(n)
+ * current_time -- implements CURRENT_TIME, CURRENT_TIME(n)
*/
-TimeTzADT *
-GetSQLCurrentTime(int32 typmod)
+Datum
+current_time(PG_FUNCTION_ARGS)
{
TimeTzADT *result;
struct pg_tm tt,
*tm = &tt;
fsec_t fsec;
int tz;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytime_typmod_check(true, typmod);
+ }
GetCurrentTimeUsec(tm, &fsec, &tz);
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
tm2timetz(tm, fsec, tz, result);
AdjustTimeForTypmod(&(result->time), typmod);
- return result;
+
+ return TimeTzADTPGetDatum(result);
}
/*
- * GetSQLLocalTime -- implements LOCALTIME, LOCALTIME(n)
+ * sql_localtime -- implements LOCALTIME, LOCALTIME(n)
*/
-TimeADT
-GetSQLLocalTime(int32 typmod)
+Datum
+sql_localtime(PG_FUNCTION_ARGS)
{
TimeADT result;
struct pg_tm tt,
*tm = &tt;
fsec_t fsec;
int tz;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytime_typmod_check(false, typmod);
+ }
GetCurrentTimeUsec(tm, &fsec, &tz);
tm2time(tm, fsec, &result);
AdjustTimeForTypmod(&result, typmod);
- return result;
+
+ return TimeADTGetDatum(result);
}
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 129f3333fb..c00dc5e32e 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -8150,7 +8150,6 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_RowExpr:
case T_CoalesceExpr:
case T_MinMaxExpr:
- case T_SQLValueFunction:
case T_XmlExpr:
case T_NextValueExpr:
case T_NullIfExpr:
@@ -9130,49 +9129,6 @@ get_rule_expr(Node *node, deparse_context *context,
}
break;
- case T_SQLValueFunction:
- {
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- /*
- * Note: this code knows that typmod for time, timestamp, and
- * timestamptz just prints as integer.
- */
- switch (svf->op)
- {
- case SVFOP_CURRENT_DATE:
- appendStringInfoString(buf, "CURRENT_DATE");
- break;
- case SVFOP_CURRENT_TIME:
- appendStringInfoString(buf, "CURRENT_TIME");
- break;
- case SVFOP_CURRENT_TIME_N:
- appendStringInfo(buf, "CURRENT_TIME(%d)", svf->typmod);
- break;
- case SVFOP_CURRENT_TIMESTAMP:
- appendStringInfoString(buf, "CURRENT_TIMESTAMP");
- break;
- case SVFOP_CURRENT_TIMESTAMP_N:
- appendStringInfo(buf, "CURRENT_TIMESTAMP(%d)",
- svf->typmod);
- break;
- case SVFOP_LOCALTIME:
- appendStringInfoString(buf, "LOCALTIME");
- break;
- case SVFOP_LOCALTIME_N:
- appendStringInfo(buf, "LOCALTIME(%d)", svf->typmod);
- break;
- case SVFOP_LOCALTIMESTAMP:
- appendStringInfoString(buf, "LOCALTIMESTAMP");
- break;
- case SVFOP_LOCALTIMESTAMP_N:
- appendStringInfo(buf, "LOCALTIMESTAMP(%d)",
- svf->typmod);
- break;
- }
- }
- break;
-
case T_XmlExpr:
{
XmlExpr *xexpr = (XmlExpr *) node;
@@ -9698,7 +9654,6 @@ looks_like_function(Node *node)
case T_NullIfExpr:
case T_CoalesceExpr:
case T_MinMaxExpr:
- case T_SQLValueFunction:
case T_XmlExpr:
/* these are all accepted by func_expr_common_subexpr */
return true;
@@ -10292,6 +10247,70 @@ get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
appendStringInfoString(buf, "SYSTEM_USER");
return true;
+ case F_CURRENT_DATE:
+ appendStringInfoString(buf, "CURRENT_DATE");
+ return true;
+ case F_CURRENT_TIME:
+ appendStringInfoString(buf, "CURRENT_TIME");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+ case F_CURRENT_TIMESTAMP:
+ appendStringInfoString(buf, "CURRENT_TIMESTAMP");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+ case F_LOCALTIME:
+ appendStringInfoString(buf, "LOCALTIME");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+ case F_LOCALTIMESTAMP:
+ appendStringInfoString(buf, "LOCALTIMESTAMP");
+ if (list_length(expr->args) == 1)
+ {
+ Const *cons = (Const *) linitial(expr->args);
+
+ Assert(IsA(cons, Const));
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+ }
+ return true;
+
case F_XMLEXISTS:
/* XMLEXISTS ... extra parens because args are c_expr */
appendStringInfoString(buf, "XMLEXISTS((");
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index d8552a1f18..ef92323fd0 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -81,27 +81,6 @@ static Timestamp timestamptz2timestamp(TimestampTz timestamp);
/* common code for timestamptypmodin and timestamptztypmodin */
static int32
-anytimestamp_typmodin(bool istz, ArrayType *ta)
-{
- int32 *tl;
- int n;
-
- tl = ArrayGetIntegerTypmods(ta, &n);
-
- /*
- * we're not too tense about good error message here because grammar
- * shouldn't allow wrong number of modifiers for TIMESTAMP
- */
- if (n != 1)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("invalid type modifier")));
-
- return anytimestamp_typmod_check(istz, tl[0]);
-}
-
-/* exported so parse_expr.c can use it */
-int32
anytimestamp_typmod_check(bool istz, int32 typmod)
{
if (typmod < 0)
@@ -122,6 +101,26 @@ anytimestamp_typmod_check(bool istz, int32 typmod)
return typmod;
}
+static int32
+anytimestamp_typmodin(bool istz, ArrayType *ta)
+{
+ int32 *tl;
+ int n;
+
+ tl = ArrayGetIntegerTypmods(ta, &n);
+
+ /*
+ * we're not too tense about good error message here because grammar
+ * shouldn't allow wrong number of modifiers for TIMESTAMP
+ */
+ if (n != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid type modifier")));
+
+ return anytimestamp_typmod_check(istz, tl[0]);
+}
+
/* common code for timestamptypmodout and timestamptztypmodout */
static char *
anytimestamp_typmodout(bool istz, int32 typmod)
@@ -1586,33 +1585,48 @@ GetCurrentTimestamp(void)
}
/*
- * GetSQLCurrentTimestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
+ * current_timestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
*/
-TimestampTz
-GetSQLCurrentTimestamp(int32 typmod)
+Datum
+current_timestamp(PG_FUNCTION_ARGS)
{
TimestampTz ts;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytimestamp_typmod_check(true, typmod);
+ }
ts = GetCurrentTransactionStartTimestamp();
if (typmod >= 0)
AdjustTimestampForTypmod(&ts, typmod);
- return ts;
+ return TimestampTzGetDatum(ts);
}
/*
- * GetSQLLocalTimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
+ * sql_localtimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
*/
-Timestamp
-GetSQLLocalTimestamp(int32 typmod)
+Datum
+sql_localtimestamp(PG_FUNCTION_ARGS)
{
Timestamp ts;
+ int32 typmod = -1;
+
+ if (!PG_ARGISNULL(0))
+ {
+ typmod = PG_GETARG_INT32(0);
+ anytimestamp_typmod_check(false, typmod);
+ }
ts = timestamptz2timestamp(GetCurrentTransactionStartTimestamp());
if (typmod >= 0)
AdjustTimestampForTypmod(&ts, typmod);
- return ts;
+ return TimestampGetDatum(ts);
}
+
/*
* timeofday(*) -- returns the current time as a text.
*/
diff --git a/src/backend/utils/misc/queryjumble.c b/src/backend/utils/misc/queryjumble.c
index a8508463e7..0ace74de78 100644
--- a/src/backend/utils/misc/queryjumble.c
+++ b/src/backend/utils/misc/queryjumble.c
@@ -606,15 +606,6 @@ JumbleExpr(JumbleState *jstate, Node *node)
JumbleExpr(jstate, (Node *) mmexpr->args);
}
break;
- case T_SQLValueFunction:
- {
- SQLValueFunction *svf = (SQLValueFunction *) node;
-
- APP_JUMB(svf->op);
- /* type is fully determined by op */
- APP_JUMB(svf->typmod);
- }
- break;
case T_XmlExpr:
{
XmlExpr *xexpr = (XmlExpr *) node;
diff --git a/src/test/regress/expected/expressions.out b/src/test/regress/expected/expressions.out
index 5bf39fd9aa..28a20900f1 100644
--- a/src/test/regress/expected/expressions.out
+++ b/src/test/regress/expected/expressions.out
@@ -2,7 +2,7 @@
-- expression evaluation tests that don't fit into a more specific file
--
--
--- Tests for SQLValueFunction
+-- Tests for various FuncCalls with COERCE_SQL_SYNTAX.
--
-- current_date (always matches because of transactional behaviour)
SELECT date(now())::text = current_date::text;
diff --git a/src/test/regress/sql/expressions.sql b/src/test/regress/sql/expressions.sql
index 0e163cc0d7..f9a0299d17 100644
--- a/src/test/regress/sql/expressions.sql
+++ b/src/test/regress/sql/expressions.sql
@@ -3,7 +3,7 @@
--
--
--- Tests for SQLValueFunction
+-- Tests for various FuncCalls with COERCE_SQL_SYNTAX.
--
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index f8302f1ed1..2f5802195d 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2397,8 +2397,6 @@ SQLFunctionCache
SQLFunctionCachePtr
SQLFunctionParseInfo
SQLFunctionParseInfoPtr
-SQLValueFunction
-SQLValueFunctionOp
SSL
SSLExtensionInfoContext
SSL_CTX
--
2.38.1
v5-0002-Simplify-back-parsing-of-SQL-callable-timestamp-f.patchtext/x-diff; charset=us-asciiDownload
From 5ec10492cda8930c014f8db315650cffa7ea57e1 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Mon, 21 Nov 2022 08:08:44 +0900
Subject: [PATCH v5 2/2] Simplify back-parsing of SQL-callable timestamp
functions
Per suggestion from Ted Yu.
---
src/backend/utils/adt/ruleutils.c | 79 ++++++++++++-------------------
1 file changed, 31 insertions(+), 48 deletions(-)
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index c00dc5e32e..ab926bedd4 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -9997,6 +9997,33 @@ get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
}
}
+/*
+ * get_func_sql_syntax_time
+ *
+ * Parse back argument of SQL-syntax function call related to a time or a
+ * timestamp. These require a specific handling with their typmod is given
+ * by the function caller through their SQL keyword.
+ */
+static void
+get_func_sql_syntax_time(List *args, deparse_context *context)
+{
+ StringInfo buf = context->buf;
+ Const *cons;
+
+ if (list_length(args) != 1)
+ return;
+
+ cons = (Const *) linitial(args);
+ Assert(IsA(cons, Const));
+
+ if (!cons->constisnull)
+ {
+ appendStringInfoString(buf, "(");
+ get_rule_expr((Node *) cons, context, false);
+ appendStringInfoString(buf, ")");
+ }
+}
+
/*
* get_func_sql_syntax - Parse back a SQL-syntax function call
*
@@ -10252,63 +10279,19 @@ get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
return true;
case F_CURRENT_TIME:
appendStringInfoString(buf, "CURRENT_TIME");
- if (list_length(expr->args) == 1)
- {
- Const *cons = (Const *) linitial(expr->args);
-
- Assert(IsA(cons, Const));
- if (!cons->constisnull)
- {
- appendStringInfoString(buf, "(");
- get_rule_expr((Node *) cons, context, false);
- appendStringInfoString(buf, ")");
- }
- }
+ get_func_sql_syntax_time(expr->args, context);
return true;
case F_CURRENT_TIMESTAMP:
appendStringInfoString(buf, "CURRENT_TIMESTAMP");
- if (list_length(expr->args) == 1)
- {
- Const *cons = (Const *) linitial(expr->args);
-
- Assert(IsA(cons, Const));
- if (!cons->constisnull)
- {
- appendStringInfoString(buf, "(");
- get_rule_expr((Node *) cons, context, false);
- appendStringInfoString(buf, ")");
- }
- }
+ get_func_sql_syntax_time(expr->args, context);
return true;
case F_LOCALTIME:
appendStringInfoString(buf, "LOCALTIME");
- if (list_length(expr->args) == 1)
- {
- Const *cons = (Const *) linitial(expr->args);
-
- Assert(IsA(cons, Const));
- if (!cons->constisnull)
- {
- appendStringInfoString(buf, "(");
- get_rule_expr((Node *) cons, context, false);
- appendStringInfoString(buf, ")");
- }
- }
+ get_func_sql_syntax_time(expr->args, context);
return true;
case F_LOCALTIMESTAMP:
appendStringInfoString(buf, "LOCALTIMESTAMP");
- if (list_length(expr->args) == 1)
- {
- Const *cons = (Const *) linitial(expr->args);
-
- Assert(IsA(cons, Const));
- if (!cons->constisnull)
- {
- appendStringInfoString(buf, "(");
- get_rule_expr((Node *) cons, context, false);
- appendStringInfoString(buf, ")");
- }
- }
+ get_func_sql_syntax_time(expr->args, context);
return true;
case F_XMLEXISTS:
--
2.38.1
On Sun, Nov 20, 2022 at 3:12 PM Michael Paquier <michael@paquier.xyz> wrote:
On Sun, Nov 20, 2022 at 08:21:10AM -0800, Ted Yu wrote:
For get_func_sql_syntax(), the code for cases
of F_CURRENT_TIME, F_CURRENT_TIMESTAMP, F_LOCALTIME and F_LOCALTIMESTAMPis
mostly the same.
Maybe we can introduce a helper so that code duplication is reduced.It would. Thanks for the suggestion.
Do you like something like the patch 0002 attached? This reduces a
bit the overall size of the patch. Both ought to be merged in the
same commit, still it is easier to see the simplification created.
--
Michael
Hi,
Thanks for the quick response.
+ * timestamp. These require a specific handling with their typmod is given
+ * by the function caller through their SQL keyword.
typo: typmod is given -> typmod given
Other than the above, code looks good to me.
Cheers
On Sun, Nov 20, 2022 at 03:15:34PM -0800, Ted Yu wrote:
+ * timestamp. These require a specific handling with their typmod is given + * by the function caller through their SQL keyword.typo: typmod is given -> typmod given
Other than the above, code looks good to me.
Thanks for double-checking. I intended a different wording, actually,
so fixed this one. And applied after an extra round of reviews.
--
Michael
Hi
2022年11月21日(月) 18:39 Michael Paquier <michael@paquier.xyz>:
On Sun, Nov 20, 2022 at 03:15:34PM -0800, Ted Yu wrote:
+ * timestamp. These require a specific handling with their typmod is given + * by the function caller through their SQL keyword.typo: typmod is given -> typmod given
Other than the above, code looks good to me.
Thanks for double-checking. I intended a different wording, actually,
so fixed this one. And applied after an extra round of reviews.
I noticed this commit (f193883f) introduces following regressions:
postgres=# SELECT current_timestamp(7);
WARNING: TIMESTAMP(7) WITH TIME ZONE precision reduced to maximum
allowed, 6
ERROR: timestamp(7) precision must be between 0 and 6
postgres=# SELECT localtimestamp(7);
WARNING: TIMESTAMP(7) precision reduced to maximum allowed, 6
ERROR: timestamp(7) precision must be between 0 and 6
Suggested fix attached.
Regards
Ian Barwick
Attachments:
v1-0001-Fix-current-local-timestamp-precision-reduction.patchtext/x-patch; charset=US-ASCII; name=v1-0001-Fix-current-local-timestamp-precision-reduction.patchDownload
From b599765b222aacbc860ba43c42ec658ed1a8b989 Mon Sep 17 00:00:00 2001
From: Ian Barwick <barwick@gmail.com>
Date: Fri, 30 Dec 2022 10:48:31 +0900
Subject: [PATCH v1] Fix [current_|local]timestamp precision reduction
Fixes regression introduced in f193883f.
---
src/backend/utils/adt/timestamp.c | 10 ++--------
src/test/regress/expected/expressions.out | 15 +++++++++++++++
src/test/regress/sql/expressions.sql | 3 +++
3 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 3f2508c0c4..b23cce1136 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -1606,10 +1606,7 @@ current_timestamp(PG_FUNCTION_ARGS)
int32 typmod = -1;
if (!PG_ARGISNULL(0))
- {
- typmod = PG_GETARG_INT32(0);
- anytimestamp_typmod_check(true, typmod);
- }
+ typmod = anytimestamp_typmod_check(true, PG_GETARG_INT32(0));
ts = GetCurrentTransactionStartTimestamp();
if (typmod >= 0)
@@ -1627,10 +1624,7 @@ sql_localtimestamp(PG_FUNCTION_ARGS)
int32 typmod = -1;
if (!PG_ARGISNULL(0))
- {
- typmod = PG_GETARG_INT32(0);
- anytimestamp_typmod_check(false, typmod);
- }
+ typmod = anytimestamp_typmod_check(false, PG_GETARG_INT32(0));
ts = timestamptz2timestamp(GetCurrentTransactionStartTimestamp());
if (typmod >= 0)
diff --git a/src/test/regress/expected/expressions.out b/src/test/regress/expected/expressions.out
index 28a20900f1..fd38830a77 100644
--- a/src/test/regress/expected/expressions.out
+++ b/src/test/regress/expected/expressions.out
@@ -50,6 +50,14 @@ SELECT length(current_timestamp::text) >= length(current_timestamp(0)::text);
t
(1 row)
+-- precision overflow
+SELECT current_timestamp = current_timestamp(7);
+WARNING: TIMESTAMP(7) WITH TIME ZONE precision reduced to maximum allowed, 6
+ ?column?
+----------
+ t
+(1 row)
+
-- localtimestamp
SELECT now()::timestamp::text = localtimestamp::text;
?column?
@@ -57,6 +65,13 @@ SELECT now()::timestamp::text = localtimestamp::text;
t
(1 row)
+SELECT localtimestamp = localtimestamp(7);
+WARNING: TIMESTAMP(7) precision reduced to maximum allowed, 6
+ ?column?
+----------
+ t
+(1 row)
+
-- current_role/user/user is tested in rolnames.sql
-- current database / catalog
SELECT current_catalog = current_database();
diff --git a/src/test/regress/sql/expressions.sql b/src/test/regress/sql/expressions.sql
index f9a0299d17..57dfb37745 100644
--- a/src/test/regress/sql/expressions.sql
+++ b/src/test/regress/sql/expressions.sql
@@ -21,8 +21,11 @@ SELECT now()::time(3)::text = localtime(3)::text;
SELECT current_timestamp = NOW();
-- precision
SELECT length(current_timestamp::text) >= length(current_timestamp(0)::text);
+-- precision overflow
+SELECT current_timestamp = current_timestamp(7);
-- localtimestamp
SELECT now()::timestamp::text = localtimestamp::text;
+SELECT localtimestamp = localtimestamp(7);
-- current_role/user/user is tested in rolnames.sql
base-commit: 388e80132c007a7528abc987e347e41432dc1542
--
2.31.1
On Fri, Dec 30, 2022 at 10:57:52AM +0900, Ian Lawrence Barwick wrote:
I noticed this commit (f193883f) introduces following regressions:
postgres=# SELECT current_timestamp(7);
WARNING: TIMESTAMP(7) WITH TIME ZONE precision reduced to maximum
allowed, 6
ERROR: timestamp(7) precision must be between 0 and 6postgres=# SELECT localtimestamp(7);
WARNING: TIMESTAMP(7) precision reduced to maximum allowed, 6
ERROR: timestamp(7) precision must be between 0 and 6Suggested fix attached.
Thanks for the report, Ian. Will fix.
--
Michael
On Fri, Dec 30, 2022 at 10:57:52AM +0900, Ian Lawrence Barwick wrote:
I noticed this commit (f193883f) introduces following regressions:
postgres=# SELECT current_timestamp(7);
WARNING: TIMESTAMP(7) WITH TIME ZONE precision reduced to maximum
allowed, 6
ERROR: timestamp(7) precision must be between 0 and 6postgres=# SELECT localtimestamp(7);
WARNING: TIMESTAMP(7) precision reduced to maximum allowed, 6
ERROR: timestamp(7) precision must be between 0 and 6Suggested fix attached.
The two changes in timestamp.c are fine, Now I can see that the same
mistake was introduced in date.c. The WARNINGs were issued and the
compilation went through the same way as the default, but they passed
down an incorrect precision, so I have fixed all that. Coverage has
been added for all four, while the patch proposed covered only two.
--
Michael