mirror of
https://github.com/postgres/postgres.git
synced 2025-11-10 17:42:29 +03:00
Common SQL/JSON clauses
This introduces some of the building blocks used by the SQL/JSON constructor and query functions. Specifically, it provides node executor and grammar support for the FORMAT JSON [ENCODING foo] clause, and values decorated with it, and for the RETURNING clause. The following SQL/JSON patches will leverage these. Nikita Glukhov (who probably deserves an award for perseverance). Reviewers have included (in no particular order) Andres Freund, Alexander Korotkov, Pavel Stehule, Andrew Alsup. Erik Rijkers, Zihong Yu and Himanshu Upadhyaya. Discussion: https://postgr.es/m/cd0bb935-0158-78a7-08b5-904886deac4b@postgrespro.ru
This commit is contained in:
@@ -2298,6 +2298,52 @@ _copyOnConflictExpr(const OnConflictExpr *from)
|
||||
return newnode;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* _copyJsonFormat
|
||||
*/
|
||||
static JsonFormat *
|
||||
_copyJsonFormat(const JsonFormat *from)
|
||||
{
|
||||
JsonFormat *newnode = makeNode(JsonFormat);
|
||||
|
||||
COPY_SCALAR_FIELD(format_type);
|
||||
COPY_SCALAR_FIELD(encoding);
|
||||
COPY_LOCATION_FIELD(location);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyJsonReturning
|
||||
*/
|
||||
static JsonReturning *
|
||||
_copyJsonReturning(const JsonReturning *from)
|
||||
{
|
||||
JsonReturning *newnode = makeNode(JsonReturning);
|
||||
|
||||
COPY_NODE_FIELD(format);
|
||||
COPY_SCALAR_FIELD(typid);
|
||||
COPY_SCALAR_FIELD(typmod);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyJsonValueExpr
|
||||
*/
|
||||
static JsonValueExpr *
|
||||
_copyJsonValueExpr(const JsonValueExpr *from)
|
||||
{
|
||||
JsonValueExpr *newnode = makeNode(JsonValueExpr);
|
||||
|
||||
COPY_NODE_FIELD(raw_expr);
|
||||
COPY_NODE_FIELD(formatted_expr);
|
||||
COPY_NODE_FIELD(format);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/* ****************************************************************
|
||||
* pathnodes.h copy functions
|
||||
*
|
||||
@@ -5350,6 +5396,15 @@ copyObjectImpl(const void *from)
|
||||
case T_OnConflictExpr:
|
||||
retval = _copyOnConflictExpr(from);
|
||||
break;
|
||||
case T_JsonFormat:
|
||||
retval = _copyJsonFormat(from);
|
||||
break;
|
||||
case T_JsonReturning:
|
||||
retval = _copyJsonReturning(from);
|
||||
break;
|
||||
case T_JsonValueExpr:
|
||||
retval = _copyJsonValueExpr(from);
|
||||
break;
|
||||
|
||||
/*
|
||||
* RELATION NODES
|
||||
|
||||
@@ -841,6 +841,36 @@ _equalOnConflictExpr(const OnConflictExpr *a, const OnConflictExpr *b)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalJsonFormat(const JsonFormat *a, const JsonFormat *b)
|
||||
{
|
||||
COMPARE_SCALAR_FIELD(format_type);
|
||||
COMPARE_SCALAR_FIELD(encoding);
|
||||
COMPARE_LOCATION_FIELD(location);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalJsonReturning(const JsonReturning *a, const JsonReturning *b)
|
||||
{
|
||||
COMPARE_NODE_FIELD(format);
|
||||
COMPARE_SCALAR_FIELD(typid);
|
||||
COMPARE_SCALAR_FIELD(typmod);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalJsonValueExpr(const JsonValueExpr *a, const JsonValueExpr *b)
|
||||
{
|
||||
COMPARE_NODE_FIELD(raw_expr);
|
||||
COMPARE_NODE_FIELD(formatted_expr);
|
||||
COMPARE_NODE_FIELD(format);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stuff from pathnodes.h
|
||||
*/
|
||||
@@ -3358,6 +3388,15 @@ equal(const void *a, const void *b)
|
||||
case T_JoinExpr:
|
||||
retval = _equalJoinExpr(a, b);
|
||||
break;
|
||||
case T_JsonFormat:
|
||||
retval = _equalJsonFormat(a, b);
|
||||
break;
|
||||
case T_JsonReturning:
|
||||
retval = _equalJsonReturning(a, b);
|
||||
break;
|
||||
case T_JsonValueExpr:
|
||||
retval = _equalJsonValueExpr(a, b);
|
||||
break;
|
||||
|
||||
/*
|
||||
* RELATION NODES
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "catalog/pg_type.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "nodes/nodeFuncs.h"
|
||||
#include "utils/errcodes.h"
|
||||
#include "utils/lsyscache.h"
|
||||
|
||||
|
||||
@@ -818,3 +819,56 @@ makeVacuumRelation(RangeVar *relation, Oid oid, List *va_cols)
|
||||
v->va_cols = va_cols;
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
* makeJsonFormat -
|
||||
* creates a JsonFormat node
|
||||
*/
|
||||
JsonFormat *
|
||||
makeJsonFormat(JsonFormatType type, JsonEncoding encoding, int location)
|
||||
{
|
||||
JsonFormat *jf = makeNode(JsonFormat);
|
||||
|
||||
jf->format_type = type;
|
||||
jf->encoding = encoding;
|
||||
jf->location = location;
|
||||
|
||||
return jf;
|
||||
}
|
||||
|
||||
/*
|
||||
* makeJsonValueExpr -
|
||||
* creates a JsonValueExpr node
|
||||
*/
|
||||
JsonValueExpr *
|
||||
makeJsonValueExpr(Expr *expr, JsonFormat *format)
|
||||
{
|
||||
JsonValueExpr *jve = makeNode(JsonValueExpr);
|
||||
|
||||
jve->raw_expr = expr;
|
||||
jve->formatted_expr = NULL;
|
||||
jve->format = format;
|
||||
|
||||
return jve;
|
||||
}
|
||||
|
||||
/*
|
||||
* makeJsonEncoding -
|
||||
* converts JSON encoding name to enum JsonEncoding
|
||||
*/
|
||||
JsonEncoding
|
||||
makeJsonEncoding(char *name)
|
||||
{
|
||||
if (!pg_strcasecmp(name, "utf8"))
|
||||
return JS_ENC_UTF8;
|
||||
if (!pg_strcasecmp(name, "utf16"))
|
||||
return JS_ENC_UTF16;
|
||||
if (!pg_strcasecmp(name, "utf32"))
|
||||
return JS_ENC_UTF32;
|
||||
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("unrecognized JSON encoding: %s", name)));
|
||||
|
||||
return JS_ENC_DEFAULT;
|
||||
}
|
||||
|
||||
@@ -250,6 +250,13 @@ exprType(const Node *expr)
|
||||
case T_PlaceHolderVar:
|
||||
type = exprType((Node *) ((const PlaceHolderVar *) expr)->phexpr);
|
||||
break;
|
||||
case T_JsonValueExpr:
|
||||
{
|
||||
const JsonValueExpr *jve = (const JsonValueExpr *) expr;
|
||||
|
||||
type = exprType((Node *) (jve->formatted_expr ? jve->formatted_expr : jve->raw_expr));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
|
||||
type = InvalidOid; /* keep compiler quiet */
|
||||
@@ -482,6 +489,8 @@ exprTypmod(const Node *expr)
|
||||
return ((const SetToDefault *) expr)->typeMod;
|
||||
case T_PlaceHolderVar:
|
||||
return exprTypmod((Node *) ((const PlaceHolderVar *) expr)->phexpr);
|
||||
case T_JsonValueExpr:
|
||||
return exprTypmod((Node *) ((const JsonValueExpr *) expr)->formatted_expr);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -958,6 +967,9 @@ exprCollation(const Node *expr)
|
||||
case T_PlaceHolderVar:
|
||||
coll = exprCollation((Node *) ((const PlaceHolderVar *) expr)->phexpr);
|
||||
break;
|
||||
case T_JsonValueExpr:
|
||||
coll = exprCollation((Node *) ((const JsonValueExpr *) expr)->formatted_expr);
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
|
||||
coll = InvalidOid; /* keep compiler quiet */
|
||||
@@ -1170,6 +1182,10 @@ exprSetCollation(Node *expr, Oid collation)
|
||||
/* NextValueExpr's result is an integer type ... */
|
||||
Assert(!OidIsValid(collation)); /* ... so never set a collation */
|
||||
break;
|
||||
case T_JsonValueExpr:
|
||||
exprSetCollation((Node *) ((JsonValueExpr *) expr)->formatted_expr,
|
||||
collation);
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
|
||||
break;
|
||||
@@ -1616,6 +1632,9 @@ exprLocation(const Node *expr)
|
||||
case T_PartitionRangeDatum:
|
||||
loc = ((const PartitionRangeDatum *) expr)->location;
|
||||
break;
|
||||
case T_JsonValueExpr:
|
||||
loc = exprLocation((Node *) ((const JsonValueExpr *) expr)->raw_expr);
|
||||
break;
|
||||
default:
|
||||
/* for any other node type it's just unknown... */
|
||||
loc = -1;
|
||||
@@ -2350,6 +2369,16 @@ expression_tree_walker(Node *node,
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case T_JsonValueExpr:
|
||||
{
|
||||
JsonValueExpr *jve = (JsonValueExpr *) node;
|
||||
|
||||
if (walker(jve->raw_expr, context))
|
||||
return true;
|
||||
if (walker(jve->formatted_expr, context))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d",
|
||||
(int) nodeTag(node));
|
||||
@@ -2680,6 +2709,7 @@ expression_tree_mutator(Node *node,
|
||||
case T_RangeTblRef:
|
||||
case T_SortGroupClause:
|
||||
case T_CTESearchClause:
|
||||
case T_JsonFormat:
|
||||
return (Node *) copyObject(node);
|
||||
case T_WithCheckOption:
|
||||
{
|
||||
@@ -3311,6 +3341,28 @@ expression_tree_mutator(Node *node,
|
||||
return (Node *) newnode;
|
||||
}
|
||||
break;
|
||||
case T_JsonReturning:
|
||||
{
|
||||
JsonReturning *jr = (JsonReturning *) node;
|
||||
JsonReturning *newnode;
|
||||
|
||||
FLATCOPY(newnode, jr, JsonReturning);
|
||||
MUTATE(newnode->format, jr->format, JsonFormat *);
|
||||
|
||||
return (Node *) newnode;
|
||||
}
|
||||
case T_JsonValueExpr:
|
||||
{
|
||||
JsonValueExpr *jve = (JsonValueExpr *) node;
|
||||
JsonValueExpr *newnode;
|
||||
|
||||
FLATCOPY(newnode, jve, JsonValueExpr);
|
||||
MUTATE(newnode->raw_expr, jve->raw_expr, Expr *);
|
||||
MUTATE(newnode->formatted_expr, jve->formatted_expr, Expr *);
|
||||
MUTATE(newnode->format, jve->format, JsonFormat *);
|
||||
|
||||
return (Node *) newnode;
|
||||
}
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d",
|
||||
(int) nodeTag(node));
|
||||
@@ -4019,6 +4071,20 @@ raw_expression_tree_walker(Node *node,
|
||||
case T_CommonTableExpr:
|
||||
/* search_clause and cycle_clause are not interesting here */
|
||||
return walker(((CommonTableExpr *) node)->ctequery, context);
|
||||
case T_JsonReturning:
|
||||
return walker(((JsonReturning *) node)->format, context);
|
||||
case T_JsonValueExpr:
|
||||
{
|
||||
JsonValueExpr *jve = (JsonValueExpr *) node;
|
||||
|
||||
if (walker(jve->raw_expr, context))
|
||||
return true;
|
||||
if (walker(jve->formatted_expr, context))
|
||||
return true;
|
||||
if (walker(jve->format, context))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d",
|
||||
(int) nodeTag(node));
|
||||
|
||||
@@ -1751,6 +1751,36 @@ _outOnConflictExpr(StringInfo str, const OnConflictExpr *node)
|
||||
WRITE_NODE_FIELD(exclRelTlist);
|
||||
}
|
||||
|
||||
static void
|
||||
_outJsonFormat(StringInfo str, const JsonFormat *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("JSONFORMAT");
|
||||
|
||||
WRITE_ENUM_FIELD(format_type, JsonFormatType);
|
||||
WRITE_ENUM_FIELD(encoding, JsonEncoding);
|
||||
WRITE_LOCATION_FIELD(location);
|
||||
}
|
||||
|
||||
static void
|
||||
_outJsonReturning(StringInfo str, const JsonReturning *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("JSONRETURNING");
|
||||
|
||||
WRITE_NODE_FIELD(format);
|
||||
WRITE_OID_FIELD(typid);
|
||||
WRITE_INT_FIELD(typmod);
|
||||
}
|
||||
|
||||
static void
|
||||
_outJsonValueExpr(StringInfo str, const JsonValueExpr *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("JSONVALUEEXPR");
|
||||
|
||||
WRITE_NODE_FIELD(raw_expr);
|
||||
WRITE_NODE_FIELD(formatted_expr);
|
||||
WRITE_NODE_FIELD(format);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Stuff from pathnodes.h.
|
||||
@@ -4537,6 +4567,15 @@ outNode(StringInfo str, const void *obj)
|
||||
case T_PartitionRangeDatum:
|
||||
_outPartitionRangeDatum(str, obj);
|
||||
break;
|
||||
case T_JsonFormat:
|
||||
_outJsonFormat(str, obj);
|
||||
break;
|
||||
case T_JsonReturning:
|
||||
_outJsonReturning(str, obj);
|
||||
break;
|
||||
case T_JsonValueExpr:
|
||||
_outJsonValueExpr(str, obj);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
|
||||
@@ -1389,6 +1389,51 @@ _readOnConflictExpr(void)
|
||||
READ_DONE();
|
||||
}
|
||||
|
||||
/*
|
||||
* _readJsonFormat
|
||||
*/
|
||||
static JsonFormat *
|
||||
_readJsonFormat(void)
|
||||
{
|
||||
READ_LOCALS(JsonFormat);
|
||||
|
||||
READ_ENUM_FIELD(format_type, JsonFormatType);
|
||||
READ_ENUM_FIELD(encoding, JsonEncoding);
|
||||
READ_LOCATION_FIELD(location);
|
||||
|
||||
READ_DONE();
|
||||
}
|
||||
|
||||
/*
|
||||
* _readJsonReturning
|
||||
*/
|
||||
static JsonReturning *
|
||||
_readJsonReturning(void)
|
||||
{
|
||||
READ_LOCALS(JsonReturning);
|
||||
|
||||
READ_NODE_FIELD(format);
|
||||
READ_OID_FIELD(typid);
|
||||
READ_INT_FIELD(typmod);
|
||||
|
||||
READ_DONE();
|
||||
}
|
||||
|
||||
/*
|
||||
* _readJsonValueExpr
|
||||
*/
|
||||
static JsonValueExpr *
|
||||
_readJsonValueExpr(void)
|
||||
{
|
||||
READ_LOCALS(JsonValueExpr);
|
||||
|
||||
READ_NODE_FIELD(raw_expr);
|
||||
READ_NODE_FIELD(formatted_expr);
|
||||
READ_NODE_FIELD(format);
|
||||
|
||||
READ_DONE();
|
||||
}
|
||||
|
||||
/*
|
||||
* Stuff from pathnodes.h.
|
||||
*
|
||||
@@ -2974,6 +3019,12 @@ parseNodeString(void)
|
||||
return_value = _readPartitionBoundSpec();
|
||||
else if (MATCH("PARTITIONRANGEDATUM", 19))
|
||||
return_value = _readPartitionRangeDatum();
|
||||
else if (MATCH("JSONFORMAT", 10))
|
||||
return_value = _readJsonFormat();
|
||||
else if (MATCH("JSONRETURNING", 13))
|
||||
return_value = _readJsonReturning();
|
||||
else if (MATCH("JSONVALUEEXPR", 13))
|
||||
return_value = _readJsonValueExpr();
|
||||
else
|
||||
{
|
||||
elog(ERROR, "badly formatted node string \"%.32s\"...", token);
|
||||
|
||||
Reference in New Issue
Block a user