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
From 8d1a424e44f46f3107a6f0f066da22c19e4e4f3b Mon Sep 17 00:00:00 2001 From: Michael Paquier <mich...@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/yzag3morycguu...@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
From 9f5bb5ba425f923ab9286b810594b2c312739ffa Mon Sep 17 00:00:00 2001 From: Michael Paquier <mich...@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/yzag3morycguu...@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
signature.asc
Description: PGP signature