Skip to content

Commit

Permalink
Common SQL/JSON clauses
Browse files Browse the repository at this point in the history
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,
Himanshu Upadhyaya, Daniel Gustafsson, Justin Pryzby.

Discussion: https://postgr.es/m/[email protected]
  • Loading branch information
adunstan committed Mar 27, 2022
1 parent b64c3bd commit f79b803
Show file tree
Hide file tree
Showing 17 changed files with 758 additions and 2 deletions.
22 changes: 22 additions & 0 deletions src/backend/executor/execExpr.c
Original file line number Diff line number Diff line change
Expand Up @@ -2428,6 +2428,28 @@ ExecInitExprRec(Expr *node, ExprState *state,
break;
}

case T_JsonValueExpr:
{
JsonValueExpr *jve = (JsonValueExpr *) node;

ExecInitExprRec(jve->raw_expr, state, resv, resnull);

if (jve->formatted_expr)
{
Datum *innermost_caseval = state->innermost_caseval;
bool *innermost_isnull = state->innermost_casenull;

state->innermost_caseval = resv;
state->innermost_casenull = resnull;

ExecInitExprRec(jve->formatted_expr, state, resv, resnull);

state->innermost_caseval = innermost_caseval;
state->innermost_casenull = innermost_isnull;
}
break;
}

default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(node));
Expand Down
55 changes: 55 additions & 0 deletions src/backend/nodes/copyfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -5351,6 +5397,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
Expand Down
39 changes: 39 additions & 0 deletions src/backend/nodes/equalfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -3359,6 +3389,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
Expand Down
54 changes: 54 additions & 0 deletions src/backend/nodes/makefuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"


Expand Down Expand Up @@ -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;
}
66 changes: 66 additions & 0 deletions src/backend/nodes/nodeFuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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:
{
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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));
Expand Down
39 changes: 39 additions & 0 deletions src/backend/nodes/outfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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:

Expand Down
Loading

0 comments on commit f79b803

Please sign in to comment.