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

Lines changed: 9 additions & 0 deletions
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

Lines changed: 78 additions & 0 deletions
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

Lines changed: 19 additions & 0 deletions
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

Lines changed: 14 additions & 0 deletions
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

Lines changed: 24 additions & 3 deletions
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

Lines changed: 14 additions & 0 deletions
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

Lines changed: 18 additions & 0 deletions
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

Lines changed: 13 additions & 3 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy