Add back SQLValueFunction for SQL keywords
authorMichael Paquier <[email protected]>
Wed, 17 May 2023 01:19:17 +0000 (10:19 +0900)
committerMichael Paquier <[email protected]>
Wed, 17 May 2023 01:19:17 +0000 (10:19 +0900)
This is equivalent to a revert of f193883 and fb32748, with the addition
that the declaration of the SQLValueFunction node needs to gain a couple
of node_attr for query jumbling.  The performance impact of removing the
function call inlining is proving to be too huge for some workloads
where these are used.  A worst-case test case of involving only simple
SELECT queries with a SQL keyword is proving to lead to a reduction of
10% in TPS via pgbench and prepared queries on a high-end machine.

None of the tests I ran back for this set of changes saw such a huge
gap, but Alexander Lakhin and Andres Freund have found that this can be
noticeable.  Keeping the older performance would mean to do more
inlining in the executor when using COERCE_SQL_SYNTAX for a function
expression, similarly to what SQLValueFunction does.  This requires more
redesign work and there is little time until 16beta1 is released, so for
now reverting the change is the best way forward, bringing back the
previous performance.

Bump catalog version.

Reported-by: Alexander Lakhin
Discussion: https://postgr.es/m/b32bed1b-0746-9b20-1472-4bdc9ca66d52@gmail.com

23 files changed:
src/backend/catalog/system_functions.sql
src/backend/executor/execExpr.c
src/backend/executor/execExprInterp.c
src/backend/jit/llvm/llvmjit_expr.c
src/backend/jit/llvm/llvmjit_types.c
src/backend/nodes/nodeFuncs.c
src/backend/optimizer/path/costsize.c
src/backend/optimizer/util/clauses.c
src/backend/parser/gram.y
src/backend/parser/parse_expr.c
src/backend/parser/parse_target.c
src/backend/utils/adt/date.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/adt/timestamp.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.dat
src/include/executor/execExpr.h
src/include/nodes/primnodes.h
src/include/utils/date.h
src/include/utils/timestamp.h
src/test/regress/expected/expressions.out
src/test/regress/sql/expressions.sql
src/tools/pgindent/typedefs.list

index b7c65ea37d73d2d6c8837d3ce48208034d4fa66b..07c0d89c4f8648aa2f9b7e93bd994b4986359682 100644 (file)
@@ -601,32 +601,6 @@ 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
index dcf56446c747b36ad98fad79b2a5485ede583683..bf257a41c8559c38aaa035c85a2a66883736d5f1 100644 (file)
@@ -2213,6 +2213,17 @@ 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;
index ca44d39100a32ecbfeaba4f4f3e1a210be441e87..7cc443ec520f5664ffbf62bdf055096203499c85 100644 (file)
@@ -455,6 +455,7 @@ 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,
@@ -1305,6 +1306,17 @@ 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 */
@@ -2497,6 +2509,67 @@ 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)
+{
+       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:
+                       *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;
+               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;
+       }
+}
+
 /*
  * Raise error if a CURRENT OF expression is evaluated.
  *
index 2c3d64ea6e58f24188b31db4edb4652107493bf9..774db57ae2e16c5fb664e67b2966041a448d50a7 100644 (file)
@@ -1549,6 +1549,12 @@ 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);
index feb8208b7975889ea25ffe8295078a921616bd51..41ac4c6f45c682f24cc065b69e9741e1c13686b2 100644 (file)
@@ -126,6 +126,7 @@ void           *referenced_functions[] =
        ExecEvalRow,
        ExecEvalRowNotNull,
        ExecEvalRowNull,
+       ExecEvalSQLValueFunction,
        ExecEvalScalarArrayOp,
        ExecEvalHashedScalarArrayOp,
        ExecEvalSubPlan,
index fe3a113c8fc6178a1f78868ef9528aa55f16e994..0ed8712a631388008902e024062ed90abbe0c54d 100644 (file)
@@ -210,6 +210,9 @@ 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;
@@ -486,6 +489,8 @@ exprTypmod(const Node *expr)
                                return typmod;
                        }
                        break;
+               case T_SQLValueFunction:
+                       return ((const SQLValueFunction *) expr)->typmod;
                case T_JsonValueExpr:
                        return exprTypmod((Node *) ((const JsonValueExpr *) expr)->formatted_expr);
                case T_JsonConstructorExpr:
@@ -930,6 +935,13 @@ 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:
 
                        /*
@@ -1167,6 +1179,11 @@ exprSetCollation(Node *expr, Oid collation)
                case T_MinMaxExpr:
                        ((MinMaxExpr *) expr)->minmaxcollid = collation;
                        break;
+               case T_SQLValueFunction:
+                       Assert((((SQLValueFunction *) expr)->type == NAMEOID) ?
+                                  (collation == C_COLLATION_OID) :
+                                  (collation == InvalidOid));
+                       break;
                case T_XmlExpr:
                        Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ?
                                   (collation == DEFAULT_COLLATION_OID) :
@@ -1468,6 +1485,10 @@ 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;
@@ -1789,10 +1810,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, 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, 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.
  */
 bool
 check_functions_in_node(Node *node, check_function_callback checker,
@@ -2008,6 +2029,7 @@ 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:
@@ -2836,6 +2858,7 @@ expression_tree_mutator_impl(Node *node,
                        break;
                case T_Param:
                case T_CaseTestExpr:
+               case T_SQLValueFunction:
                case T_JsonFormat:
                case T_CoerceToDomainValue:
                case T_SetToDefault:
@@ -3797,6 +3820,7 @@ raw_expression_tree_walker_impl(Node *node,
                case T_JsonFormat:
                case T_SetToDefault:
                case T_CurrentOfExpr:
+               case T_SQLValueFunction:
                case T_Integer:
                case T_Float:
                case T_Boolean:
index 0a2562c149a34c1efb77b8c0414ff8aba1ace7a8..e60603df814c82c51d68c72b63915c296ac26556 100644 (file)
@@ -4606,6 +4606,7 @@ 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))
index 11269fee3ed65fbe7ca225ae6e41b5d3fb89b0c6..7f453b04f8bed73cb3415499e42c5d8ae43dd222 100644 (file)
@@ -412,6 +412,12 @@ contain_mutable_functions_walker(Node *node, void *context)
                /* Check all subnodes */
        }
 
+       if (IsA(node, SQLValueFunction))
+       {
+               /* all variants of SQLValueFunction are stable */
+               return true;
+       }
+
        if (IsA(node, NextValueExpr))
        {
                /* NextValueExpr is volatile */
@@ -560,8 +566,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.  Hence, none of
-        * them are of interest here.
+        * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
+        * SQLValueFunction is stable.  Hence, none of them are of interest here.
         */
 
        /* Recurse to check arguments */
@@ -606,9 +612,10 @@ 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.  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, while
+        * SQLValueFunction is stable.  Hence, none of them are of interest here.
+        * Also, since we're intentionally ignoring nextval(), presumably we
+        * should ignore NextValueExpr.
         */
 
        /* Recurse to check arguments */
@@ -754,8 +761,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.)  NextValueExpr is
-        * parallel-unsafe.
+        * parallel query in the presence of domain types.)  SQLValueFunction
+        * should be safe in all cases.  NextValueExpr is parallel-unsafe.
         */
        if (IsA(node, CoerceToDomain))
        {
@@ -1202,6 +1209,7 @@ 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:
@@ -3243,6 +3251,23 @@ 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:
                        {
                                /*
index d6426f3b8e0eabbea4fd5fc3e11d69ffdec34a67..6f5aa8a3cbcf662b7cada65b86968660a9e952d0 100644 (file)
@@ -198,6 +198,8 @@ 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);
@@ -15288,87 +15290,51 @@ func_expr_common_subexpr:
                                }
                        | CURRENT_DATE
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("current_date"),
-                                                                                          NIL,
-                                                                                          COERCE_SQL_SYNTAX,
-                                                                                          @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_DATE, -1, @1);
                                }
                        | CURRENT_TIME
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("current_time"),
-                                                                                          NIL,
-                                                                                          COERCE_SQL_SYNTAX,
-                                                                                          @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME, -1, @1);
                                }
                        | CURRENT_TIME '(' Iconst ')'
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("current_time"),
-                                                                                          list_make1(makeIntConst($3, @3)),
-                                                                                          COERCE_SQL_SYNTAX,
-                                                                                          @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME_N, $3, @1);
                                }
                        | CURRENT_TIMESTAMP
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("current_timestamp"),
-                                                                                          NIL,
-                                                                                          COERCE_SQL_SYNTAX,
-                                                                                          @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP, -1, @1);
                                }
                        | CURRENT_TIMESTAMP '(' Iconst ')'
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("current_timestamp"),
-                                                                                          list_make1(makeIntConst($3, @3)),
-                                                                                          COERCE_SQL_SYNTAX,
-                                                                                          @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP_N, $3, @1);
                                }
                        | LOCALTIME
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("localtime"),
-                                                                                          NIL,
-                                                                                          COERCE_SQL_SYNTAX,
-                                                                                          @1);
+                                       $$ = makeSQLValueFunction(SVFOP_LOCALTIME, -1, @1);
                                }
                        | LOCALTIME '(' Iconst ')'
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("localtime"),
-                                                                                          list_make1(makeIntConst($3, @3)),
-                                                                                          COERCE_SQL_SYNTAX,
-                                                                                          @1);
+                                       $$ = makeSQLValueFunction(SVFOP_LOCALTIME_N, $3, @1);
                                }
                        | LOCALTIMESTAMP
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("localtimestamp"),
-                                                                                          NIL,
-                                                                                          COERCE_SQL_SYNTAX,
-                                                                                          @1);
+                                       $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP, -1, @1);
                                }
                        | LOCALTIMESTAMP '(' Iconst ')'
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("localtimestamp"),
-                                                                                          list_make1(makeIntConst($3, @3)),
-                                                                                          COERCE_SQL_SYNTAX,
-                                                                                          @1);
+                                       $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP_N, $3, @1);
                                }
                        | CURRENT_ROLE
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("current_role"),
-                                                                                          NIL,
-                                                                                          COERCE_SQL_SYNTAX,
-                                                                                          @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_ROLE, -1, @1);
                                }
                        | CURRENT_USER
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("current_user"),
-                                                                                          NIL,
-                                                                                          COERCE_SQL_SYNTAX,
-                                                                                          @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_USER, -1, @1);
                                }
                        | SESSION_USER
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("session_user"),
-                                                                                          NIL,
-                                                                                          COERCE_SQL_SYNTAX,
-                                                                                          @1);
+                                       $$ = makeSQLValueFunction(SVFOP_SESSION_USER, -1, @1);
                                }
                        | SYSTEM_USER
                                {
@@ -15379,24 +15345,15 @@ func_expr_common_subexpr:
                                }
                        | USER
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("user"),
-                                                                                          NIL,
-                                                                                          COERCE_SQL_SYNTAX,
-                                                                                          @1);
+                                       $$ = makeSQLValueFunction(SVFOP_USER, -1, @1);
                                }
                        | CURRENT_CATALOG
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("current_catalog"),
-                                                                                          NIL,
-                                                                                          COERCE_SQL_SYNTAX,
-                                                                                          @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_CATALOG, -1, @1);
                                }
                        | CURRENT_SCHEMA
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("current_schema"),
-                                                                                          NIL,
-                                                                                          COERCE_SQL_SYNTAX,
-                                                                                          @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_SCHEMA, -1, @1);
                                }
                        | CAST '(' a_expr AS Typename ')'
                                { $$ = makeTypeCast($3, $5, @1); }
@@ -18519,6 +18476,18 @@ 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)
index 64356436ef716ef8e4a2e032b3a5a9d9c6ed7211..0b3632735bfbe6e28e94042eabc5887fcf7b7bed 100644 (file)
@@ -64,6 +64,8 @@ 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);
@@ -250,6 +252,11 @@ 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;
@@ -2220,6 +2227,59 @@ 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;
+               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;
+}
+
 static Node *
 transformXmlExpr(ParseState *pstate, XmlExpr *x)
 {
index e77b542fd76500303b2da5edac38fd541f98f25d..4cca97ff9c18b013ad97336d126b6dce4766d461 100644 (file)
@@ -1876,6 +1876,49 @@ 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;
+                               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:
                        /* make SQL/XML functions act like a regular function */
                        switch (((XmlExpr *) node)->op)
index a163fbb4ab5deb8b5cae62853a94f83fb674826a..ae0f24de2c3c54eb6d0405cdb212597c2407238e 100644 (file)
 
 /* 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)
@@ -66,26 +87,6 @@ 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)
@@ -301,10 +302,10 @@ EncodeSpecialDate(DateADT dt, char *str)
 
 
 /*
- * current_date -- implements CURRENT_DATE
+ * GetSQLCurrentDate -- implements CURRENT_DATE
  */
-Datum
-current_date(PG_FUNCTION_ARGS)
+DateADT
+GetSQLCurrentDate(void)
 {
        struct pg_tm tm;
 
@@ -330,56 +331,46 @@ current_date(PG_FUNCTION_ARGS)
                cache_mday = tm.tm_mday;
        }
 
-       return DateADTGetDatum(cache_date);
+       return cache_date;
 }
 
 /*
- * current_time -- implements CURRENT_TIME, CURRENT_TIME(n)
+ * GetSQLCurrentTime -- implements CURRENT_TIME, CURRENT_TIME(n)
  */
-Datum
-current_time(PG_FUNCTION_ARGS)
+TimeTzADT *
+GetSQLCurrentTime(int32 typmod)
 {
        TimeTzADT  *result;
        struct pg_tm tt,
                           *tm = &tt;
        fsec_t          fsec;
        int                     tz;
-       int32           typmod = -1;
-
-       if (!PG_ARGISNULL(0))
-               typmod = anytime_typmod_check(true, PG_GETARG_INT32(0));
 
        GetCurrentTimeUsec(tm, &fsec, &tz);
 
        result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
        tm2timetz(tm, fsec, tz, result);
        AdjustTimeForTypmod(&(result->time), typmod);
-
-       return TimeTzADTPGetDatum(result);
+       return result;
 }
 
 /*
- * sql_localtime -- implements LOCALTIME, LOCALTIME(n)
+ * GetSQLLocalTime -- implements LOCALTIME, LOCALTIME(n)
  */
-Datum
-sql_localtime(PG_FUNCTION_ARGS)
+TimeADT
+GetSQLLocalTime(int32 typmod)
 {
        TimeADT         result;
        struct pg_tm tt,
                           *tm = &tt;
        fsec_t          fsec;
        int                     tz;
-       int32           typmod = -1;
-
-       if (!PG_ARGISNULL(0))
-               typmod = anytime_typmod_check(false, PG_GETARG_INT32(0));
 
        GetCurrentTimeUsec(tm, &fsec, &tz);
 
        tm2time(tm, fsec, &result);
        AdjustTimeForTypmod(&result, typmod);
-
-       return TimeADTGetDatum(result);
+       return result;
 }
 
 
index 60f9d08d5dd28dc4a5c151b73e977049c9cb220d..e93d66a7ec5496ece5616dbf9fd810379d95eb23 100644 (file)
@@ -8254,6 +8254,7 @@ 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:
@@ -9242,6 +9243,67 @@ 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;
+                                       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;
+
                case T_XmlExpr:
                        {
                                XmlExpr    *xexpr = (XmlExpr *) node;
@@ -9816,6 +9878,7 @@ 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;
@@ -10217,33 +10280,6 @@ get_windowfunc_expr_helper(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 when 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
  *
@@ -10470,48 +10506,10 @@ 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;
 
-               case F_CURRENT_DATE:
-                       appendStringInfoString(buf, "CURRENT_DATE");
-                       return true;
-               case F_CURRENT_TIME:
-                       appendStringInfoString(buf, "CURRENT_TIME");
-                       get_func_sql_syntax_time(expr->args, context);
-                       return true;
-               case F_CURRENT_TIMESTAMP:
-                       appendStringInfoString(buf, "CURRENT_TIMESTAMP");
-                       get_func_sql_syntax_time(expr->args, context);
-                       return true;
-               case F_LOCALTIME:
-                       appendStringInfoString(buf, "LOCALTIME");
-                       get_func_sql_syntax_time(expr->args, context);
-                       return true;
-               case F_LOCALTIMESTAMP:
-                       appendStringInfoString(buf, "LOCALTIMESTAMP");
-                       get_func_sql_syntax_time(expr->args, context);
-                       return true;
-
                case F_XMLEXISTS:
                        /* XMLEXISTS ... extra parens because args are c_expr */
                        appendStringInfoString(buf, "XMLEXISTS((");
index aaadc68ae6a9d96ff759a0887f99624c1c2b170c..0e50aaec5a52639dd39e0fa684b848fc5ecaa2df 100644 (file)
@@ -83,6 +83,27 @@ 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)
@@ -103,26 +124,6 @@ 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)
@@ -1594,42 +1595,33 @@ GetCurrentTimestamp(void)
 }
 
 /*
- * current_timestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
+ * GetSQLCurrentTimestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
  */
-Datum
-current_timestamp(PG_FUNCTION_ARGS)
+TimestampTz
+GetSQLCurrentTimestamp(int32 typmod)
 {
        TimestampTz ts;
-       int32           typmod = -1;
-
-       if (!PG_ARGISNULL(0))
-               typmod = anytimestamp_typmod_check(true, PG_GETARG_INT32(0));
 
        ts = GetCurrentTransactionStartTimestamp();
        if (typmod >= 0)
                AdjustTimestampForTypmod(&ts, typmod, NULL);
-       return TimestampTzGetDatum(ts);
+       return ts;
 }
 
 /*
- * sql_localtimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
+ * GetSQLLocalTimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
  */
-Datum
-sql_localtimestamp(PG_FUNCTION_ARGS)
+Timestamp
+GetSQLLocalTimestamp(int32 typmod)
 {
        Timestamp       ts;
-       int32           typmod = -1;
-
-       if (!PG_ARGISNULL(0))
-               typmod = anytimestamp_typmod_check(false, PG_GETARG_INT32(0));
 
        ts = timestamptz2timestamp(GetCurrentTransactionStartTimestamp());
        if (typmod >= 0)
                AdjustTimestampForTypmod(&ts, typmod, NULL);
-       return TimestampGetDatum(ts);
+       return ts;
 }
 
-
 /*
  * timeofday(*) -- returns the current time as a text.
  */
index d10cc28b0c1c5e703c096250814bd9c58776f4f7..e617381bf40543f04bd32f5a9ceed6d7cdf83051 100644 (file)
@@ -57,6 +57,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     202305121
+#define CATALOG_VERSION_NO     202305171
 
 #endif
index b2bc81b15f8d4b8dc4fd03f635910e14580922f2..d7a60b39b584e3b960ce2a6f7d428dc7a08086db 100644 (file)
 { 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' },
 { 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', proisstrict => 'f', provolatile => 's',
-  prorettype => 'timetz', proargtypes => 'int4', prosrc => 'current_time' },
-{ oid => '9980', descr => 'current timestamp',
-  proname => 'current_timestamp', proisstrict => 'f', provolatile => 's',
-  prorettype => 'timestamptz', proargtypes => 'int4',
-  prosrc => 'current_timestamp' },
-{ oid => '9981', descr => 'local time',
-  proname => 'localtime', proisstrict => 'f', provolatile => 's',
-  prorettype => 'time', proargtypes => 'int4', prosrc => 'sql_localtime' },
-{ oid => '9982', descr => 'local timestamp',
-  proname => 'localtimestamp', proisstrict => 'f', provolatile => 's',
-  prorettype => 'timestamp', proargtypes => 'int4',
-  prosrc => 'sql_localtimestamp' },
 
 { oid => '744',
   proname => 'array_eq', prorettype => 'bool',
index 157b0d85f29286166e1edb495f2bba46a47f81ce..048573c2bcb5756a0dd537be3197a0e48f900ebe 100644 (file)
@@ -171,6 +171,7 @@ typedef enum ExprEvalOp
        EEOP_DISTINCT,
        EEOP_NOT_DISTINCT,
        EEOP_NULLIF,
+       EEOP_SQLVALUEFUNCTION,
        EEOP_CURRENTOFEXPR,
        EEOP_NEXTVALUEEXPR,
        EEOP_ARRAYEXPR,
@@ -418,6 +419,12 @@ typedef struct ExprEvalStep
                        FunctionCallInfo fcinfo_data_in;
                }                       iocoerce;
 
+               /* for EEOP_SQLVALUEFUNCTION */
+               struct
+               {
+                       SQLValueFunction *svf;
+               }                       sqlvaluefunction;
+
                /* for EEOP_NEXTVALUEEXPR */
                struct
                {
@@ -769,6 +776,7 @@ 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,
index be9c29f0bfb0fa8acda691849c87f981d6fee47e..08e7dae73f1adb2e1c9d7cc6d304077c76a9f346 100644 (file)
@@ -1445,6 +1445,49 @@ typedef struct MinMaxExpr
        int                     location;
 } 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,
+       SVFOP_CURRENT_ROLE,
+       SVFOP_CURRENT_USER,
+       SVFOP_USER,
+       SVFOP_SESSION_USER,
+       SVFOP_CURRENT_CATALOG,
+       SVFOP_CURRENT_SCHEMA
+} SQLValueFunctionOp;
+
+typedef struct SQLValueFunction
+{
+       Expr            xpr;
+       SQLValueFunctionOp op;          /* which function this is */
+       /*
+        * Result type/typmod.  Type is fully determined by "op", so no need to
+        * include this Oid in the query jumbling.
+        */
+       Oid                     type pg_node_attr(query_jumble_ignore);
+       int32           typmod;
+       int                     location;               /* token location, or -1 if unknown */
+} SQLValueFunction;
+
 /*
  * XmlExpr - various SQL/XML functions requiring special grammar productions
  *
index 5fd886b3dba6450fea0f28a3c9b3a08260ba5ab5..97e1a0212172e817337561aeee344c2b131edffd 100644 (file)
@@ -96,6 +96,7 @@ 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);
@@ -103,6 +104,9 @@ 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);
index edd59dc43226bda5bfa478681d4ccad367a66e31..c4dd96c8c97c85924afc413b7fe4b6663212e966 100644 (file)
@@ -95,7 +95,11 @@ 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,
index d2c6db1bd5014df6f1ef8621df52f155e1319f11..caeeb19674092169763f2c0d3cfe42d0feac22fe 100644 (file)
@@ -2,7 +2,7 @@
 -- expression evaluation tests that don't fit into a more specific file
 --
 --
--- Tests for various FuncCalls with COERCE_SQL_SYNTAX.
+-- Tests for SQLValueFunction
 --
 -- current_date  (always matches because of transactional behaviour)
 SELECT date(now())::text = current_date::text;
index d315ef5af50a7e734a4c5891b54d0dfeff70f480..e02c21f3368e602a8107e2caf07b0adc0a18f118 100644 (file)
@@ -3,7 +3,7 @@
 --
 
 --
--- Tests for various FuncCalls with COERCE_SQL_SYNTAX.
+-- Tests for SQLValueFunction
 --
 
 
index b4058b88c3e9ef319d1677e13bbbf6bb3165ab4c..06da7cd428480b876dbe726982f1fe31afd5c250 100644 (file)
@@ -2425,6 +2425,8 @@ SQLFunctionCache
 SQLFunctionCachePtr
 SQLFunctionParseInfo
 SQLFunctionParseInfoPtr
+SQLValueFunction
+SQLValueFunctionOp
 SSL
 SSLExtensionInfoContext
 SSL_CTX