]> granicus.if.org Git - postgresql/commitdiff
Improve parsetree representation of special functions such as CURRENT_DATE.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 17 Aug 2016 00:33:01 +0000 (20:33 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 17 Aug 2016 00:33:01 +0000 (20:33 -0400)
We implement a dozen or so parameterless functions that the SQL standard
defines special syntax for.  Up to now, that was done by converting them
into more or less ad-hoc constructs such as "'now'::text::date".  That's
messy for multiple reasons: it exposes what should be implementation
details to users, and performance is worse than it needs to be in several
cases.  To improve matters, invent a new expression node type
SQLValueFunction that can represent any of these parameterless functions.

Bump catversion because this changes stored parsetrees for rules.

Discussion: <30058.1463091294@sss.pgh.pa.us>

24 files changed:
contrib/pg_stat_statements/pg_stat_statements.c
src/backend/executor/execQual.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/nodeFuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.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/nodes/nodes.h
src/include/nodes/primnodes.h
src/include/utils/date.h
src/include/utils/timestamp.h
src/pl/plpgsql/src/pl_exec.c
src/test/regress/expected/rowsecurity.out
src/test/regress/expected/rules.out
src/test/regress/expected/select_views.out
src/test/regress/expected/select_views_1.out

index 3d9b8e45d9fa7db1420c85073483f0bbb7e26ff5..8ce24e0401fa9812bdd02f9c4571bfd81f4e445a 100644 (file)
@@ -2632,6 +2632,15 @@ JumbleExpr(pgssJumbleState *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;
index cbb76d1f1cd2c63229fc95d43704c3b306f2d6da..743e7d636a066853d3c1e073618221bafdd7b55a 100644 (file)
 #include "pgstat.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
+#include "utils/date.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
+#include "utils/timestamp.h"
 #include "utils/typcache.h"
 #include "utils/xml.h"
 
@@ -147,6 +149,9 @@ static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr,
 static Datum ExecEvalMinMax(MinMaxExprState *minmaxExpr,
                           ExprContext *econtext,
                           bool *isNull, ExprDoneCond *isDone);
+static Datum ExecEvalSQLValueFunction(ExprState *svfExpr,
+                                                ExprContext *econtext,
+                                                bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
                        bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalNullIf(FuncExprState *nullIfExpr,
@@ -3530,6 +3535,75 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
        return result;
 }
 
+/* ----------------------------------------------------------------
+ *             ExecEvalSQLValueFunction
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalSQLValueFunction(ExprState *svfExpr,
+                                                ExprContext *econtext,
+                                                bool *isNull, ExprDoneCond *isDone)
+{
+       Datum           result = (Datum) 0;
+       SQLValueFunction *svf = (SQLValueFunction *) svfExpr->expr;
+       FunctionCallInfoData fcinfo;
+
+       if (isDone)
+               *isDone = ExprSingleResult;
+       *isNull = 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:
+                       result = DateADTGetDatum(GetSQLCurrentDate());
+                       break;
+               case SVFOP_CURRENT_TIME:
+               case SVFOP_CURRENT_TIME_N:
+                       result = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod));
+                       break;
+               case SVFOP_CURRENT_TIMESTAMP:
+               case SVFOP_CURRENT_TIMESTAMP_N:
+                       result = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod));
+                       break;
+               case SVFOP_LOCALTIME:
+               case SVFOP_LOCALTIME_N:
+                       result = TimeADTGetDatum(GetSQLLocalTime(svf->typmod));
+                       break;
+               case SVFOP_LOCALTIMESTAMP:
+               case SVFOP_LOCALTIMESTAMP_N:
+                       result = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
+                       break;
+               case SVFOP_CURRENT_ROLE:
+               case SVFOP_CURRENT_USER:
+               case SVFOP_USER:
+                       InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
+                       result = current_user(&fcinfo);
+                       *isNull = fcinfo.isnull;
+                       break;
+               case SVFOP_SESSION_USER:
+                       InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
+                       result = session_user(&fcinfo);
+                       *isNull = fcinfo.isnull;
+                       break;
+               case SVFOP_CURRENT_CATALOG:
+                       InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
+                       result = current_database(&fcinfo);
+                       *isNull = fcinfo.isnull;
+                       break;
+               case SVFOP_CURRENT_SCHEMA:
+                       InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
+                       result = current_schema(&fcinfo);
+                       *isNull = fcinfo.isnull;
+                       break;
+       }
+
+       return result;
+}
+
 /* ----------------------------------------------------------------
  *             ExecEvalXml
  * ----------------------------------------------------------------
@@ -5086,6 +5160,10 @@ ExecInitExpr(Expr *node, PlanState *parent)
                                state = (ExprState *) mstate;
                        }
                        break;
+               case T_SQLValueFunction:
+                       state = (ExprState *) makeNode(ExprState);
+                       state->evalfunc = ExecEvalSQLValueFunction;
+                       break;
                case T_XmlExpr:
                        {
                                XmlExpr    *xexpr = (XmlExpr *) node;
index 3244c76ddcca13b79db7902da12a22f4f3ccf283..c7a06442ba699886b4d33b55aac38d152fc8ee5f 100644 (file)
@@ -1752,6 +1752,22 @@ _copyMinMaxExpr(const MinMaxExpr *from)
        return newnode;
 }
 
+/*
+ * _copySQLValueFunction
+ */
+static SQLValueFunction *
+_copySQLValueFunction(const SQLValueFunction *from)
+{
+       SQLValueFunction *newnode = makeNode(SQLValueFunction);
+
+       COPY_SCALAR_FIELD(op);
+       COPY_SCALAR_FIELD(type);
+       COPY_SCALAR_FIELD(typmod);
+       COPY_LOCATION_FIELD(location);
+
+       return newnode;
+}
+
 /*
  * _copyXmlExpr
  */
@@ -4525,6 +4541,9 @@ copyObject(const void *from)
                case T_MinMaxExpr:
                        retval = _copyMinMaxExpr(from);
                        break;
+               case T_SQLValueFunction:
+                       retval = _copySQLValueFunction(from);
+                       break;
                case T_XmlExpr:
                        retval = _copyXmlExpr(from);
                        break;
index 1eb679926af9f0f1ab412f11278711756e6ccae0..448e1a9d55a0420a3f41587b63452a770c421dd3 100644 (file)
@@ -619,6 +619,17 @@ _equalMinMaxExpr(const MinMaxExpr *a, const MinMaxExpr *b)
        return true;
 }
 
+static bool
+_equalSQLValueFunction(const SQLValueFunction *a, const SQLValueFunction *b)
+{
+       COMPARE_SCALAR_FIELD(op);
+       COMPARE_SCALAR_FIELD(type);
+       COMPARE_SCALAR_FIELD(typmod);
+       COMPARE_LOCATION_FIELD(location);
+
+       return true;
+}
+
 static bool
 _equalXmlExpr(const XmlExpr *a, const XmlExpr *b)
 {
@@ -2842,6 +2853,9 @@ equal(const void *a, const void *b)
                case T_MinMaxExpr:
                        retval = _equalMinMaxExpr(a, b);
                        break;
+               case T_SQLValueFunction:
+                       retval = _equalSQLValueFunction(a, b);
+                       break;
                case T_XmlExpr:
                        retval = _equalXmlExpr(a, b);
                        break;
index cd391673511693217ef97099a8d3bcf2cbd8face..399744193c0b90998bbbdaf92e5e28c600cb0e3c 100644 (file)
@@ -218,6 +218,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;
@@ -479,6 +482,8 @@ 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:
@@ -718,6 +723,8 @@ expression_returns_set_walker(Node *node, void *context)
                return false;
        if (IsA(node, MinMaxExpr))
                return false;
+       if (IsA(node, SQLValueFunction))
+               return false;
        if (IsA(node, XmlExpr))
                return false;
 
@@ -883,6 +890,9 @@ exprCollation(const Node *expr)
                case T_MinMaxExpr:
                        coll = ((const MinMaxExpr *) expr)->minmaxcollid;
                        break;
+               case T_SQLValueFunction:
+                       coll = InvalidOid;      /* all cases return non-collatable types */
+                       break;
                case T_XmlExpr:
 
                        /*
@@ -1091,6 +1101,9 @@ exprSetCollation(Node *expr, Oid collation)
                case T_MinMaxExpr:
                        ((MinMaxExpr *) expr)->minmaxcollid = collation;
                        break;
+               case T_SQLValueFunction:
+                       Assert(!OidIsValid(collation));         /* no collatable results */
+                       break;
                case T_XmlExpr:
                        Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ?
                                   (collation == DEFAULT_COLLATION_OID) :
@@ -1364,6 +1377,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;
@@ -1633,9 +1650,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, and CoerceToDomain 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, and CoerceToDomain
+ * 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,
@@ -1859,6 +1877,7 @@ expression_tree_walker(Node *node,
                case T_CaseTestExpr:
                case T_SetToDefault:
                case T_CurrentOfExpr:
+               case T_SQLValueFunction:
                case T_RangeTblRef:
                case T_SortGroupClause:
                        /* primitive node types with no expression subnodes */
@@ -2433,6 +2452,7 @@ expression_tree_mutator(Node *node,
                case T_CaseTestExpr:
                case T_SetToDefault:
                case T_CurrentOfExpr:
+               case T_SQLValueFunction:
                case T_RangeTblRef:
                case T_SortGroupClause:
                        return (Node *) copyObject(node);
@@ -3197,6 +3217,7 @@ raw_expression_tree_walker(Node *node,
        {
                case T_SetToDefault:
                case T_CurrentOfExpr:
+               case T_SQLValueFunction:
                case T_Integer:
                case T_Float:
                case T_String:
index acaf4ea5ebcd694b266001ddc8526891b56bcddb..1fab807772cc189970bd62c4b184b772f9f2fa3b 100644 (file)
@@ -1423,6 +1423,17 @@ _outMinMaxExpr(StringInfo str, const MinMaxExpr *node)
        WRITE_LOCATION_FIELD(location);
 }
 
+static void
+_outSQLValueFunction(StringInfo str, const SQLValueFunction *node)
+{
+       WRITE_NODE_TYPE("SQLVALUEFUNCTION");
+
+       WRITE_ENUM_FIELD(op, SQLValueFunctionOp);
+       WRITE_OID_FIELD(type);
+       WRITE_INT_FIELD(typmod);
+       WRITE_LOCATION_FIELD(location);
+}
+
 static void
 _outXmlExpr(StringInfo str, const XmlExpr *node)
 {
@@ -3522,6 +3533,9 @@ outNode(StringInfo str, const void *obj)
                        case T_MinMaxExpr:
                                _outMinMaxExpr(str, obj);
                                break;
+                       case T_SQLValueFunction:
+                               _outSQLValueFunction(str, obj);
+                               break;
                        case T_XmlExpr:
                                _outXmlExpr(str, obj);
                                break;
index 94954dcc722a3d865bc50a7b0a8c31cb68be2bda..c83063e2197f0426e57ecf99ae6a583c448866ad 100644 (file)
@@ -1041,6 +1041,22 @@ _readMinMaxExpr(void)
        READ_DONE();
 }
 
+/*
+ * _readSQLValueFunction
+ */
+static SQLValueFunction *
+_readSQLValueFunction(void)
+{
+       READ_LOCALS(SQLValueFunction);
+
+       READ_ENUM_FIELD(op, SQLValueFunctionOp);
+       READ_OID_FIELD(type);
+       READ_INT_FIELD(typmod);
+       READ_LOCATION_FIELD(location);
+
+       READ_DONE();
+}
+
 /*
  * _readXmlExpr
  */
@@ -2348,6 +2364,8 @@ parseNodeString(void)
                return_value = _readCoalesceExpr();
        else if (MATCH("MINMAX", 6))
                return_value = _readMinMaxExpr();
+       else if (MATCH("SQLVALUEFUNCTION", 16))
+               return_value = _readSQLValueFunction();
        else if (MATCH("XMLEXPR", 7))
                return_value = _readXmlExpr();
        else if (MATCH("NULLTEST", 8))
index 4e23898ff91f274420434d43744eed645a01d988..a40ad406065623afc34d2e262d7b03ba0ddbe1a0 100644 (file)
@@ -962,6 +962,12 @@ contain_mutable_functions_walker(Node *node, void *context)
                                                                context))
                return true;
 
+       if (IsA(node, SQLValueFunction))
+       {
+               /* all variants of SQLValueFunction are stable */
+               return true;
+       }
+
        /*
         * It should be safe to treat MinMaxExpr as immutable, because it will
         * depend on a non-cross-type btree comparison function, and those should
@@ -1031,7 +1037,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.
+        * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
+        * SQLValueFunction is stable.  Hence, none of them are of interest here.
         */
 
        /* Recurse to check arguments */
@@ -1076,7 +1083,8 @@ 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.
+        * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
+        * SQLValueFunction is stable.  Hence, none of them are of interest here.
         */
 
        /* Recurse to check arguments */
@@ -1143,7 +1151,8 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *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.)
+        * parallel query in the presence of domain types.)  SQLValueFunction
+        * should be safe in all cases.
         */
        if (IsA(node, CoerceToDomain))
        {
@@ -1458,6 +1467,7 @@ contain_leaked_vars_walker(Node *node, void *context)
                case T_CaseTestExpr:
                case T_RowExpr:
                case T_MinMaxExpr:
+               case T_SQLValueFunction:
                case T_NullTest:
                case T_BooleanTest:
                case T_List:
index 6a0f7b393cb9655289cc647bfbc347142d8e2fa9..cb5cfc480cffd77a278dd7d6ce27e4e69d39d999 100644 (file)
@@ -165,6 +165,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);
@@ -12330,143 +12332,63 @@ func_expr_common_subexpr:
                                }
                        | CURRENT_DATE
                                {
-                                       /*
-                                        * Translate as "'now'::text::date".
-                                        *
-                                        * We cannot use "'now'::date" because coerce_type() will
-                                        * immediately reduce that to a constant representing
-                                        * today's date.  We need to delay the conversion until
-                                        * runtime, else the wrong things will happen when
-                                        * CURRENT_DATE is used in a column default value or rule.
-                                        *
-                                        * This could be simplified if we had a way to generate
-                                        * an expression tree representing runtime application
-                                        * of type-input conversion functions.  (As of PG 7.3
-                                        * that is actually possible, but not clear that we want
-                                        * to rely on it.)
-                                        *
-                                        * The token location is attached to the run-time
-                                        * typecast, not to the Const, for the convenience of
-                                        * pg_stat_statements (which doesn't want these constructs
-                                        * to appear to be replaceable constants).
-                                        */
-                                       Node *n;
-                                       n = makeStringConstCast("now", -1, SystemTypeName("text"));
-                                       $$ = makeTypeCast(n, SystemTypeName("date"), @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_DATE, -1, @1);
                                }
                        | CURRENT_TIME
                                {
-                                       /*
-                                        * Translate as "'now'::text::timetz".
-                                        * See comments for CURRENT_DATE.
-                                        */
-                                       Node *n;
-                                       n = makeStringConstCast("now", -1, SystemTypeName("text"));
-                                       $$ = makeTypeCast(n, SystemTypeName("timetz"), @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME, -1, @1);
                                }
                        | CURRENT_TIME '(' Iconst ')'
                                {
-                                       /*
-                                        * Translate as "'now'::text::timetz(n)".
-                                        * See comments for CURRENT_DATE.
-                                        */
-                                       Node *n;
-                                       TypeName *d;
-                                       n = makeStringConstCast("now", -1, SystemTypeName("text"));
-                                       d = SystemTypeName("timetz");
-                                       d->typmods = list_make1(makeIntConst($3, @3));
-                                       $$ = makeTypeCast(n, d, @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_TIME_N, $3, @1);
                                }
                        | CURRENT_TIMESTAMP
                                {
-                                       /*
-                                        * Translate as "now()", since we have a function that
-                                        * does exactly what is needed.
-                                        */
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("now"), NIL, @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP, -1, @1);
                                }
                        | CURRENT_TIMESTAMP '(' Iconst ')'
                                {
-                                       /*
-                                        * Translate as "'now'::text::timestamptz(n)".
-                                        * See comments for CURRENT_DATE.
-                                        */
-                                       Node *n;
-                                       TypeName *d;
-                                       n = makeStringConstCast("now", -1, SystemTypeName("text"));
-                                       d = SystemTypeName("timestamptz");
-                                       d->typmods = list_make1(makeIntConst($3, @3));
-                                       $$ = makeTypeCast(n, d, @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP_N, $3, @1);
                                }
                        | LOCALTIME
                                {
-                                       /*
-                                        * Translate as "'now'::text::time".
-                                        * See comments for CURRENT_DATE.
-                                        */
-                                       Node *n;
-                                       n = makeStringConstCast("now", -1, SystemTypeName("text"));
-                                       $$ = makeTypeCast((Node *)n, SystemTypeName("time"), @1);
+                                       $$ = makeSQLValueFunction(SVFOP_LOCALTIME, -1, @1);
                                }
                        | LOCALTIME '(' Iconst ')'
                                {
-                                       /*
-                                        * Translate as "'now'::text::time(n)".
-                                        * See comments for CURRENT_DATE.
-                                        */
-                                       Node *n;
-                                       TypeName *d;
-                                       n = makeStringConstCast("now", -1, SystemTypeName("text"));
-                                       d = SystemTypeName("time");
-                                       d->typmods = list_make1(makeIntConst($3, @3));
-                                       $$ = makeTypeCast((Node *)n, d, @1);
+                                       $$ = makeSQLValueFunction(SVFOP_LOCALTIME_N, $3, @1);
                                }
                        | LOCALTIMESTAMP
                                {
-                                       /*
-                                        * Translate as "'now'::text::timestamp".
-                                        * See comments for CURRENT_DATE.
-                                        */
-                                       Node *n;
-                                       n = makeStringConstCast("now", -1, SystemTypeName("text"));
-                                       $$ = makeTypeCast(n, SystemTypeName("timestamp"), @1);
+                                       $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP, -1, @1);
                                }
                        | LOCALTIMESTAMP '(' Iconst ')'
                                {
-                                       /*
-                                        * Translate as "'now'::text::timestamp(n)".
-                                        * See comments for CURRENT_DATE.
-                                        */
-                                       Node *n;
-                                       TypeName *d;
-                                       n = makeStringConstCast("now", -1, SystemTypeName("text"));
-                                       d = SystemTypeName("timestamp");
-                                       d->typmods = list_make1(makeIntConst($3, @3));
-                                       $$ = makeTypeCast(n, d, @1);
+                                       $$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP_N, $3, @1);
                                }
                        | CURRENT_ROLE
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("current_user"), NIL, @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_ROLE, -1, @1);
                                }
                        | CURRENT_USER
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("current_user"), NIL, @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_USER, -1, @1);
                                }
                        | SESSION_USER
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("session_user"), NIL, @1);
+                                       $$ = makeSQLValueFunction(SVFOP_SESSION_USER, -1, @1);
                                }
                        | USER
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("current_user"), NIL, @1);
+                                       $$ = makeSQLValueFunction(SVFOP_USER, -1, @1);
                                }
                        | CURRENT_CATALOG
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("current_database"), NIL, @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_CATALOG, -1, @1);
                                }
                        | CURRENT_SCHEMA
                                {
-                                       $$ = (Node *) makeFuncCall(SystemFuncName("current_schema"), NIL, @1);
+                                       $$ = makeSQLValueFunction(SVFOP_CURRENT_SCHEMA, -1, @1);
                                }
                        | CAST '(' a_expr AS Typename ')'
                                { $$ = makeTypeCast($3, $5, @1); }
@@ -14710,6 +14632,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 cead21283d00a3f201515de2808993b468be49c7..63f7965532ef87b07d7a0afabc09ef2608cb1b4f 100644 (file)
@@ -34,7 +34,9 @@
 #include "parser/parse_type.h"
 #include "parser/parse_agg.h"
 #include "utils/builtins.h"
+#include "utils/date.h"
 #include "utils/lsyscache.h"
+#include "utils/timestamp.h"
 #include "utils/xml.h"
 
 
@@ -107,6 +109,8 @@ static Node *transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
 static Node *transformRowExpr(ParseState *pstate, RowExpr *r);
 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);
@@ -306,6 +310,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;
@@ -2178,6 +2187,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 fc93063ed0b48cbc0922bc27c52ef0f2c50633b5..b7b82bfb6b1095252998c91e97f7142a26ce3b96 100644 (file)
@@ -1761,6 +1761,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 420f383a804cf136d61aa512074b1b8e12900508..bc7d190210a5a5611f85938bda01bb96627a02c7 100644 (file)
@@ -21,6 +21,7 @@
 #include <time.h>
 
 #include "access/hash.h"
+#include "access/xact.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "parser/scansup.h"
@@ -51,7 +52,6 @@ static void AdjustTimeForTypmod(TimeADT *time, int32 typmod);
 static int32
 anytime_typmodin(bool istz, ArrayType *ta)
 {
-       int32           typmod;
        int32      *tl;
        int                     n;
 
@@ -66,22 +66,27 @@ anytime_typmodin(bool istz, ArrayType *ta)
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                 errmsg("invalid type modifier")));
 
-       if (*tl < 0)
+       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)
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                 errmsg("TIME(%d)%s precision must not be negative",
-                                               *tl, (istz ? " WITH TIME ZONE" : ""))));
-       if (*tl > MAX_TIME_PRECISION)
+                                               typmod, (istz ? " WITH TIME ZONE" : ""))));
+       if (typmod > MAX_TIME_PRECISION)
        {
                ereport(WARNING,
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                 errmsg("TIME(%d)%s precision reduced to maximum allowed, %d",
-                                               *tl, (istz ? " WITH TIME ZONE" : ""),
+                                               typmod, (istz ? " WITH TIME ZONE" : ""),
                                                MAX_TIME_PRECISION)));
                typmod = MAX_TIME_PRECISION;
        }
-       else
-               typmod = *tl;
 
        return typmod;
 }
@@ -298,6 +303,80 @@ EncodeSpecialDate(DateADT dt, char *str)
 }
 
 
+/*
+ * GetSQLCurrentDate -- implements CURRENT_DATE
+ */
+DateADT
+GetSQLCurrentDate(void)
+{
+       TimestampTz ts;
+       struct pg_tm tt,
+                          *tm = &tt;
+       fsec_t          fsec;
+       int                     tz;
+
+       ts = GetCurrentTransactionStartTimestamp();
+
+       if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0)
+               ereport(ERROR,
+                               (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+                                errmsg("timestamp out of range")));
+
+       return date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - POSTGRES_EPOCH_JDATE;
+}
+
+/*
+ * GetSQLCurrentTime -- implements CURRENT_TIME, CURRENT_TIME(n)
+ */
+TimeTzADT *
+GetSQLCurrentTime(int32 typmod)
+{
+       TimeTzADT  *result;
+       TimestampTz ts;
+       struct pg_tm tt,
+                          *tm = &tt;
+       fsec_t          fsec;
+       int                     tz;
+
+       ts = GetCurrentTransactionStartTimestamp();
+
+       if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0)
+               ereport(ERROR,
+                               (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+                                errmsg("timestamp out of range")));
+
+       result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
+       tm2timetz(tm, fsec, tz, result);
+       AdjustTimeForTypmod(&(result->time), typmod);
+       return result;
+}
+
+/*
+ * GetSQLLocalTime -- implements LOCALTIME, LOCALTIME(n)
+ */
+TimeADT
+GetSQLLocalTime(int32 typmod)
+{
+       TimeADT         result;
+       TimestampTz ts;
+       struct pg_tm tt,
+                          *tm = &tt;
+       fsec_t          fsec;
+       int                     tz;
+
+       ts = GetCurrentTransactionStartTimestamp();
+
+       if (timestamp2tm(ts, &tz, tm, &fsec, NULL, NULL) != 0)
+               ereport(ERROR,
+                               (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+                                errmsg("timestamp out of range")));
+
+       tm2time(tm, fsec, &result);
+       AdjustTimeForTypmod(&result, typmod);
+       return result;
+}
+
+
 /*
  * Comparison functions for dates
  */
index ec966c752ea46039ea68132d5b0c95877e0ca267..8a81d7a078f98d84a89fea6279e1fd37d2217bb3 100644 (file)
@@ -6884,6 +6884,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_NullIfExpr:
                case T_Aggref:
@@ -7871,6 +7872,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;
index d7ee865cf750a0fda4ab7c82d43279855bced5af..c1d6f05b5ed79746fe7e4ffec64c136a5a8f1f9c 100644 (file)
@@ -72,13 +72,13 @@ static Timestamp dt2local(Timestamp dt, int timezone);
 static void AdjustTimestampForTypmod(Timestamp *time, int32 typmod);
 static void AdjustIntervalForTypmod(Interval *interval, int32 typmod);
 static TimestampTz timestamp2timestamptz(Timestamp timestamp);
+static Timestamp timestamptz2timestamp(TimestampTz timestamp);
 
 
 /* common code for timestamptypmodin and timestamptztypmodin */
 static int32
 anytimestamp_typmodin(bool istz, ArrayType *ta)
 {
-       int32           typmod;
        int32      *tl;
        int                     n;
 
@@ -93,22 +93,27 @@ anytimestamp_typmodin(bool istz, ArrayType *ta)
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                 errmsg("invalid type modifier")));
 
-       if (*tl < 0)
+       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)
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                 errmsg("TIMESTAMP(%d)%s precision must not be negative",
-                                               *tl, (istz ? " WITH TIME ZONE" : ""))));
-       if (*tl > MAX_TIMESTAMP_PRECISION)
+                                               typmod, (istz ? " WITH TIME ZONE" : ""))));
+       if (typmod > MAX_TIMESTAMP_PRECISION)
        {
                ereport(WARNING,
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                   errmsg("TIMESTAMP(%d)%s precision reduced to maximum allowed, %d",
-                                 *tl, (istz ? " WITH TIME ZONE" : ""),
+                                 typmod, (istz ? " WITH TIME ZONE" : ""),
                                  MAX_TIMESTAMP_PRECISION)));
                typmod = MAX_TIMESTAMP_PRECISION;
        }
-       else
-               typmod = *tl;
 
        return typmod;
 }
@@ -336,6 +341,10 @@ timestamp_scale(PG_FUNCTION_ARGS)
        PG_RETURN_TIMESTAMP(result);
 }
 
+/*
+ * AdjustTimestampForTypmod --- round off a timestamp to suit given typmod
+ * Works for either timestamp or timestamptz.
+ */
 static void
 AdjustTimestampForTypmod(Timestamp *time, int32 typmod)
 {
@@ -1686,6 +1695,34 @@ IntegerTimestampToTimestampTz(int64 timestamp)
 }
 #endif
 
+/*
+ * GetSQLCurrentTimestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
+ */
+TimestampTz
+GetSQLCurrentTimestamp(int32 typmod)
+{
+       TimestampTz ts;
+
+       ts = GetCurrentTransactionStartTimestamp();
+       if (typmod >= 0)
+               AdjustTimestampForTypmod(&ts, typmod);
+       return ts;
+}
+
+/*
+ * GetSQLLocalTimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
+ */
+Timestamp
+GetSQLLocalTimestamp(int32 typmod)
+{
+       Timestamp       ts;
+
+       ts = timestamptz2timestamp(GetCurrentTransactionStartTimestamp());
+       if (typmod >= 0)
+               AdjustTimestampForTypmod(&ts, typmod);
+       return ts;
+}
+
 /*
  * TimestampDifference -- convert the difference between two timestamps
  *             into integer seconds and microseconds
@@ -5415,6 +5452,13 @@ Datum
 timestamptz_timestamp(PG_FUNCTION_ARGS)
 {
        TimestampTz timestamp = PG_GETARG_TIMESTAMPTZ(0);
+
+       PG_RETURN_TIMESTAMP(timestamptz2timestamp(timestamp));
+}
+
+static Timestamp
+timestamptz2timestamp(TimestampTz timestamp)
+{
        Timestamp       result;
        struct pg_tm tt,
                           *tm = &tt;
@@ -5434,7 +5478,7 @@ timestamptz_timestamp(PG_FUNCTION_ARGS)
                                        (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
                                         errmsg("timestamp out of range")));
        }
-       PG_RETURN_TIMESTAMP(result);
+       return result;
 }
 
 /* timestamptz_zone()
index 2ca3cd911a0225e6610ce978afbe0992d03a0b52..82810c8fbaeadd847961e2ec65f7e8cac25c78a0 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201608131
+#define CATALOG_VERSION_NO     201608161
 
 #endif
index 6b850e4bc4ecbd4aded4db991168900144fea02f..2f7efa810c1ef136e836737b046173fc95d5c7b9 100644 (file)
@@ -166,6 +166,7 @@ typedef enum NodeTag
        T_RowCompareExpr,
        T_CoalesceExpr,
        T_MinMaxExpr,
+       T_SQLValueFunction,
        T_XmlExpr,
        T_NullTest,
        T_BooleanTest,
index df2d27d77ca6ca8270dd3a3d85f448fb5e25f022..65510b010bad010aaad283c70ff2afb246b575b3 100644 (file)
@@ -1050,6 +1050,45 @@ 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,
+       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 */
+       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
  *
index 1b962af7d8872e260efbd9c4e3dd29573ad60052..df753c445057d98737c5fc70e2d6d6fbe10558f4 100644 (file)
@@ -89,8 +89,12 @@ typedef struct
 
 
 /* date.c */
+extern int32 anytime_typmod_check(bool istz, int32 typmod);
 extern double date2timestamp_no_overflow(DateADT dateVal);
 extern void EncodeSpecialDate(DateADT dt, char *str);
+extern DateADT GetSQLCurrentDate(void);
+extern TimeTzADT *GetSQLCurrentTime(int32 typmod);
+extern TimeADT GetSQLLocalTime(int32 typmod);
 
 extern Datum date_in(PG_FUNCTION_ARGS);
 extern Datum date_out(PG_FUNCTION_ARGS);
index 85cc7ce1fe8cf8dc1253a7488dc67c74c41687d8..93b90fe3a053649e357686f584277ba03f187799 100644 (file)
@@ -215,7 +215,11 @@ extern Datum generate_series_timestamptz(PG_FUNCTION_ARGS);
 
 /* 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 bool TimestampDifferenceExceeds(TimestampTz start_time,
index 586ff1f329546094e659c11b73936196fb9db744..fec55e502fb8e0466e35a32fc8383bd1310394e2 100644 (file)
@@ -6494,6 +6494,9 @@ exec_simple_check_node(Node *node)
                                return TRUE;
                        }
 
+               case T_SQLValueFunction:
+                       return TRUE;
+
                case T_XmlExpr:
                        {
                                XmlExpr    *expr = (XmlExpr *) node;
index c15bf958a51732745cb95839bd1ebd6a4426dc90..abfee92f4de0402cb630d703f369ea83d79f0ae6 100644 (file)
@@ -182,7 +182,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle);
          Filter: (dlevel <= $0)
          InitPlan 1 (returns $0)
            ->  Index Scan using uaccount_pkey on uaccount
-                 Index Cond: (pguser = "current_user"())
+                 Index Cond: (pguser = CURRENT_USER)
 (7 rows)
 
 EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle);
@@ -198,7 +198,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dt
                      Filter: (dlevel <= $0)
                      InitPlan 1 (returns $0)
                        ->  Index Scan using uaccount_pkey on uaccount
-                             Index Cond: (pguser = "current_user"())
+                             Index Cond: (pguser = CURRENT_USER)
 (11 rows)
 
 -- only owner can change policies
@@ -265,22 +265,22 @@ NOTICE:  f_leak => great manga
 (3 rows)
 
 EXPLAIN (COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle);
-                  QUERY PLAN                  
-----------------------------------------------
+                QUERY PLAN                
+------------------------------------------
  Subquery Scan on document
    Filter: f_leak(document.dtitle)
    ->  Seq Scan on document document_1
-         Filter: (dauthor = "current_user"())
+         Filter: (dauthor = CURRENT_USER)
 (4 rows)
 
 EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle);
-                     QUERY PLAN                     
-----------------------------------------------------
+                    QUERY PLAN                    
+--------------------------------------------------
  Nested Loop
    ->  Subquery Scan on document
          Filter: f_leak(document.dtitle)
          ->  Seq Scan on document document_1
-               Filter: (dauthor = "current_user"())
+               Filter: (dauthor = CURRENT_USER)
    ->  Index Scan using category_pkey on category
          Index Cond: (cid = document.cid)
 (7 rows)
index c5ff3181a3e15237f98be819fcf4998a542c95e0..8157324fee1238e097a0c4b71f2a206ee711e860 100644 (file)
@@ -2269,14 +2269,14 @@ pg_settings|pg_settings_u|CREATE RULE pg_settings_u AS
    WHERE (new.name = old.name) DO  SELECT set_config(old.name, new.setting, false) AS set_config;
 rtest_emp|rtest_emp_del|CREATE RULE rtest_emp_del AS
     ON DELETE TO rtest_emp DO  INSERT INTO rtest_emplog (ename, who, action, newsal, oldsal)
-  VALUES (old.ename, "current_user"(), 'fired'::bpchar, '$0.00'::money, old.salary);
+  VALUES (old.ename, CURRENT_USER, 'fired'::bpchar, '$0.00'::money, old.salary);
 rtest_emp|rtest_emp_ins|CREATE RULE rtest_emp_ins AS
     ON INSERT TO rtest_emp DO  INSERT INTO rtest_emplog (ename, who, action, newsal, oldsal)
-  VALUES (new.ename, "current_user"(), 'hired'::bpchar, new.salary, '$0.00'::money);
+  VALUES (new.ename, CURRENT_USER, 'hired'::bpchar, new.salary, '$0.00'::money);
 rtest_emp|rtest_emp_upd|CREATE RULE rtest_emp_upd AS
     ON UPDATE TO rtest_emp
    WHERE (new.salary <> old.salary) DO  INSERT INTO rtest_emplog (ename, who, action, newsal, oldsal)
-  VALUES (new.ename, "current_user"(), 'honored'::bpchar, new.salary, old.salary);
+  VALUES (new.ename, CURRENT_USER, 'honored'::bpchar, new.salary, old.salary);
 rtest_nothn1|rtest_nothn_r1|CREATE RULE rtest_nothn_r1 AS
     ON INSERT TO rtest_nothn1
    WHERE ((new.a >= 10) AND (new.a < 20)) DO INSTEAD NOTHING;
index 7f575266c1bb0f668c1a8780a5dbe90df6463bb0..878035332bb94901e280407a8bea647cc6cb64bf 100644 (file)
@@ -1326,10 +1326,10 @@ NOTICE:  f_leak => hamburger
 (1 row)
 
 EXPLAIN (COSTS OFF) SELECT * FROM my_property_normal WHERE f_leak(passwd);
-                            QUERY PLAN                            
-------------------------------------------------------------------
+                          QUERY PLAN                          
+--------------------------------------------------------------
  Seq Scan on customer
-   Filter: (f_leak(passwd) AND (name = ("current_user"())::text))
+   Filter: (f_leak(passwd) AND (name = (CURRENT_USER)::text))
 (2 rows)
 
 SELECT * FROM my_property_secure WHERE f_leak(passwd);
@@ -1340,12 +1340,12 @@ NOTICE:  f_leak => passwd123
 (1 row)
 
 EXPLAIN (COSTS OFF) SELECT * FROM my_property_secure WHERE f_leak(passwd);
-                    QUERY PLAN                     
----------------------------------------------------
+                  QUERY PLAN                   
+-----------------------------------------------
  Subquery Scan on my_property_secure
    Filter: f_leak(my_property_secure.passwd)
    ->  Seq Scan on customer
-         Filter: (name = ("current_user"())::text)
+         Filter: (name = (CURRENT_USER)::text)
 (4 rows)
 
 --
@@ -1367,10 +1367,10 @@ NOTICE:  f_leak => hamburger
 
 EXPLAIN (COSTS OFF) SELECT * FROM my_property_normal v
                WHERE f_leak('passwd') AND f_leak(passwd);
-                                         QUERY PLAN                                          
----------------------------------------------------------------------------------------------
+                                       QUERY PLAN                                        
+-----------------------------------------------------------------------------------------
  Seq Scan on customer
-   Filter: (f_leak('passwd'::text) AND f_leak(passwd) AND (name = ("current_user"())::text))
+   Filter: (f_leak('passwd'::text) AND f_leak(passwd) AND (name = (CURRENT_USER)::text))
 (2 rows)
 
 SELECT * FROM my_property_secure v
@@ -1386,12 +1386,12 @@ NOTICE:  f_leak => passwd
 
 EXPLAIN (COSTS OFF) SELECT * FROM my_property_secure v
                WHERE f_leak('passwd') AND f_leak(passwd);
-                                   QUERY PLAN                                   
---------------------------------------------------------------------------------
+                                 QUERY PLAN                                 
+----------------------------------------------------------------------------
  Subquery Scan on v
    Filter: f_leak(v.passwd)
    ->  Seq Scan on customer
-         Filter: (f_leak('passwd'::text) AND (name = ("current_user"())::text))
+         Filter: (f_leak('passwd'::text) AND (name = (CURRENT_USER)::text))
 (4 rows)
 
 --
@@ -1409,15 +1409,15 @@ NOTICE:  f_leak => 9801-2345-6789-0123
 (1 row)
 
 EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_normal WHERE f_leak(cnum);
-                       QUERY PLAN                        
----------------------------------------------------------
+                     QUERY PLAN                      
+-----------------------------------------------------
  Hash Join
    Hash Cond: (r.cid = l.cid)
    ->  Seq Scan on credit_card r
          Filter: f_leak(cnum)
    ->  Hash
          ->  Seq Scan on customer l
-               Filter: (name = ("current_user"())::text)
+               Filter: (name = (CURRENT_USER)::text)
 (7 rows)
 
 SELECT * FROM my_credit_card_secure WHERE f_leak(cnum);
@@ -1428,8 +1428,8 @@ NOTICE:  f_leak => 1111-2222-3333-4444
 (1 row)
 
 EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_secure WHERE f_leak(cnum);
-                          QUERY PLAN                           
----------------------------------------------------------------
+                        QUERY PLAN                         
+-----------------------------------------------------------
  Subquery Scan on my_credit_card_secure
    Filter: f_leak(my_credit_card_secure.cnum)
    ->  Hash Join
@@ -1437,7 +1437,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_secure WHERE f_leak(cnum);
          ->  Seq Scan on credit_card r
          ->  Hash
                ->  Seq Scan on customer l
-                     Filter: (name = ("current_user"())::text)
+                     Filter: (name = (CURRENT_USER)::text)
 (8 rows)
 
 --
@@ -1471,7 +1471,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_normal
                      ->  Seq Scan on credit_card r_1
                      ->  Hash
                            ->  Seq Scan on customer l_1
-                                 Filter: (name = ("current_user"())::text)
+                                 Filter: (name = (CURRENT_USER)::text)
 (13 rows)
 
 SELECT * FROM my_credit_card_usage_secure
@@ -1502,7 +1502,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_secure
                      ->  Seq Scan on credit_card r_1
                      ->  Hash
                            ->  Seq Scan on customer l
-                                 Filter: (name = ("current_user"())::text)
+                                 Filter: (name = (CURRENT_USER)::text)
 (13 rows)
 
 --
index 5275ef0b2ded731d3eddfd6f2c47e31bb6116337..1a05c6ccbd5e05e9103cd7fd04e7473b6c0f2389 100644 (file)
@@ -1326,10 +1326,10 @@ NOTICE:  f_leak => hamburger
 (1 row)
 
 EXPLAIN (COSTS OFF) SELECT * FROM my_property_normal WHERE f_leak(passwd);
-                            QUERY PLAN                            
-------------------------------------------------------------------
+                          QUERY PLAN                          
+--------------------------------------------------------------
  Seq Scan on customer
-   Filter: (f_leak(passwd) AND (name = ("current_user"())::text))
+   Filter: (f_leak(passwd) AND (name = (CURRENT_USER)::text))
 (2 rows)
 
 SELECT * FROM my_property_secure WHERE f_leak(passwd);
@@ -1340,12 +1340,12 @@ NOTICE:  f_leak => passwd123
 (1 row)
 
 EXPLAIN (COSTS OFF) SELECT * FROM my_property_secure WHERE f_leak(passwd);
-                    QUERY PLAN                     
----------------------------------------------------
+                  QUERY PLAN                   
+-----------------------------------------------
  Subquery Scan on my_property_secure
    Filter: f_leak(my_property_secure.passwd)
    ->  Seq Scan on customer
-         Filter: (name = ("current_user"())::text)
+         Filter: (name = (CURRENT_USER)::text)
 (4 rows)
 
 --
@@ -1367,10 +1367,10 @@ NOTICE:  f_leak => hamburger
 
 EXPLAIN (COSTS OFF) SELECT * FROM my_property_normal v
                WHERE f_leak('passwd') AND f_leak(passwd);
-                                         QUERY PLAN                                          
----------------------------------------------------------------------------------------------
+                                       QUERY PLAN                                        
+-----------------------------------------------------------------------------------------
  Seq Scan on customer
-   Filter: (f_leak('passwd'::text) AND f_leak(passwd) AND (name = ("current_user"())::text))
+   Filter: (f_leak('passwd'::text) AND f_leak(passwd) AND (name = (CURRENT_USER)::text))
 (2 rows)
 
 SELECT * FROM my_property_secure v
@@ -1386,12 +1386,12 @@ NOTICE:  f_leak => passwd
 
 EXPLAIN (COSTS OFF) SELECT * FROM my_property_secure v
                WHERE f_leak('passwd') AND f_leak(passwd);
-                                   QUERY PLAN                                   
---------------------------------------------------------------------------------
+                                 QUERY PLAN                                 
+----------------------------------------------------------------------------
  Subquery Scan on v
    Filter: f_leak(v.passwd)
    ->  Seq Scan on customer
-         Filter: (f_leak('passwd'::text) AND (name = ("current_user"())::text))
+         Filter: (f_leak('passwd'::text) AND (name = (CURRENT_USER)::text))
 (4 rows)
 
 --
@@ -1409,15 +1409,15 @@ NOTICE:  f_leak => 9801-2345-6789-0123
 (1 row)
 
 EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_normal WHERE f_leak(cnum);
-                       QUERY PLAN                        
----------------------------------------------------------
+                     QUERY PLAN                      
+-----------------------------------------------------
  Hash Join
    Hash Cond: (r.cid = l.cid)
    ->  Seq Scan on credit_card r
          Filter: f_leak(cnum)
    ->  Hash
          ->  Seq Scan on customer l
-               Filter: (name = ("current_user"())::text)
+               Filter: (name = (CURRENT_USER)::text)
 (7 rows)
 
 SELECT * FROM my_credit_card_secure WHERE f_leak(cnum);
@@ -1428,8 +1428,8 @@ NOTICE:  f_leak => 1111-2222-3333-4444
 (1 row)
 
 EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_secure WHERE f_leak(cnum);
-                          QUERY PLAN                           
----------------------------------------------------------------
+                        QUERY PLAN                         
+-----------------------------------------------------------
  Subquery Scan on my_credit_card_secure
    Filter: f_leak(my_credit_card_secure.cnum)
    ->  Hash Join
@@ -1437,7 +1437,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_secure WHERE f_leak(cnum);
          ->  Seq Scan on credit_card r
          ->  Hash
                ->  Seq Scan on customer l
-                     Filter: (name = ("current_user"())::text)
+                     Filter: (name = (CURRENT_USER)::text)
 (8 rows)
 
 --
@@ -1471,7 +1471,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_normal
                      ->  Seq Scan on credit_card r_1
                      ->  Hash
                            ->  Seq Scan on customer l_1
-                                 Filter: (name = ("current_user"())::text)
+                                 Filter: (name = (CURRENT_USER)::text)
 (13 rows)
 
 SELECT * FROM my_credit_card_usage_secure
@@ -1502,7 +1502,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_secure
                      ->  Seq Scan on credit_card r_1
                      ->  Hash
                            ->  Seq Scan on customer l
-                                 Filter: (name = ("current_user"())::text)
+                                 Filter: (name = (CURRENT_USER)::text)
 (13 rows)
 
 --