Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 0bb51aa

Browse files
committed
Improve parsetree representation of special functions such as CURRENT_DATE.
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>
1 parent 4bc4cfe commit 0bb51aa

File tree

24 files changed

+626
-168
lines changed

24 files changed

+626
-168
lines changed

contrib/pg_stat_statements/pg_stat_statements.c

+9
Original file line numberDiff line numberDiff line change
@@ -2632,6 +2632,15 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
26322632
JumbleExpr(jstate, (Node *) mmexpr->args);
26332633
}
26342634
break;
2635+
case T_SQLValueFunction:
2636+
{
2637+
SQLValueFunction *svf = (SQLValueFunction *) node;
2638+
2639+
APP_JUMB(svf->op);
2640+
/* type is fully determined by op */
2641+
APP_JUMB(svf->typmod);
2642+
}
2643+
break;
26352644
case T_XmlExpr:
26362645
{
26372646
XmlExpr *xexpr = (XmlExpr *) node;

src/backend/executor/execQual.c

+78
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,10 @@
5353
#include "pgstat.h"
5454
#include "utils/acl.h"
5555
#include "utils/builtins.h"
56+
#include "utils/date.h"
5657
#include "utils/lsyscache.h"
5758
#include "utils/memutils.h"
59+
#include "utils/timestamp.h"
5860
#include "utils/typcache.h"
5961
#include "utils/xml.h"
6062

@@ -147,6 +149,9 @@ static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr,
147149
static Datum ExecEvalMinMax(MinMaxExprState *minmaxExpr,
148150
ExprContext *econtext,
149151
bool *isNull, ExprDoneCond *isDone);
152+
static Datum ExecEvalSQLValueFunction(ExprState *svfExpr,
153+
ExprContext *econtext,
154+
bool *isNull, ExprDoneCond *isDone);
150155
static Datum ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
151156
bool *isNull, ExprDoneCond *isDone);
152157
static Datum ExecEvalNullIf(FuncExprState *nullIfExpr,
@@ -3530,6 +3535,75 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
35303535
return result;
35313536
}
35323537

3538+
/* ----------------------------------------------------------------
3539+
* ExecEvalSQLValueFunction
3540+
* ----------------------------------------------------------------
3541+
*/
3542+
static Datum
3543+
ExecEvalSQLValueFunction(ExprState *svfExpr,
3544+
ExprContext *econtext,
3545+
bool *isNull, ExprDoneCond *isDone)
3546+
{
3547+
Datum result = (Datum) 0;
3548+
SQLValueFunction *svf = (SQLValueFunction *) svfExpr->expr;
3549+
FunctionCallInfoData fcinfo;
3550+
3551+
if (isDone)
3552+
*isDone = ExprSingleResult;
3553+
*isNull = false;
3554+
3555+
/*
3556+
* Note: current_schema() can return NULL. current_user() etc currently
3557+
* cannot, but might as well code those cases the same way for safety.
3558+
*/
3559+
switch (svf->op)
3560+
{
3561+
case SVFOP_CURRENT_DATE:
3562+
result = DateADTGetDatum(GetSQLCurrentDate());
3563+
break;
3564+
case SVFOP_CURRENT_TIME:
3565+
case SVFOP_CURRENT_TIME_N:
3566+
result = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod));
3567+
break;
3568+
case SVFOP_CURRENT_TIMESTAMP:
3569+
case SVFOP_CURRENT_TIMESTAMP_N:
3570+
result = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod));
3571+
break;
3572+
case SVFOP_LOCALTIME:
3573+
case SVFOP_LOCALTIME_N:
3574+
result = TimeADTGetDatum(GetSQLLocalTime(svf->typmod));
3575+
break;
3576+
case SVFOP_LOCALTIMESTAMP:
3577+
case SVFOP_LOCALTIMESTAMP_N:
3578+
result = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
3579+
break;
3580+
case SVFOP_CURRENT_ROLE:
3581+
case SVFOP_CURRENT_USER:
3582+
case SVFOP_USER:
3583+
InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
3584+
result = current_user(&fcinfo);
3585+
*isNull = fcinfo.isnull;
3586+
break;
3587+
case SVFOP_SESSION_USER:
3588+
InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
3589+
result = session_user(&fcinfo);
3590+
*isNull = fcinfo.isnull;
3591+
break;
3592+
case SVFOP_CURRENT_CATALOG:
3593+
InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
3594+
result = current_database(&fcinfo);
3595+
*isNull = fcinfo.isnull;
3596+
break;
3597+
case SVFOP_CURRENT_SCHEMA:
3598+
InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
3599+
result = current_schema(&fcinfo);
3600+
*isNull = fcinfo.isnull;
3601+
break;
3602+
}
3603+
3604+
return result;
3605+
}
3606+
35333607
/* ----------------------------------------------------------------
35343608
* ExecEvalXml
35353609
* ----------------------------------------------------------------
@@ -5086,6 +5160,10 @@ ExecInitExpr(Expr *node, PlanState *parent)
50865160
state = (ExprState *) mstate;
50875161
}
50885162
break;
5163+
case T_SQLValueFunction:
5164+
state = (ExprState *) makeNode(ExprState);
5165+
state->evalfunc = ExecEvalSQLValueFunction;
5166+
break;
50895167
case T_XmlExpr:
50905168
{
50915169
XmlExpr *xexpr = (XmlExpr *) node;

src/backend/nodes/copyfuncs.c

+19
Original file line numberDiff line numberDiff line change
@@ -1752,6 +1752,22 @@ _copyMinMaxExpr(const MinMaxExpr *from)
17521752
return newnode;
17531753
}
17541754

1755+
/*
1756+
* _copySQLValueFunction
1757+
*/
1758+
static SQLValueFunction *
1759+
_copySQLValueFunction(const SQLValueFunction *from)
1760+
{
1761+
SQLValueFunction *newnode = makeNode(SQLValueFunction);
1762+
1763+
COPY_SCALAR_FIELD(op);
1764+
COPY_SCALAR_FIELD(type);
1765+
COPY_SCALAR_FIELD(typmod);
1766+
COPY_LOCATION_FIELD(location);
1767+
1768+
return newnode;
1769+
}
1770+
17551771
/*
17561772
* _copyXmlExpr
17571773
*/
@@ -4525,6 +4541,9 @@ copyObject(const void *from)
45254541
case T_MinMaxExpr:
45264542
retval = _copyMinMaxExpr(from);
45274543
break;
4544+
case T_SQLValueFunction:
4545+
retval = _copySQLValueFunction(from);
4546+
break;
45284547
case T_XmlExpr:
45294548
retval = _copyXmlExpr(from);
45304549
break;

src/backend/nodes/equalfuncs.c

+14
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,17 @@ _equalMinMaxExpr(const MinMaxExpr *a, const MinMaxExpr *b)
619619
return true;
620620
}
621621

622+
static bool
623+
_equalSQLValueFunction(const SQLValueFunction *a, const SQLValueFunction *b)
624+
{
625+
COMPARE_SCALAR_FIELD(op);
626+
COMPARE_SCALAR_FIELD(type);
627+
COMPARE_SCALAR_FIELD(typmod);
628+
COMPARE_LOCATION_FIELD(location);
629+
630+
return true;
631+
}
632+
622633
static bool
623634
_equalXmlExpr(const XmlExpr *a, const XmlExpr *b)
624635
{
@@ -2842,6 +2853,9 @@ equal(const void *a, const void *b)
28422853
case T_MinMaxExpr:
28432854
retval = _equalMinMaxExpr(a, b);
28442855
break;
2856+
case T_SQLValueFunction:
2857+
retval = _equalSQLValueFunction(a, b);
2858+
break;
28452859
case T_XmlExpr:
28462860
retval = _equalXmlExpr(a, b);
28472861
break;

src/backend/nodes/nodeFuncs.c

+24-3
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,9 @@ exprType(const Node *expr)
218218
case T_MinMaxExpr:
219219
type = ((const MinMaxExpr *) expr)->minmaxtype;
220220
break;
221+
case T_SQLValueFunction:
222+
type = ((const SQLValueFunction *) expr)->type;
223+
break;
221224
case T_XmlExpr:
222225
if (((const XmlExpr *) expr)->op == IS_DOCUMENT)
223226
type = BOOLOID;
@@ -479,6 +482,8 @@ exprTypmod(const Node *expr)
479482
return typmod;
480483
}
481484
break;
485+
case T_SQLValueFunction:
486+
return ((const SQLValueFunction *) expr)->typmod;
482487
case T_CoerceToDomain:
483488
return ((const CoerceToDomain *) expr)->resulttypmod;
484489
case T_CoerceToDomainValue:
@@ -718,6 +723,8 @@ expression_returns_set_walker(Node *node, void *context)
718723
return false;
719724
if (IsA(node, MinMaxExpr))
720725
return false;
726+
if (IsA(node, SQLValueFunction))
727+
return false;
721728
if (IsA(node, XmlExpr))
722729
return false;
723730

@@ -883,6 +890,9 @@ exprCollation(const Node *expr)
883890
case T_MinMaxExpr:
884891
coll = ((const MinMaxExpr *) expr)->minmaxcollid;
885892
break;
893+
case T_SQLValueFunction:
894+
coll = InvalidOid; /* all cases return non-collatable types */
895+
break;
886896
case T_XmlExpr:
887897

888898
/*
@@ -1091,6 +1101,9 @@ exprSetCollation(Node *expr, Oid collation)
10911101
case T_MinMaxExpr:
10921102
((MinMaxExpr *) expr)->minmaxcollid = collation;
10931103
break;
1104+
case T_SQLValueFunction:
1105+
Assert(!OidIsValid(collation)); /* no collatable results */
1106+
break;
10941107
case T_XmlExpr:
10951108
Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ?
10961109
(collation == DEFAULT_COLLATION_OID) :
@@ -1364,6 +1377,10 @@ exprLocation(const Node *expr)
13641377
/* GREATEST/LEAST keyword should always be the first thing */
13651378
loc = ((const MinMaxExpr *) expr)->location;
13661379
break;
1380+
case T_SQLValueFunction:
1381+
/* function keyword should always be the first thing */
1382+
loc = ((const SQLValueFunction *) expr)->location;
1383+
break;
13671384
case T_XmlExpr:
13681385
{
13691386
const XmlExpr *xexpr = (const XmlExpr *) expr;
@@ -1633,9 +1650,10 @@ set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
16331650
* for themselves, in case additional checks should be made, or because they
16341651
* have special rules about which parts of the tree need to be visited.
16351652
*
1636-
* Note: we ignore MinMaxExpr, XmlExpr, and CoerceToDomain nodes, because they
1637-
* do not contain SQL function OIDs. However, they can invoke SQL-visible
1638-
* functions, so callers should take thought about how to treat them.
1653+
* Note: we ignore MinMaxExpr, SQLValueFunction, XmlExpr, and CoerceToDomain
1654+
* nodes, because they do not contain SQL function OIDs. However, they can
1655+
* invoke SQL-visible functions, so callers should take thought about how to
1656+
* treat them.
16391657
*/
16401658
bool
16411659
check_functions_in_node(Node *node, check_function_callback checker,
@@ -1859,6 +1877,7 @@ expression_tree_walker(Node *node,
18591877
case T_CaseTestExpr:
18601878
case T_SetToDefault:
18611879
case T_CurrentOfExpr:
1880+
case T_SQLValueFunction:
18621881
case T_RangeTblRef:
18631882
case T_SortGroupClause:
18641883
/* primitive node types with no expression subnodes */
@@ -2433,6 +2452,7 @@ expression_tree_mutator(Node *node,
24332452
case T_CaseTestExpr:
24342453
case T_SetToDefault:
24352454
case T_CurrentOfExpr:
2455+
case T_SQLValueFunction:
24362456
case T_RangeTblRef:
24372457
case T_SortGroupClause:
24382458
return (Node *) copyObject(node);
@@ -3197,6 +3217,7 @@ raw_expression_tree_walker(Node *node,
31973217
{
31983218
case T_SetToDefault:
31993219
case T_CurrentOfExpr:
3220+
case T_SQLValueFunction:
32003221
case T_Integer:
32013222
case T_Float:
32023223
case T_String:

src/backend/nodes/outfuncs.c

+14
Original file line numberDiff line numberDiff line change
@@ -1423,6 +1423,17 @@ _outMinMaxExpr(StringInfo str, const MinMaxExpr *node)
14231423
WRITE_LOCATION_FIELD(location);
14241424
}
14251425

1426+
static void
1427+
_outSQLValueFunction(StringInfo str, const SQLValueFunction *node)
1428+
{
1429+
WRITE_NODE_TYPE("SQLVALUEFUNCTION");
1430+
1431+
WRITE_ENUM_FIELD(op, SQLValueFunctionOp);
1432+
WRITE_OID_FIELD(type);
1433+
WRITE_INT_FIELD(typmod);
1434+
WRITE_LOCATION_FIELD(location);
1435+
}
1436+
14261437
static void
14271438
_outXmlExpr(StringInfo str, const XmlExpr *node)
14281439
{
@@ -3522,6 +3533,9 @@ outNode(StringInfo str, const void *obj)
35223533
case T_MinMaxExpr:
35233534
_outMinMaxExpr(str, obj);
35243535
break;
3536+
case T_SQLValueFunction:
3537+
_outSQLValueFunction(str, obj);
3538+
break;
35253539
case T_XmlExpr:
35263540
_outXmlExpr(str, obj);
35273541
break;

src/backend/nodes/readfuncs.c

+18
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,22 @@ _readMinMaxExpr(void)
10411041
READ_DONE();
10421042
}
10431043

1044+
/*
1045+
* _readSQLValueFunction
1046+
*/
1047+
static SQLValueFunction *
1048+
_readSQLValueFunction(void)
1049+
{
1050+
READ_LOCALS(SQLValueFunction);
1051+
1052+
READ_ENUM_FIELD(op, SQLValueFunctionOp);
1053+
READ_OID_FIELD(type);
1054+
READ_INT_FIELD(typmod);
1055+
READ_LOCATION_FIELD(location);
1056+
1057+
READ_DONE();
1058+
}
1059+
10441060
/*
10451061
* _readXmlExpr
10461062
*/
@@ -2348,6 +2364,8 @@ parseNodeString(void)
23482364
return_value = _readCoalesceExpr();
23492365
else if (MATCH("MINMAX", 6))
23502366
return_value = _readMinMaxExpr();
2367+
else if (MATCH("SQLVALUEFUNCTION", 16))
2368+
return_value = _readSQLValueFunction();
23512369
else if (MATCH("XMLEXPR", 7))
23522370
return_value = _readXmlExpr();
23532371
else if (MATCH("NULLTEST", 8))

src/backend/optimizer/util/clauses.c

+13-3
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,12 @@ contain_mutable_functions_walker(Node *node, void *context)
962962
context))
963963
return true;
964964

965+
if (IsA(node, SQLValueFunction))
966+
{
967+
/* all variants of SQLValueFunction are stable */
968+
return true;
969+
}
970+
965971
/*
966972
* It should be safe to treat MinMaxExpr as immutable, because it will
967973
* depend on a non-cross-type btree comparison function, and those should
@@ -1031,7 +1037,8 @@ contain_volatile_functions_walker(Node *node, void *context)
10311037

10321038
/*
10331039
* See notes in contain_mutable_functions_walker about why we treat
1034-
* MinMaxExpr, XmlExpr, and CoerceToDomain as immutable.
1040+
* MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
1041+
* SQLValueFunction is stable. Hence, none of them are of interest here.
10351042
*/
10361043

10371044
/* Recurse to check arguments */
@@ -1076,7 +1083,8 @@ contain_volatile_functions_not_nextval_walker(Node *node, void *context)
10761083

10771084
/*
10781085
* See notes in contain_mutable_functions_walker about why we treat
1079-
* MinMaxExpr, XmlExpr, and CoerceToDomain as immutable.
1086+
* MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
1087+
* SQLValueFunction is stable. Hence, none of them are of interest here.
10801088
*/
10811089

10821090
/* Recurse to check arguments */
@@ -1143,7 +1151,8 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context)
11431151
* (Note: in principle that's wrong because a domain constraint could
11441152
* contain a parallel-unsafe function; but useful constraints probably
11451153
* never would have such, and assuming they do would cripple use of
1146-
* parallel query in the presence of domain types.)
1154+
* parallel query in the presence of domain types.) SQLValueFunction
1155+
* should be safe in all cases.
11471156
*/
11481157
if (IsA(node, CoerceToDomain))
11491158
{
@@ -1458,6 +1467,7 @@ contain_leaked_vars_walker(Node *node, void *context)
14581467
case T_CaseTestExpr:
14591468
case T_RowExpr:
14601469
case T_MinMaxExpr:
1470+
case T_SQLValueFunction:
14611471
case T_NullTest:
14621472
case T_BooleanTest:
14631473
case T_List:

0 commit comments

Comments
 (0)