mirror of
https://github.com/postgres/postgres.git
synced 2025-04-20 00:42:27 +03:00
Add back SQLValueFunction for SQL keywords
This is equivalent to a revert of f193883 and fb32748, with the addition that the declaration of the SQLValueFunction node needs to gain a couple of node_attr for query jumbling. The performance impact of removing the function call inlining is proving to be too huge for some workloads where these are used. A worst-case test case of involving only simple SELECT queries with a SQL keyword is proving to lead to a reduction of 10% in TPS via pgbench and prepared queries on a high-end machine. None of the tests I ran back for this set of changes saw such a huge gap, but Alexander Lakhin and Andres Freund have found that this can be noticeable. Keeping the older performance would mean to do more inlining in the executor when using COERCE_SQL_SYNTAX for a function expression, similarly to what SQLValueFunction does. This requires more redesign work and there is little time until 16beta1 is released, so for now reverting the change is the best way forward, bringing back the previous performance. Bump catalog version. Reported-by: Alexander Lakhin Discussion: https://postgr.es/m/b32bed1b-0746-9b20-1472-4bdc9ca66d52@gmail.com
This commit is contained in:
parent
1d369c9e90
commit
d8c3106bb6
@ -601,32 +601,6 @@ LANGUAGE internal
|
|||||||
STRICT IMMUTABLE PARALLEL SAFE
|
STRICT IMMUTABLE PARALLEL SAFE
|
||||||
AS 'unicode_is_normalized';
|
AS 'unicode_is_normalized';
|
||||||
|
|
||||||
-- Functions with SQL-mandated special syntax and some defaults.
|
|
||||||
CREATE OR REPLACE FUNCTION
|
|
||||||
"current_time"(int4 DEFAULT NULL)
|
|
||||||
RETURNS timetz
|
|
||||||
LANGUAGE internal
|
|
||||||
STABLE PARALLEL SAFE
|
|
||||||
AS 'current_time';
|
|
||||||
CREATE OR REPLACE FUNCTION
|
|
||||||
"current_timestamp"(int4 DEFAULT NULL)
|
|
||||||
RETURNS timestamptz
|
|
||||||
LANGUAGE internal
|
|
||||||
STABLE PARALLEL SAFE
|
|
||||||
AS 'current_timestamp';
|
|
||||||
CREATE OR REPLACE FUNCTION
|
|
||||||
"localtime"(int4 DEFAULT NULL)
|
|
||||||
RETURNS time
|
|
||||||
LANGUAGE internal
|
|
||||||
STABLE PARALLEL SAFE
|
|
||||||
AS 'sql_localtime';
|
|
||||||
CREATE OR REPLACE FUNCTION
|
|
||||||
"localtimestamp"(int4 DEFAULT NULL)
|
|
||||||
RETURNS timestamp
|
|
||||||
LANGUAGE internal
|
|
||||||
STABLE PARALLEL SAFE
|
|
||||||
AS 'sql_localtimestamp';
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- The default permissions for functions mean that anyone can execute them.
|
-- The default permissions for functions mean that anyone can execute them.
|
||||||
-- A number of functions shouldn't be executable by just anyone, but rather
|
-- A number of functions shouldn't be executable by just anyone, but rather
|
||||||
|
@ -2213,6 +2213,17 @@ ExecInitExprRec(Expr *node, ExprState *state,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case T_SQLValueFunction:
|
||||||
|
{
|
||||||
|
SQLValueFunction *svf = (SQLValueFunction *) node;
|
||||||
|
|
||||||
|
scratch.opcode = EEOP_SQLVALUEFUNCTION;
|
||||||
|
scratch.d.sqlvaluefunction.svf = svf;
|
||||||
|
|
||||||
|
ExprEvalPushStep(state, &scratch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case T_XmlExpr:
|
case T_XmlExpr:
|
||||||
{
|
{
|
||||||
XmlExpr *xexpr = (XmlExpr *) node;
|
XmlExpr *xexpr = (XmlExpr *) node;
|
||||||
|
@ -455,6 +455,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
&&CASE_EEOP_DISTINCT,
|
&&CASE_EEOP_DISTINCT,
|
||||||
&&CASE_EEOP_NOT_DISTINCT,
|
&&CASE_EEOP_NOT_DISTINCT,
|
||||||
&&CASE_EEOP_NULLIF,
|
&&CASE_EEOP_NULLIF,
|
||||||
|
&&CASE_EEOP_SQLVALUEFUNCTION,
|
||||||
&&CASE_EEOP_CURRENTOFEXPR,
|
&&CASE_EEOP_CURRENTOFEXPR,
|
||||||
&&CASE_EEOP_NEXTVALUEEXPR,
|
&&CASE_EEOP_NEXTVALUEEXPR,
|
||||||
&&CASE_EEOP_ARRAYEXPR,
|
&&CASE_EEOP_ARRAYEXPR,
|
||||||
@ -1305,6 +1306,17 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
|
|||||||
EEO_NEXT();
|
EEO_NEXT();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EEO_CASE(EEOP_SQLVALUEFUNCTION)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Doesn't seem worthwhile to have an inline implementation
|
||||||
|
* efficiency-wise.
|
||||||
|
*/
|
||||||
|
ExecEvalSQLValueFunction(state, op);
|
||||||
|
|
||||||
|
EEO_NEXT();
|
||||||
|
}
|
||||||
|
|
||||||
EEO_CASE(EEOP_CURRENTOFEXPR)
|
EEO_CASE(EEOP_CURRENTOFEXPR)
|
||||||
{
|
{
|
||||||
/* error invocation uses space, and shouldn't ever occur */
|
/* error invocation uses space, and shouldn't ever occur */
|
||||||
@ -2497,6 +2509,67 @@ ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
|
|||||||
errmsg("no value found for parameter %d", paramId)));
|
errmsg("no value found for parameter %d", paramId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Evaluate a SQLValueFunction expression.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
|
||||||
|
{
|
||||||
|
LOCAL_FCINFO(fcinfo, 0);
|
||||||
|
SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
|
||||||
|
|
||||||
|
*op->resnull = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: current_schema() can return NULL. current_user() etc currently
|
||||||
|
* cannot, but might as well code those cases the same way for safety.
|
||||||
|
*/
|
||||||
|
switch (svf->op)
|
||||||
|
{
|
||||||
|
case SVFOP_CURRENT_DATE:
|
||||||
|
*op->resvalue = DateADTGetDatum(GetSQLCurrentDate());
|
||||||
|
break;
|
||||||
|
case SVFOP_CURRENT_TIME:
|
||||||
|
case SVFOP_CURRENT_TIME_N:
|
||||||
|
*op->resvalue = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod));
|
||||||
|
break;
|
||||||
|
case SVFOP_CURRENT_TIMESTAMP:
|
||||||
|
case SVFOP_CURRENT_TIMESTAMP_N:
|
||||||
|
*op->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod));
|
||||||
|
break;
|
||||||
|
case SVFOP_LOCALTIME:
|
||||||
|
case SVFOP_LOCALTIME_N:
|
||||||
|
*op->resvalue = TimeADTGetDatum(GetSQLLocalTime(svf->typmod));
|
||||||
|
break;
|
||||||
|
case SVFOP_LOCALTIMESTAMP:
|
||||||
|
case SVFOP_LOCALTIMESTAMP_N:
|
||||||
|
*op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
|
||||||
|
break;
|
||||||
|
case SVFOP_CURRENT_ROLE:
|
||||||
|
case SVFOP_CURRENT_USER:
|
||||||
|
case SVFOP_USER:
|
||||||
|
InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
|
||||||
|
*op->resvalue = current_user(fcinfo);
|
||||||
|
*op->resnull = fcinfo->isnull;
|
||||||
|
break;
|
||||||
|
case SVFOP_SESSION_USER:
|
||||||
|
InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
|
||||||
|
*op->resvalue = session_user(fcinfo);
|
||||||
|
*op->resnull = fcinfo->isnull;
|
||||||
|
break;
|
||||||
|
case SVFOP_CURRENT_CATALOG:
|
||||||
|
InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
|
||||||
|
*op->resvalue = current_database(fcinfo);
|
||||||
|
*op->resnull = fcinfo->isnull;
|
||||||
|
break;
|
||||||
|
case SVFOP_CURRENT_SCHEMA:
|
||||||
|
InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
|
||||||
|
*op->resvalue = current_schema(fcinfo);
|
||||||
|
*op->resnull = fcinfo->isnull;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Raise error if a CURRENT OF expression is evaluated.
|
* Raise error if a CURRENT OF expression is evaluated.
|
||||||
*
|
*
|
||||||
|
@ -1549,6 +1549,12 @@ llvm_compile_expr(ExprState *state)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case EEOP_SQLVALUEFUNCTION:
|
||||||
|
build_EvalXFunc(b, mod, "ExecEvalSQLValueFunction",
|
||||||
|
v_state, op);
|
||||||
|
LLVMBuildBr(b, opblocks[opno + 1]);
|
||||||
|
break;
|
||||||
|
|
||||||
case EEOP_CURRENTOFEXPR:
|
case EEOP_CURRENTOFEXPR:
|
||||||
build_EvalXFunc(b, mod, "ExecEvalCurrentOfExpr",
|
build_EvalXFunc(b, mod, "ExecEvalCurrentOfExpr",
|
||||||
v_state, op);
|
v_state, op);
|
||||||
|
@ -126,6 +126,7 @@ void *referenced_functions[] =
|
|||||||
ExecEvalRow,
|
ExecEvalRow,
|
||||||
ExecEvalRowNotNull,
|
ExecEvalRowNotNull,
|
||||||
ExecEvalRowNull,
|
ExecEvalRowNull,
|
||||||
|
ExecEvalSQLValueFunction,
|
||||||
ExecEvalScalarArrayOp,
|
ExecEvalScalarArrayOp,
|
||||||
ExecEvalHashedScalarArrayOp,
|
ExecEvalHashedScalarArrayOp,
|
||||||
ExecEvalSubPlan,
|
ExecEvalSubPlan,
|
||||||
|
@ -210,6 +210,9 @@ exprType(const Node *expr)
|
|||||||
case T_MinMaxExpr:
|
case T_MinMaxExpr:
|
||||||
type = ((const MinMaxExpr *) expr)->minmaxtype;
|
type = ((const MinMaxExpr *) expr)->minmaxtype;
|
||||||
break;
|
break;
|
||||||
|
case T_SQLValueFunction:
|
||||||
|
type = ((const SQLValueFunction *) expr)->type;
|
||||||
|
break;
|
||||||
case T_XmlExpr:
|
case T_XmlExpr:
|
||||||
if (((const XmlExpr *) expr)->op == IS_DOCUMENT)
|
if (((const XmlExpr *) expr)->op == IS_DOCUMENT)
|
||||||
type = BOOLOID;
|
type = BOOLOID;
|
||||||
@ -486,6 +489,8 @@ exprTypmod(const Node *expr)
|
|||||||
return typmod;
|
return typmod;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case T_SQLValueFunction:
|
||||||
|
return ((const SQLValueFunction *) expr)->typmod;
|
||||||
case T_JsonValueExpr:
|
case T_JsonValueExpr:
|
||||||
return exprTypmod((Node *) ((const JsonValueExpr *) expr)->formatted_expr);
|
return exprTypmod((Node *) ((const JsonValueExpr *) expr)->formatted_expr);
|
||||||
case T_JsonConstructorExpr:
|
case T_JsonConstructorExpr:
|
||||||
@ -930,6 +935,13 @@ exprCollation(const Node *expr)
|
|||||||
case T_MinMaxExpr:
|
case T_MinMaxExpr:
|
||||||
coll = ((const MinMaxExpr *) expr)->minmaxcollid;
|
coll = ((const MinMaxExpr *) expr)->minmaxcollid;
|
||||||
break;
|
break;
|
||||||
|
case T_SQLValueFunction:
|
||||||
|
/* Returns either NAME or a non-collatable type */
|
||||||
|
if (((const SQLValueFunction *) expr)->type == NAMEOID)
|
||||||
|
coll = C_COLLATION_OID;
|
||||||
|
else
|
||||||
|
coll = InvalidOid;
|
||||||
|
break;
|
||||||
case T_XmlExpr:
|
case T_XmlExpr:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1167,6 +1179,11 @@ exprSetCollation(Node *expr, Oid collation)
|
|||||||
case T_MinMaxExpr:
|
case T_MinMaxExpr:
|
||||||
((MinMaxExpr *) expr)->minmaxcollid = collation;
|
((MinMaxExpr *) expr)->minmaxcollid = collation;
|
||||||
break;
|
break;
|
||||||
|
case T_SQLValueFunction:
|
||||||
|
Assert((((SQLValueFunction *) expr)->type == NAMEOID) ?
|
||||||
|
(collation == C_COLLATION_OID) :
|
||||||
|
(collation == InvalidOid));
|
||||||
|
break;
|
||||||
case T_XmlExpr:
|
case T_XmlExpr:
|
||||||
Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ?
|
Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ?
|
||||||
(collation == DEFAULT_COLLATION_OID) :
|
(collation == DEFAULT_COLLATION_OID) :
|
||||||
@ -1468,6 +1485,10 @@ exprLocation(const Node *expr)
|
|||||||
/* GREATEST/LEAST keyword should always be the first thing */
|
/* GREATEST/LEAST keyword should always be the first thing */
|
||||||
loc = ((const MinMaxExpr *) expr)->location;
|
loc = ((const MinMaxExpr *) expr)->location;
|
||||||
break;
|
break;
|
||||||
|
case T_SQLValueFunction:
|
||||||
|
/* function keyword should always be the first thing */
|
||||||
|
loc = ((const SQLValueFunction *) expr)->location;
|
||||||
|
break;
|
||||||
case T_XmlExpr:
|
case T_XmlExpr:
|
||||||
{
|
{
|
||||||
const XmlExpr *xexpr = (const XmlExpr *) expr;
|
const XmlExpr *xexpr = (const XmlExpr *) expr;
|
||||||
@ -1789,10 +1810,10 @@ set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
|
|||||||
* for themselves, in case additional checks should be made, or because they
|
* 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.
|
* have special rules about which parts of the tree need to be visited.
|
||||||
*
|
*
|
||||||
* Note: we ignore MinMaxExpr, XmlExpr, CoerceToDomain, and NextValueExpr
|
* Note: we ignore MinMaxExpr, SQLValueFunction, XmlExpr, CoerceToDomain,
|
||||||
* nodes, because they do not contain SQL function OIDs. However, they can
|
* and NextValueExpr nodes, because they do not contain SQL function OIDs.
|
||||||
* invoke SQL-visible functions, so callers should take thought about how
|
* However, they can invoke SQL-visible functions, so callers should take
|
||||||
* to treat them.
|
* thought about how to treat them.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
check_functions_in_node(Node *node, check_function_callback checker,
|
check_functions_in_node(Node *node, check_function_callback checker,
|
||||||
@ -2008,6 +2029,7 @@ expression_tree_walker_impl(Node *node,
|
|||||||
case T_Const:
|
case T_Const:
|
||||||
case T_Param:
|
case T_Param:
|
||||||
case T_CaseTestExpr:
|
case T_CaseTestExpr:
|
||||||
|
case T_SQLValueFunction:
|
||||||
case T_CoerceToDomainValue:
|
case T_CoerceToDomainValue:
|
||||||
case T_SetToDefault:
|
case T_SetToDefault:
|
||||||
case T_CurrentOfExpr:
|
case T_CurrentOfExpr:
|
||||||
@ -2836,6 +2858,7 @@ expression_tree_mutator_impl(Node *node,
|
|||||||
break;
|
break;
|
||||||
case T_Param:
|
case T_Param:
|
||||||
case T_CaseTestExpr:
|
case T_CaseTestExpr:
|
||||||
|
case T_SQLValueFunction:
|
||||||
case T_JsonFormat:
|
case T_JsonFormat:
|
||||||
case T_CoerceToDomainValue:
|
case T_CoerceToDomainValue:
|
||||||
case T_SetToDefault:
|
case T_SetToDefault:
|
||||||
@ -3797,6 +3820,7 @@ raw_expression_tree_walker_impl(Node *node,
|
|||||||
case T_JsonFormat:
|
case T_JsonFormat:
|
||||||
case T_SetToDefault:
|
case T_SetToDefault:
|
||||||
case T_CurrentOfExpr:
|
case T_CurrentOfExpr:
|
||||||
|
case T_SQLValueFunction:
|
||||||
case T_Integer:
|
case T_Integer:
|
||||||
case T_Float:
|
case T_Float:
|
||||||
case T_Boolean:
|
case T_Boolean:
|
||||||
|
@ -4606,6 +4606,7 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IsA(node, MinMaxExpr) ||
|
else if (IsA(node, MinMaxExpr) ||
|
||||||
|
IsA(node, SQLValueFunction) ||
|
||||||
IsA(node, XmlExpr) ||
|
IsA(node, XmlExpr) ||
|
||||||
IsA(node, CoerceToDomain) ||
|
IsA(node, CoerceToDomain) ||
|
||||||
IsA(node, NextValueExpr))
|
IsA(node, NextValueExpr))
|
||||||
|
@ -412,6 +412,12 @@ contain_mutable_functions_walker(Node *node, void *context)
|
|||||||
/* Check all subnodes */
|
/* Check all subnodes */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsA(node, SQLValueFunction))
|
||||||
|
{
|
||||||
|
/* all variants of SQLValueFunction are stable */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsA(node, NextValueExpr))
|
if (IsA(node, NextValueExpr))
|
||||||
{
|
{
|
||||||
/* NextValueExpr is volatile */
|
/* NextValueExpr is volatile */
|
||||||
@ -560,8 +566,8 @@ contain_volatile_functions_walker(Node *node, void *context)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* See notes in contain_mutable_functions_walker about why we treat
|
* See notes in contain_mutable_functions_walker about why we treat
|
||||||
* MinMaxExpr, XmlExpr, and CoerceToDomain as immutable. Hence, none of
|
* MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
|
||||||
* them are of interest here.
|
* SQLValueFunction is stable. Hence, none of them are of interest here.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Recurse to check arguments */
|
/* Recurse to check arguments */
|
||||||
@ -606,9 +612,10 @@ contain_volatile_functions_not_nextval_walker(Node *node, void *context)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* See notes in contain_mutable_functions_walker about why we treat
|
* See notes in contain_mutable_functions_walker about why we treat
|
||||||
* MinMaxExpr, XmlExpr, and CoerceToDomain as immutable. Hence, none of
|
* MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
|
||||||
* them are of interest here. Also, since we're intentionally ignoring
|
* SQLValueFunction is stable. Hence, none of them are of interest here.
|
||||||
* nextval(), presumably we should ignore NextValueExpr.
|
* Also, since we're intentionally ignoring nextval(), presumably we
|
||||||
|
* should ignore NextValueExpr.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Recurse to check arguments */
|
/* Recurse to check arguments */
|
||||||
@ -754,8 +761,8 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
|
|||||||
* (Note: in principle that's wrong because a domain constraint could
|
* (Note: in principle that's wrong because a domain constraint could
|
||||||
* contain a parallel-unsafe function; but useful constraints probably
|
* contain a parallel-unsafe function; but useful constraints probably
|
||||||
* never would have such, and assuming they do would cripple use of
|
* never would have such, and assuming they do would cripple use of
|
||||||
* parallel query in the presence of domain types.) NextValueExpr is
|
* parallel query in the presence of domain types.) SQLValueFunction
|
||||||
* parallel-unsafe.
|
* should be safe in all cases. NextValueExpr is parallel-unsafe.
|
||||||
*/
|
*/
|
||||||
if (IsA(node, CoerceToDomain))
|
if (IsA(node, CoerceToDomain))
|
||||||
{
|
{
|
||||||
@ -1202,6 +1209,7 @@ contain_leaked_vars_walker(Node *node, void *context)
|
|||||||
case T_CaseExpr:
|
case T_CaseExpr:
|
||||||
case T_CaseTestExpr:
|
case T_CaseTestExpr:
|
||||||
case T_RowExpr:
|
case T_RowExpr:
|
||||||
|
case T_SQLValueFunction:
|
||||||
case T_NullTest:
|
case T_NullTest:
|
||||||
case T_BooleanTest:
|
case T_BooleanTest:
|
||||||
case T_NextValueExpr:
|
case T_NextValueExpr:
|
||||||
@ -3243,6 +3251,23 @@ eval_const_expressions_mutator(Node *node,
|
|||||||
newcoalesce->location = coalesceexpr->location;
|
newcoalesce->location = coalesceexpr->location;
|
||||||
return (Node *) newcoalesce;
|
return (Node *) newcoalesce;
|
||||||
}
|
}
|
||||||
|
case T_SQLValueFunction:
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* All variants of SQLValueFunction are stable, so if we are
|
||||||
|
* estimating the expression's value, we should evaluate the
|
||||||
|
* current function value. Otherwise just copy.
|
||||||
|
*/
|
||||||
|
SQLValueFunction *svf = (SQLValueFunction *) node;
|
||||||
|
|
||||||
|
if (context->estimate)
|
||||||
|
return (Node *) evaluate_expr((Expr *) svf,
|
||||||
|
svf->type,
|
||||||
|
svf->typmod,
|
||||||
|
InvalidOid);
|
||||||
|
else
|
||||||
|
return copyObject((Node *) svf);
|
||||||
|
}
|
||||||
case T_FieldSelect:
|
case T_FieldSelect:
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -198,6 +198,8 @@ static Node *makeAndExpr(Node *lexpr, Node *rexpr, int location);
|
|||||||
static Node *makeOrExpr(Node *lexpr, Node *rexpr, int location);
|
static Node *makeOrExpr(Node *lexpr, Node *rexpr, int location);
|
||||||
static Node *makeNotExpr(Node *expr, int location);
|
static Node *makeNotExpr(Node *expr, int location);
|
||||||
static Node *makeAArrayExpr(List *elements, 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,
|
static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
|
||||||
List *args, int location);
|
List *args, int location);
|
||||||
static List *mergeTableFuncParameters(List *func_args, List *columns);
|
static List *mergeTableFuncParameters(List *func_args, List *columns);
|
||||||
@ -15288,87 +15290,51 @@ func_expr_common_subexpr:
|
|||||||
}
|
}
|
||||||
| CURRENT_DATE
|
| CURRENT_DATE
|
||||||
{
|
{
|
||||||
$$ = (Node *) makeFuncCall(SystemFuncName("current_date"),
|
$$ = makeSQLValueFunction(SVFOP_CURRENT_DATE, -1, @1);
|
||||||
NIL,
|
|
||||||
COERCE_SQL_SYNTAX,
|
|
||||||
@1);
|
|
||||||
}
|
}
|
||||||
| CURRENT_TIME
|
| CURRENT_TIME
|
||||||
{
|
{
|
||||||
$$ = (Node *) makeFuncCall(SystemFuncName("current_time"),
|
$$ = makeSQLValueFunction(SVFOP_CURRENT_TIME, -1, @1);
|
||||||
NIL,
|
|
||||||
COERCE_SQL_SYNTAX,
|
|
||||||
@1);
|
|
||||||
}
|
}
|
||||||
| CURRENT_TIME '(' Iconst ')'
|
| CURRENT_TIME '(' Iconst ')'
|
||||||
{
|
{
|
||||||
$$ = (Node *) makeFuncCall(SystemFuncName("current_time"),
|
$$ = makeSQLValueFunction(SVFOP_CURRENT_TIME_N, $3, @1);
|
||||||
list_make1(makeIntConst($3, @3)),
|
|
||||||
COERCE_SQL_SYNTAX,
|
|
||||||
@1);
|
|
||||||
}
|
}
|
||||||
| CURRENT_TIMESTAMP
|
| CURRENT_TIMESTAMP
|
||||||
{
|
{
|
||||||
$$ = (Node *) makeFuncCall(SystemFuncName("current_timestamp"),
|
$$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP, -1, @1);
|
||||||
NIL,
|
|
||||||
COERCE_SQL_SYNTAX,
|
|
||||||
@1);
|
|
||||||
}
|
}
|
||||||
| CURRENT_TIMESTAMP '(' Iconst ')'
|
| CURRENT_TIMESTAMP '(' Iconst ')'
|
||||||
{
|
{
|
||||||
$$ = (Node *) makeFuncCall(SystemFuncName("current_timestamp"),
|
$$ = makeSQLValueFunction(SVFOP_CURRENT_TIMESTAMP_N, $3, @1);
|
||||||
list_make1(makeIntConst($3, @3)),
|
|
||||||
COERCE_SQL_SYNTAX,
|
|
||||||
@1);
|
|
||||||
}
|
}
|
||||||
| LOCALTIME
|
| LOCALTIME
|
||||||
{
|
{
|
||||||
$$ = (Node *) makeFuncCall(SystemFuncName("localtime"),
|
$$ = makeSQLValueFunction(SVFOP_LOCALTIME, -1, @1);
|
||||||
NIL,
|
|
||||||
COERCE_SQL_SYNTAX,
|
|
||||||
@1);
|
|
||||||
}
|
}
|
||||||
| LOCALTIME '(' Iconst ')'
|
| LOCALTIME '(' Iconst ')'
|
||||||
{
|
{
|
||||||
$$ = (Node *) makeFuncCall(SystemFuncName("localtime"),
|
$$ = makeSQLValueFunction(SVFOP_LOCALTIME_N, $3, @1);
|
||||||
list_make1(makeIntConst($3, @3)),
|
|
||||||
COERCE_SQL_SYNTAX,
|
|
||||||
@1);
|
|
||||||
}
|
}
|
||||||
| LOCALTIMESTAMP
|
| LOCALTIMESTAMP
|
||||||
{
|
{
|
||||||
$$ = (Node *) makeFuncCall(SystemFuncName("localtimestamp"),
|
$$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP, -1, @1);
|
||||||
NIL,
|
|
||||||
COERCE_SQL_SYNTAX,
|
|
||||||
@1);
|
|
||||||
}
|
}
|
||||||
| LOCALTIMESTAMP '(' Iconst ')'
|
| LOCALTIMESTAMP '(' Iconst ')'
|
||||||
{
|
{
|
||||||
$$ = (Node *) makeFuncCall(SystemFuncName("localtimestamp"),
|
$$ = makeSQLValueFunction(SVFOP_LOCALTIMESTAMP_N, $3, @1);
|
||||||
list_make1(makeIntConst($3, @3)),
|
|
||||||
COERCE_SQL_SYNTAX,
|
|
||||||
@1);
|
|
||||||
}
|
}
|
||||||
| CURRENT_ROLE
|
| CURRENT_ROLE
|
||||||
{
|
{
|
||||||
$$ = (Node *) makeFuncCall(SystemFuncName("current_role"),
|
$$ = makeSQLValueFunction(SVFOP_CURRENT_ROLE, -1, @1);
|
||||||
NIL,
|
|
||||||
COERCE_SQL_SYNTAX,
|
|
||||||
@1);
|
|
||||||
}
|
}
|
||||||
| CURRENT_USER
|
| CURRENT_USER
|
||||||
{
|
{
|
||||||
$$ = (Node *) makeFuncCall(SystemFuncName("current_user"),
|
$$ = makeSQLValueFunction(SVFOP_CURRENT_USER, -1, @1);
|
||||||
NIL,
|
|
||||||
COERCE_SQL_SYNTAX,
|
|
||||||
@1);
|
|
||||||
}
|
}
|
||||||
| SESSION_USER
|
| SESSION_USER
|
||||||
{
|
{
|
||||||
$$ = (Node *) makeFuncCall(SystemFuncName("session_user"),
|
$$ = makeSQLValueFunction(SVFOP_SESSION_USER, -1, @1);
|
||||||
NIL,
|
|
||||||
COERCE_SQL_SYNTAX,
|
|
||||||
@1);
|
|
||||||
}
|
}
|
||||||
| SYSTEM_USER
|
| SYSTEM_USER
|
||||||
{
|
{
|
||||||
@ -15379,24 +15345,15 @@ func_expr_common_subexpr:
|
|||||||
}
|
}
|
||||||
| USER
|
| USER
|
||||||
{
|
{
|
||||||
$$ = (Node *) makeFuncCall(SystemFuncName("user"),
|
$$ = makeSQLValueFunction(SVFOP_USER, -1, @1);
|
||||||
NIL,
|
|
||||||
COERCE_SQL_SYNTAX,
|
|
||||||
@1);
|
|
||||||
}
|
}
|
||||||
| CURRENT_CATALOG
|
| CURRENT_CATALOG
|
||||||
{
|
{
|
||||||
$$ = (Node *) makeFuncCall(SystemFuncName("current_catalog"),
|
$$ = makeSQLValueFunction(SVFOP_CURRENT_CATALOG, -1, @1);
|
||||||
NIL,
|
|
||||||
COERCE_SQL_SYNTAX,
|
|
||||||
@1);
|
|
||||||
}
|
}
|
||||||
| CURRENT_SCHEMA
|
| CURRENT_SCHEMA
|
||||||
{
|
{
|
||||||
$$ = (Node *) makeFuncCall(SystemFuncName("current_schema"),
|
$$ = makeSQLValueFunction(SVFOP_CURRENT_SCHEMA, -1, @1);
|
||||||
NIL,
|
|
||||||
COERCE_SQL_SYNTAX,
|
|
||||||
@1);
|
|
||||||
}
|
}
|
||||||
| CAST '(' a_expr AS Typename ')'
|
| CAST '(' a_expr AS Typename ')'
|
||||||
{ $$ = makeTypeCast($3, $5, @1); }
|
{ $$ = makeTypeCast($3, $5, @1); }
|
||||||
@ -18519,6 +18476,18 @@ makeAArrayExpr(List *elements, int location)
|
|||||||
return (Node *) n;
|
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 *
|
static Node *
|
||||||
makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
|
makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
|
||||||
int location)
|
int location)
|
||||||
|
@ -64,6 +64,8 @@ static Node *transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
|
|||||||
static Node *transformRowExpr(ParseState *pstate, RowExpr *r, bool allowDefault);
|
static Node *transformRowExpr(ParseState *pstate, RowExpr *r, bool allowDefault);
|
||||||
static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c);
|
static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c);
|
||||||
static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m);
|
static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m);
|
||||||
|
static Node *transformSQLValueFunction(ParseState *pstate,
|
||||||
|
SQLValueFunction *svf);
|
||||||
static Node *transformXmlExpr(ParseState *pstate, XmlExpr *x);
|
static Node *transformXmlExpr(ParseState *pstate, XmlExpr *x);
|
||||||
static Node *transformXmlSerialize(ParseState *pstate, XmlSerialize *xs);
|
static Node *transformXmlSerialize(ParseState *pstate, XmlSerialize *xs);
|
||||||
static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
|
static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
|
||||||
@ -250,6 +252,11 @@ transformExprRecurse(ParseState *pstate, Node *expr)
|
|||||||
result = transformMinMaxExpr(pstate, (MinMaxExpr *) expr);
|
result = transformMinMaxExpr(pstate, (MinMaxExpr *) expr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_SQLValueFunction:
|
||||||
|
result = transformSQLValueFunction(pstate,
|
||||||
|
(SQLValueFunction *) expr);
|
||||||
|
break;
|
||||||
|
|
||||||
case T_XmlExpr:
|
case T_XmlExpr:
|
||||||
result = transformXmlExpr(pstate, (XmlExpr *) expr);
|
result = transformXmlExpr(pstate, (XmlExpr *) expr);
|
||||||
break;
|
break;
|
||||||
@ -2220,6 +2227,59 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m)
|
|||||||
return (Node *) newm;
|
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 *
|
static Node *
|
||||||
transformXmlExpr(ParseState *pstate, XmlExpr *x)
|
transformXmlExpr(ParseState *pstate, XmlExpr *x)
|
||||||
{
|
{
|
||||||
|
@ -1876,6 +1876,49 @@ FigureColnameInternal(Node *node, char **name)
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case T_XmlExpr:
|
||||||
/* make SQL/XML functions act like a regular function */
|
/* make SQL/XML functions act like a regular function */
|
||||||
switch (((XmlExpr *) node)->op)
|
switch (((XmlExpr *) node)->op)
|
||||||
|
@ -46,6 +46,27 @@
|
|||||||
|
|
||||||
/* common code for timetypmodin and timetztypmodin */
|
/* common code for timetypmodin and timetztypmodin */
|
||||||
static int32
|
static int32
|
||||||
|
anytime_typmodin(bool istz, ArrayType *ta)
|
||||||
|
{
|
||||||
|
int32 *tl;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
tl = ArrayGetIntegerTypmods(ta, &n);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we're not too tense about good error message here because grammar
|
||||||
|
* shouldn't allow wrong number of modifiers for TIME
|
||||||
|
*/
|
||||||
|
if (n != 1)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("invalid type modifier")));
|
||||||
|
|
||||||
|
return anytime_typmod_check(istz, tl[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* exported so parse_expr.c can use it */
|
||||||
|
int32
|
||||||
anytime_typmod_check(bool istz, int32 typmod)
|
anytime_typmod_check(bool istz, int32 typmod)
|
||||||
{
|
{
|
||||||
if (typmod < 0)
|
if (typmod < 0)
|
||||||
@ -66,26 +87,6 @@ anytime_typmod_check(bool istz, int32 typmod)
|
|||||||
return typmod;
|
return typmod;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32
|
|
||||||
anytime_typmodin(bool istz, ArrayType *ta)
|
|
||||||
{
|
|
||||||
int32 *tl;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
tl = ArrayGetIntegerTypmods(ta, &n);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* we're not too tense about good error message here because grammar
|
|
||||||
* shouldn't allow wrong number of modifiers for TIME
|
|
||||||
*/
|
|
||||||
if (n != 1)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
||||||
errmsg("invalid type modifier")));
|
|
||||||
|
|
||||||
return anytime_typmod_check(istz, tl[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* common code for timetypmodout and timetztypmodout */
|
/* common code for timetypmodout and timetztypmodout */
|
||||||
static char *
|
static char *
|
||||||
anytime_typmodout(bool istz, int32 typmod)
|
anytime_typmodout(bool istz, int32 typmod)
|
||||||
@ -301,10 +302,10 @@ EncodeSpecialDate(DateADT dt, char *str)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* current_date -- implements CURRENT_DATE
|
* GetSQLCurrentDate -- implements CURRENT_DATE
|
||||||
*/
|
*/
|
||||||
Datum
|
DateADT
|
||||||
current_date(PG_FUNCTION_ARGS)
|
GetSQLCurrentDate(void)
|
||||||
{
|
{
|
||||||
struct pg_tm tm;
|
struct pg_tm tm;
|
||||||
|
|
||||||
@ -330,56 +331,46 @@ current_date(PG_FUNCTION_ARGS)
|
|||||||
cache_mday = tm.tm_mday;
|
cache_mday = tm.tm_mday;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DateADTGetDatum(cache_date);
|
return cache_date;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* current_time -- implements CURRENT_TIME, CURRENT_TIME(n)
|
* GetSQLCurrentTime -- implements CURRENT_TIME, CURRENT_TIME(n)
|
||||||
*/
|
*/
|
||||||
Datum
|
TimeTzADT *
|
||||||
current_time(PG_FUNCTION_ARGS)
|
GetSQLCurrentTime(int32 typmod)
|
||||||
{
|
{
|
||||||
TimeTzADT *result;
|
TimeTzADT *result;
|
||||||
struct pg_tm tt,
|
struct pg_tm tt,
|
||||||
*tm = &tt;
|
*tm = &tt;
|
||||||
fsec_t fsec;
|
fsec_t fsec;
|
||||||
int tz;
|
int tz;
|
||||||
int32 typmod = -1;
|
|
||||||
|
|
||||||
if (!PG_ARGISNULL(0))
|
|
||||||
typmod = anytime_typmod_check(true, PG_GETARG_INT32(0));
|
|
||||||
|
|
||||||
GetCurrentTimeUsec(tm, &fsec, &tz);
|
GetCurrentTimeUsec(tm, &fsec, &tz);
|
||||||
|
|
||||||
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
|
result = (TimeTzADT *) palloc(sizeof(TimeTzADT));
|
||||||
tm2timetz(tm, fsec, tz, result);
|
tm2timetz(tm, fsec, tz, result);
|
||||||
AdjustTimeForTypmod(&(result->time), typmod);
|
AdjustTimeForTypmod(&(result->time), typmod);
|
||||||
|
return result;
|
||||||
return TimeTzADTPGetDatum(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sql_localtime -- implements LOCALTIME, LOCALTIME(n)
|
* GetSQLLocalTime -- implements LOCALTIME, LOCALTIME(n)
|
||||||
*/
|
*/
|
||||||
Datum
|
TimeADT
|
||||||
sql_localtime(PG_FUNCTION_ARGS)
|
GetSQLLocalTime(int32 typmod)
|
||||||
{
|
{
|
||||||
TimeADT result;
|
TimeADT result;
|
||||||
struct pg_tm tt,
|
struct pg_tm tt,
|
||||||
*tm = &tt;
|
*tm = &tt;
|
||||||
fsec_t fsec;
|
fsec_t fsec;
|
||||||
int tz;
|
int tz;
|
||||||
int32 typmod = -1;
|
|
||||||
|
|
||||||
if (!PG_ARGISNULL(0))
|
|
||||||
typmod = anytime_typmod_check(false, PG_GETARG_INT32(0));
|
|
||||||
|
|
||||||
GetCurrentTimeUsec(tm, &fsec, &tz);
|
GetCurrentTimeUsec(tm, &fsec, &tz);
|
||||||
|
|
||||||
tm2time(tm, fsec, &result);
|
tm2time(tm, fsec, &result);
|
||||||
AdjustTimeForTypmod(&result, typmod);
|
AdjustTimeForTypmod(&result, typmod);
|
||||||
|
return result;
|
||||||
return TimeADTGetDatum(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -8254,6 +8254,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
|
|||||||
case T_RowExpr:
|
case T_RowExpr:
|
||||||
case T_CoalesceExpr:
|
case T_CoalesceExpr:
|
||||||
case T_MinMaxExpr:
|
case T_MinMaxExpr:
|
||||||
|
case T_SQLValueFunction:
|
||||||
case T_XmlExpr:
|
case T_XmlExpr:
|
||||||
case T_NextValueExpr:
|
case T_NextValueExpr:
|
||||||
case T_NullIfExpr:
|
case T_NullIfExpr:
|
||||||
@ -9242,6 +9243,67 @@ get_rule_expr(Node *node, deparse_context *context,
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
case T_XmlExpr:
|
||||||
{
|
{
|
||||||
XmlExpr *xexpr = (XmlExpr *) node;
|
XmlExpr *xexpr = (XmlExpr *) node;
|
||||||
@ -9816,6 +9878,7 @@ looks_like_function(Node *node)
|
|||||||
case T_NullIfExpr:
|
case T_NullIfExpr:
|
||||||
case T_CoalesceExpr:
|
case T_CoalesceExpr:
|
||||||
case T_MinMaxExpr:
|
case T_MinMaxExpr:
|
||||||
|
case T_SQLValueFunction:
|
||||||
case T_XmlExpr:
|
case T_XmlExpr:
|
||||||
/* these are all accepted by func_expr_common_subexpr */
|
/* these are all accepted by func_expr_common_subexpr */
|
||||||
return true;
|
return true;
|
||||||
@ -10217,33 +10280,6 @@ get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* get_func_sql_syntax_time
|
|
||||||
*
|
|
||||||
* Parse back argument of SQL-syntax function call related to a time or a
|
|
||||||
* timestamp. These require a specific handling when their typmod is given
|
|
||||||
* by the function caller through their SQL keyword.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
get_func_sql_syntax_time(List *args, deparse_context *context)
|
|
||||||
{
|
|
||||||
StringInfo buf = context->buf;
|
|
||||||
Const *cons;
|
|
||||||
|
|
||||||
if (list_length(args) != 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
cons = (Const *) linitial(args);
|
|
||||||
Assert(IsA(cons, Const));
|
|
||||||
|
|
||||||
if (!cons->constisnull)
|
|
||||||
{
|
|
||||||
appendStringInfoString(buf, "(");
|
|
||||||
get_rule_expr((Node *) cons, context, false);
|
|
||||||
appendStringInfoString(buf, ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get_func_sql_syntax - Parse back a SQL-syntax function call
|
* get_func_sql_syntax - Parse back a SQL-syntax function call
|
||||||
*
|
*
|
||||||
@ -10470,48 +10506,10 @@ get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
|
|||||||
appendStringInfoChar(buf, ')');
|
appendStringInfoChar(buf, ')');
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case F_CURRENT_CATALOG:
|
|
||||||
appendStringInfoString(buf, "CURRENT_CATALOG");
|
|
||||||
return true;
|
|
||||||
case F_CURRENT_ROLE:
|
|
||||||
appendStringInfoString(buf, "CURRENT_ROLE");
|
|
||||||
return true;
|
|
||||||
case F_CURRENT_SCHEMA:
|
|
||||||
appendStringInfoString(buf, "CURRENT_SCHEMA");
|
|
||||||
return true;
|
|
||||||
case F_CURRENT_USER:
|
|
||||||
appendStringInfoString(buf, "CURRENT_USER");
|
|
||||||
return true;
|
|
||||||
case F_USER:
|
|
||||||
appendStringInfoString(buf, "USER");
|
|
||||||
return true;
|
|
||||||
case F_SESSION_USER:
|
|
||||||
appendStringInfoString(buf, "SESSION_USER");
|
|
||||||
return true;
|
|
||||||
case F_SYSTEM_USER:
|
case F_SYSTEM_USER:
|
||||||
appendStringInfoString(buf, "SYSTEM_USER");
|
appendStringInfoString(buf, "SYSTEM_USER");
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case F_CURRENT_DATE:
|
|
||||||
appendStringInfoString(buf, "CURRENT_DATE");
|
|
||||||
return true;
|
|
||||||
case F_CURRENT_TIME:
|
|
||||||
appendStringInfoString(buf, "CURRENT_TIME");
|
|
||||||
get_func_sql_syntax_time(expr->args, context);
|
|
||||||
return true;
|
|
||||||
case F_CURRENT_TIMESTAMP:
|
|
||||||
appendStringInfoString(buf, "CURRENT_TIMESTAMP");
|
|
||||||
get_func_sql_syntax_time(expr->args, context);
|
|
||||||
return true;
|
|
||||||
case F_LOCALTIME:
|
|
||||||
appendStringInfoString(buf, "LOCALTIME");
|
|
||||||
get_func_sql_syntax_time(expr->args, context);
|
|
||||||
return true;
|
|
||||||
case F_LOCALTIMESTAMP:
|
|
||||||
appendStringInfoString(buf, "LOCALTIMESTAMP");
|
|
||||||
get_func_sql_syntax_time(expr->args, context);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case F_XMLEXISTS:
|
case F_XMLEXISTS:
|
||||||
/* XMLEXISTS ... extra parens because args are c_expr */
|
/* XMLEXISTS ... extra parens because args are c_expr */
|
||||||
appendStringInfoString(buf, "XMLEXISTS((");
|
appendStringInfoString(buf, "XMLEXISTS((");
|
||||||
|
@ -83,6 +83,27 @@ static Timestamp timestamptz2timestamp(TimestampTz timestamp);
|
|||||||
|
|
||||||
/* common code for timestamptypmodin and timestamptztypmodin */
|
/* common code for timestamptypmodin and timestamptztypmodin */
|
||||||
static int32
|
static int32
|
||||||
|
anytimestamp_typmodin(bool istz, ArrayType *ta)
|
||||||
|
{
|
||||||
|
int32 *tl;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
tl = ArrayGetIntegerTypmods(ta, &n);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we're not too tense about good error message here because grammar
|
||||||
|
* shouldn't allow wrong number of modifiers for TIMESTAMP
|
||||||
|
*/
|
||||||
|
if (n != 1)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("invalid type modifier")));
|
||||||
|
|
||||||
|
return anytimestamp_typmod_check(istz, tl[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* exported so parse_expr.c can use it */
|
||||||
|
int32
|
||||||
anytimestamp_typmod_check(bool istz, int32 typmod)
|
anytimestamp_typmod_check(bool istz, int32 typmod)
|
||||||
{
|
{
|
||||||
if (typmod < 0)
|
if (typmod < 0)
|
||||||
@ -103,26 +124,6 @@ anytimestamp_typmod_check(bool istz, int32 typmod)
|
|||||||
return typmod;
|
return typmod;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32
|
|
||||||
anytimestamp_typmodin(bool istz, ArrayType *ta)
|
|
||||||
{
|
|
||||||
int32 *tl;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
tl = ArrayGetIntegerTypmods(ta, &n);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* we're not too tense about good error message here because grammar
|
|
||||||
* shouldn't allow wrong number of modifiers for TIMESTAMP
|
|
||||||
*/
|
|
||||||
if (n != 1)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
||||||
errmsg("invalid type modifier")));
|
|
||||||
|
|
||||||
return anytimestamp_typmod_check(istz, tl[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* common code for timestamptypmodout and timestamptztypmodout */
|
/* common code for timestamptypmodout and timestamptztypmodout */
|
||||||
static char *
|
static char *
|
||||||
anytimestamp_typmodout(bool istz, int32 typmod)
|
anytimestamp_typmodout(bool istz, int32 typmod)
|
||||||
@ -1594,42 +1595,33 @@ GetCurrentTimestamp(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* current_timestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
|
* GetSQLCurrentTimestamp -- implements CURRENT_TIMESTAMP, CURRENT_TIMESTAMP(n)
|
||||||
*/
|
*/
|
||||||
Datum
|
TimestampTz
|
||||||
current_timestamp(PG_FUNCTION_ARGS)
|
GetSQLCurrentTimestamp(int32 typmod)
|
||||||
{
|
{
|
||||||
TimestampTz ts;
|
TimestampTz ts;
|
||||||
int32 typmod = -1;
|
|
||||||
|
|
||||||
if (!PG_ARGISNULL(0))
|
|
||||||
typmod = anytimestamp_typmod_check(true, PG_GETARG_INT32(0));
|
|
||||||
|
|
||||||
ts = GetCurrentTransactionStartTimestamp();
|
ts = GetCurrentTransactionStartTimestamp();
|
||||||
if (typmod >= 0)
|
if (typmod >= 0)
|
||||||
AdjustTimestampForTypmod(&ts, typmod, NULL);
|
AdjustTimestampForTypmod(&ts, typmod, NULL);
|
||||||
return TimestampTzGetDatum(ts);
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sql_localtimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
|
* GetSQLLocalTimestamp -- implements LOCALTIMESTAMP, LOCALTIMESTAMP(n)
|
||||||
*/
|
*/
|
||||||
Datum
|
Timestamp
|
||||||
sql_localtimestamp(PG_FUNCTION_ARGS)
|
GetSQLLocalTimestamp(int32 typmod)
|
||||||
{
|
{
|
||||||
Timestamp ts;
|
Timestamp ts;
|
||||||
int32 typmod = -1;
|
|
||||||
|
|
||||||
if (!PG_ARGISNULL(0))
|
|
||||||
typmod = anytimestamp_typmod_check(false, PG_GETARG_INT32(0));
|
|
||||||
|
|
||||||
ts = timestamptz2timestamp(GetCurrentTransactionStartTimestamp());
|
ts = timestamptz2timestamp(GetCurrentTransactionStartTimestamp());
|
||||||
if (typmod >= 0)
|
if (typmod >= 0)
|
||||||
AdjustTimestampForTypmod(&ts, typmod, NULL);
|
AdjustTimestampForTypmod(&ts, typmod, NULL);
|
||||||
return TimestampGetDatum(ts);
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* timeofday(*) -- returns the current time as a text.
|
* timeofday(*) -- returns the current time as a text.
|
||||||
*/
|
*/
|
||||||
|
@ -57,6 +57,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 202305121
|
#define CATALOG_VERSION_NO 202305171
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1505,38 +1505,12 @@
|
|||||||
{ oid => '745', descr => 'current user name',
|
{ oid => '745', descr => 'current user name',
|
||||||
proname => 'current_user', provolatile => 's', prorettype => 'name',
|
proname => 'current_user', provolatile => 's', prorettype => 'name',
|
||||||
proargtypes => '', prosrc => 'current_user' },
|
proargtypes => '', prosrc => 'current_user' },
|
||||||
{ oid => '9695', descr => 'current role name',
|
|
||||||
proname => 'current_role', provolatile => 's', prorettype => 'name',
|
|
||||||
proargtypes => '', prosrc => 'current_user' },
|
|
||||||
{ oid => '9696', descr => 'user name',
|
|
||||||
proname => 'user', provolatile => 's', prorettype => 'name',
|
|
||||||
proargtypes => '', prosrc => 'current_user' },
|
|
||||||
{ oid => '9697', descr => 'name of the current database',
|
|
||||||
proname => 'current_catalog', provolatile => 's', prorettype => 'name',
|
|
||||||
proargtypes => '', prosrc => 'current_database' },
|
|
||||||
{ oid => '746', descr => 'session user name',
|
{ oid => '746', descr => 'session user name',
|
||||||
proname => 'session_user', provolatile => 's', prorettype => 'name',
|
proname => 'session_user', provolatile => 's', prorettype => 'name',
|
||||||
proargtypes => '', prosrc => 'session_user' },
|
proargtypes => '', prosrc => 'session_user' },
|
||||||
{ oid => '9977', descr => 'system user name',
|
{ oid => '9977', descr => 'system user name',
|
||||||
proname => 'system_user', provolatile => 's', prorettype => 'text',
|
proname => 'system_user', provolatile => 's', prorettype => 'text',
|
||||||
proargtypes => '', prosrc => 'system_user' },
|
proargtypes => '', prosrc => 'system_user' },
|
||||||
{ oid => '9978', descr => 'current date',
|
|
||||||
proname => 'current_date', provolatile => 's', prorettype => 'date',
|
|
||||||
proargtypes => '', prosrc => 'current_date' },
|
|
||||||
{ oid => '9979', descr => 'current time',
|
|
||||||
proname => 'current_time', proisstrict => 'f', provolatile => 's',
|
|
||||||
prorettype => 'timetz', proargtypes => 'int4', prosrc => 'current_time' },
|
|
||||||
{ oid => '9980', descr => 'current timestamp',
|
|
||||||
proname => 'current_timestamp', proisstrict => 'f', provolatile => 's',
|
|
||||||
prorettype => 'timestamptz', proargtypes => 'int4',
|
|
||||||
prosrc => 'current_timestamp' },
|
|
||||||
{ oid => '9981', descr => 'local time',
|
|
||||||
proname => 'localtime', proisstrict => 'f', provolatile => 's',
|
|
||||||
prorettype => 'time', proargtypes => 'int4', prosrc => 'sql_localtime' },
|
|
||||||
{ oid => '9982', descr => 'local timestamp',
|
|
||||||
proname => 'localtimestamp', proisstrict => 'f', provolatile => 's',
|
|
||||||
prorettype => 'timestamp', proargtypes => 'int4',
|
|
||||||
prosrc => 'sql_localtimestamp' },
|
|
||||||
|
|
||||||
{ oid => '744',
|
{ oid => '744',
|
||||||
proname => 'array_eq', prorettype => 'bool',
|
proname => 'array_eq', prorettype => 'bool',
|
||||||
|
@ -171,6 +171,7 @@ typedef enum ExprEvalOp
|
|||||||
EEOP_DISTINCT,
|
EEOP_DISTINCT,
|
||||||
EEOP_NOT_DISTINCT,
|
EEOP_NOT_DISTINCT,
|
||||||
EEOP_NULLIF,
|
EEOP_NULLIF,
|
||||||
|
EEOP_SQLVALUEFUNCTION,
|
||||||
EEOP_CURRENTOFEXPR,
|
EEOP_CURRENTOFEXPR,
|
||||||
EEOP_NEXTVALUEEXPR,
|
EEOP_NEXTVALUEEXPR,
|
||||||
EEOP_ARRAYEXPR,
|
EEOP_ARRAYEXPR,
|
||||||
@ -418,6 +419,12 @@ typedef struct ExprEvalStep
|
|||||||
FunctionCallInfo fcinfo_data_in;
|
FunctionCallInfo fcinfo_data_in;
|
||||||
} iocoerce;
|
} iocoerce;
|
||||||
|
|
||||||
|
/* for EEOP_SQLVALUEFUNCTION */
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
SQLValueFunction *svf;
|
||||||
|
} sqlvaluefunction;
|
||||||
|
|
||||||
/* for EEOP_NEXTVALUEEXPR */
|
/* for EEOP_NEXTVALUEEXPR */
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
@ -769,6 +776,7 @@ extern void ExecEvalParamExec(ExprState *state, ExprEvalStep *op,
|
|||||||
ExprContext *econtext);
|
ExprContext *econtext);
|
||||||
extern void ExecEvalParamExtern(ExprState *state, ExprEvalStep *op,
|
extern void ExecEvalParamExtern(ExprState *state, ExprEvalStep *op,
|
||||||
ExprContext *econtext);
|
ExprContext *econtext);
|
||||||
|
extern void ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op);
|
||||||
extern void ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op);
|
extern void ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op);
|
||||||
extern void ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op);
|
extern void ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op);
|
||||||
extern void ExecEvalRowNull(ExprState *state, ExprEvalStep *op,
|
extern void ExecEvalRowNull(ExprState *state, ExprEvalStep *op,
|
||||||
|
@ -1445,6 +1445,49 @@ typedef struct MinMaxExpr
|
|||||||
int location;
|
int location;
|
||||||
} MinMaxExpr;
|
} MinMaxExpr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SQLValueFunction - parameterless functions with special grammar productions
|
||||||
|
*
|
||||||
|
* The SQL standard categorizes some of these as <datetime value function>
|
||||||
|
* and others as <general value specification>. We call 'em SQLValueFunctions
|
||||||
|
* for lack of a better term. We store type and typmod of the result so that
|
||||||
|
* some code doesn't need to know each function individually, and because
|
||||||
|
* we would need to store typmod anyway for some of the datetime functions.
|
||||||
|
* Note that currently, all variants return non-collating datatypes, so we do
|
||||||
|
* not need a collation field; also, all these functions are stable.
|
||||||
|
*/
|
||||||
|
typedef enum SQLValueFunctionOp
|
||||||
|
{
|
||||||
|
SVFOP_CURRENT_DATE,
|
||||||
|
SVFOP_CURRENT_TIME,
|
||||||
|
SVFOP_CURRENT_TIME_N,
|
||||||
|
SVFOP_CURRENT_TIMESTAMP,
|
||||||
|
SVFOP_CURRENT_TIMESTAMP_N,
|
||||||
|
SVFOP_LOCALTIME,
|
||||||
|
SVFOP_LOCALTIME_N,
|
||||||
|
SVFOP_LOCALTIMESTAMP,
|
||||||
|
SVFOP_LOCALTIMESTAMP_N,
|
||||||
|
SVFOP_CURRENT_ROLE,
|
||||||
|
SVFOP_CURRENT_USER,
|
||||||
|
SVFOP_USER,
|
||||||
|
SVFOP_SESSION_USER,
|
||||||
|
SVFOP_CURRENT_CATALOG,
|
||||||
|
SVFOP_CURRENT_SCHEMA
|
||||||
|
} SQLValueFunctionOp;
|
||||||
|
|
||||||
|
typedef struct SQLValueFunction
|
||||||
|
{
|
||||||
|
Expr xpr;
|
||||||
|
SQLValueFunctionOp op; /* which function this is */
|
||||||
|
/*
|
||||||
|
* Result type/typmod. Type is fully determined by "op", so no need to
|
||||||
|
* include this Oid in the query jumbling.
|
||||||
|
*/
|
||||||
|
Oid type pg_node_attr(query_jumble_ignore);
|
||||||
|
int32 typmod;
|
||||||
|
int location; /* token location, or -1 if unknown */
|
||||||
|
} SQLValueFunction;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XmlExpr - various SQL/XML functions requiring special grammar productions
|
* XmlExpr - various SQL/XML functions requiring special grammar productions
|
||||||
*
|
*
|
||||||
|
@ -96,6 +96,7 @@ TimeTzADTPGetDatum(const TimeTzADT *X)
|
|||||||
|
|
||||||
|
|
||||||
/* date.c */
|
/* date.c */
|
||||||
|
extern int32 anytime_typmod_check(bool istz, int32 typmod);
|
||||||
extern double date2timestamp_no_overflow(DateADT dateVal);
|
extern double date2timestamp_no_overflow(DateADT dateVal);
|
||||||
extern Timestamp date2timestamp_opt_overflow(DateADT dateVal, int *overflow);
|
extern Timestamp date2timestamp_opt_overflow(DateADT dateVal, int *overflow);
|
||||||
extern TimestampTz date2timestamptz_opt_overflow(DateADT dateVal, int *overflow);
|
extern TimestampTz date2timestamptz_opt_overflow(DateADT dateVal, int *overflow);
|
||||||
@ -103,6 +104,9 @@ extern int32 date_cmp_timestamp_internal(DateADT dateVal, Timestamp dt2);
|
|||||||
extern int32 date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2);
|
extern int32 date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2);
|
||||||
|
|
||||||
extern void EncodeSpecialDate(DateADT dt, char *str);
|
extern void EncodeSpecialDate(DateADT dt, char *str);
|
||||||
|
extern DateADT GetSQLCurrentDate(void);
|
||||||
|
extern TimeTzADT *GetSQLCurrentTime(int32 typmod);
|
||||||
|
extern TimeADT GetSQLLocalTime(int32 typmod);
|
||||||
extern int time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec);
|
extern int time2tm(TimeADT time, struct pg_tm *tm, fsec_t *fsec);
|
||||||
extern int timetz2tm(TimeTzADT *time, struct pg_tm *tm, fsec_t *fsec, int *tzp);
|
extern int timetz2tm(TimeTzADT *time, struct pg_tm *tm, fsec_t *fsec, int *tzp);
|
||||||
extern int tm2time(struct pg_tm *tm, fsec_t fsec, TimeADT *result);
|
extern int tm2time(struct pg_tm *tm, fsec_t fsec, TimeADT *result);
|
||||||
|
@ -95,7 +95,11 @@ extern PGDLLIMPORT TimestampTz PgReloadTime;
|
|||||||
|
|
||||||
/* Internal routines (not fmgr-callable) */
|
/* Internal routines (not fmgr-callable) */
|
||||||
|
|
||||||
|
extern int32 anytimestamp_typmod_check(bool istz, int32 typmod);
|
||||||
|
|
||||||
extern TimestampTz GetCurrentTimestamp(void);
|
extern TimestampTz GetCurrentTimestamp(void);
|
||||||
|
extern TimestampTz GetSQLCurrentTimestamp(int32 typmod);
|
||||||
|
extern Timestamp GetSQLLocalTimestamp(int32 typmod);
|
||||||
extern void TimestampDifference(TimestampTz start_time, TimestampTz stop_time,
|
extern void TimestampDifference(TimestampTz start_time, TimestampTz stop_time,
|
||||||
long *secs, int *microsecs);
|
long *secs, int *microsecs);
|
||||||
extern long TimestampDifferenceMilliseconds(TimestampTz start_time,
|
extern long TimestampDifferenceMilliseconds(TimestampTz start_time,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
-- expression evaluation tests that don't fit into a more specific file
|
-- expression evaluation tests that don't fit into a more specific file
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- Tests for various FuncCalls with COERCE_SQL_SYNTAX.
|
-- Tests for SQLValueFunction
|
||||||
--
|
--
|
||||||
-- current_date (always matches because of transactional behaviour)
|
-- current_date (always matches because of transactional behaviour)
|
||||||
SELECT date(now())::text = current_date::text;
|
SELECT date(now())::text = current_date::text;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
--
|
--
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Tests for various FuncCalls with COERCE_SQL_SYNTAX.
|
-- Tests for SQLValueFunction
|
||||||
--
|
--
|
||||||
|
|
||||||
|
|
||||||
|
@ -2425,6 +2425,8 @@ SQLFunctionCache
|
|||||||
SQLFunctionCachePtr
|
SQLFunctionCachePtr
|
||||||
SQLFunctionParseInfo
|
SQLFunctionParseInfo
|
||||||
SQLFunctionParseInfoPtr
|
SQLFunctionParseInfoPtr
|
||||||
|
SQLValueFunction
|
||||||
|
SQLValueFunctionOp
|
||||||
SSL
|
SSL
|
||||||
SSLExtensionInfoContext
|
SSLExtensionInfoContext
|
||||||
SSL_CTX
|
SSL_CTX
|
||||||
|
Loading…
x
Reference in New Issue
Block a user