mirror of
https://github.com/postgres/postgres.git
synced 2025-11-10 17:42:29 +03:00
JSON_TABLE
This feature allows jsonb data to be treated as a table and thus used in a FROM clause like other tabular data. Data can be selected from the jsonb using jsonpath expressions, and hoisted out of nested structures in the jsonb to form multiple rows, more or less like an outer join. Nikita Glukhov Reviewers have included (in no particular order) Andres Freund, Alexander Korotkov, Pavel Stehule, Andrew Alsup, Erik Rijkers, Zhihong Yu (whose name I previously misspelled), Himanshu Upadhyaya, Daniel Gustafsson, Justin Pryzby. Discussion: https://postgr.es/m/7e2cb85d-24cf-4abb-30a5-1a33715959bd@postgrespro.ru
This commit is contained in:
@@ -1394,6 +1394,7 @@ _copyTableFunc(const TableFunc *from)
|
||||
{
|
||||
TableFunc *newnode = makeNode(TableFunc);
|
||||
|
||||
COPY_SCALAR_FIELD(functype);
|
||||
COPY_NODE_FIELD(ns_uris);
|
||||
COPY_NODE_FIELD(ns_names);
|
||||
COPY_NODE_FIELD(docexpr);
|
||||
@@ -1404,7 +1405,9 @@ _copyTableFunc(const TableFunc *from)
|
||||
COPY_NODE_FIELD(colcollations);
|
||||
COPY_NODE_FIELD(colexprs);
|
||||
COPY_NODE_FIELD(coldefexprs);
|
||||
COPY_NODE_FIELD(colvalexprs);
|
||||
COPY_BITMAPSET_FIELD(notnulls);
|
||||
COPY_NODE_FIELD(plan);
|
||||
COPY_SCALAR_FIELD(ordinalitycol);
|
||||
COPY_LOCATION_FIELD(location);
|
||||
|
||||
@@ -2683,6 +2686,76 @@ _copyJsonArgument(const JsonArgument *from)
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyJsonTable
|
||||
*/
|
||||
static JsonTable *
|
||||
_copyJsonTable(const JsonTable *from)
|
||||
{
|
||||
JsonTable *newnode = makeNode(JsonTable);
|
||||
|
||||
COPY_NODE_FIELD(common);
|
||||
COPY_NODE_FIELD(columns);
|
||||
COPY_NODE_FIELD(on_error);
|
||||
COPY_NODE_FIELD(alias);
|
||||
COPY_SCALAR_FIELD(location);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyJsonTableColumn
|
||||
*/
|
||||
static JsonTableColumn *
|
||||
_copyJsonTableColumn(const JsonTableColumn *from)
|
||||
{
|
||||
JsonTableColumn *newnode = makeNode(JsonTableColumn);
|
||||
|
||||
COPY_SCALAR_FIELD(coltype);
|
||||
COPY_STRING_FIELD(name);
|
||||
COPY_NODE_FIELD(typeName);
|
||||
COPY_STRING_FIELD(pathspec);
|
||||
COPY_SCALAR_FIELD(format);
|
||||
COPY_SCALAR_FIELD(wrapper);
|
||||
COPY_SCALAR_FIELD(omit_quotes);
|
||||
COPY_NODE_FIELD(columns);
|
||||
COPY_NODE_FIELD(on_empty);
|
||||
COPY_NODE_FIELD(on_error);
|
||||
COPY_SCALAR_FIELD(location);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyJsonTableParent
|
||||
*/
|
||||
static JsonTableParent *
|
||||
_copyJsonTableParent(const JsonTableParent *from)
|
||||
{
|
||||
JsonTableParent *newnode = makeNode(JsonTableParent);
|
||||
|
||||
COPY_NODE_FIELD(path);
|
||||
COPY_NODE_FIELD(child);
|
||||
COPY_SCALAR_FIELD(colMin);
|
||||
COPY_SCALAR_FIELD(colMax);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyJsonTableSibling
|
||||
*/
|
||||
static JsonTableSibling *
|
||||
_copyJsonTableSibling(const JsonTableSibling *from)
|
||||
{
|
||||
JsonTableSibling *newnode = makeNode(JsonTableSibling);
|
||||
|
||||
COPY_NODE_FIELD(larg);
|
||||
COPY_NODE_FIELD(rarg);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/* ****************************************************************
|
||||
* pathnodes.h copy functions
|
||||
*
|
||||
@@ -5850,6 +5923,18 @@ copyObjectImpl(const void *from)
|
||||
case T_JsonItemCoercions:
|
||||
retval = _copyJsonItemCoercions(from);
|
||||
break;
|
||||
case T_JsonTable:
|
||||
retval = _copyJsonTable(from);
|
||||
break;
|
||||
case T_JsonTableColumn:
|
||||
retval = _copyJsonTableColumn(from);
|
||||
break;
|
||||
case T_JsonTableParent:
|
||||
retval = _copyJsonTableParent(from);
|
||||
break;
|
||||
case T_JsonTableSibling:
|
||||
retval = _copyJsonTableSibling(from);
|
||||
break;
|
||||
|
||||
/*
|
||||
* RELATION NODES
|
||||
|
||||
@@ -127,6 +127,7 @@ _equalRangeVar(const RangeVar *a, const RangeVar *b)
|
||||
static bool
|
||||
_equalTableFunc(const TableFunc *a, const TableFunc *b)
|
||||
{
|
||||
COMPARE_SCALAR_FIELD(functype);
|
||||
COMPARE_NODE_FIELD(ns_uris);
|
||||
COMPARE_NODE_FIELD(ns_names);
|
||||
COMPARE_NODE_FIELD(docexpr);
|
||||
@@ -137,13 +138,65 @@ _equalTableFunc(const TableFunc *a, const TableFunc *b)
|
||||
COMPARE_NODE_FIELD(colcollations);
|
||||
COMPARE_NODE_FIELD(colexprs);
|
||||
COMPARE_NODE_FIELD(coldefexprs);
|
||||
COMPARE_NODE_FIELD(colvalexprs);
|
||||
COMPARE_BITMAPSET_FIELD(notnulls);
|
||||
COMPARE_NODE_FIELD(plan);
|
||||
COMPARE_SCALAR_FIELD(ordinalitycol);
|
||||
COMPARE_LOCATION_FIELD(location);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalJsonTable(const JsonTable *a, const JsonTable *b)
|
||||
{
|
||||
COMPARE_NODE_FIELD(common);
|
||||
COMPARE_NODE_FIELD(columns);
|
||||
COMPARE_NODE_FIELD(on_error);
|
||||
COMPARE_NODE_FIELD(alias);
|
||||
COMPARE_SCALAR_FIELD(location);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalJsonTableColumn(const JsonTableColumn *a, const JsonTableColumn *b)
|
||||
{
|
||||
COMPARE_SCALAR_FIELD(coltype);
|
||||
COMPARE_STRING_FIELD(name);
|
||||
COMPARE_NODE_FIELD(typeName);
|
||||
COMPARE_STRING_FIELD(pathspec);
|
||||
COMPARE_SCALAR_FIELD(format);
|
||||
COMPARE_SCALAR_FIELD(wrapper);
|
||||
COMPARE_SCALAR_FIELD(omit_quotes);
|
||||
COMPARE_NODE_FIELD(columns);
|
||||
COMPARE_NODE_FIELD(on_empty);
|
||||
COMPARE_NODE_FIELD(on_error);
|
||||
COMPARE_SCALAR_FIELD(location);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalJsonTableParent(const JsonTableParent *a, const JsonTableParent *b)
|
||||
{
|
||||
COMPARE_NODE_FIELD(path);
|
||||
COMPARE_NODE_FIELD(child);
|
||||
COMPARE_SCALAR_FIELD(colMin);
|
||||
COMPARE_SCALAR_FIELD(colMax);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalJsonTableSibling(const JsonTableSibling *a, const JsonTableSibling *b)
|
||||
{
|
||||
COMPARE_NODE_FIELD(larg);
|
||||
COMPARE_NODE_FIELD(rarg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalIntoClause(const IntoClause *a, const IntoClause *b)
|
||||
{
|
||||
@@ -3719,6 +3772,12 @@ equal(const void *a, const void *b)
|
||||
case T_JsonItemCoercions:
|
||||
retval = _equalJsonItemCoercions(a, b);
|
||||
break;
|
||||
case T_JsonTableParent:
|
||||
retval = _equalJsonTableParent(a, b);
|
||||
break;
|
||||
case T_JsonTableSibling:
|
||||
retval = _equalJsonTableSibling(a, b);
|
||||
break;
|
||||
|
||||
/*
|
||||
* RELATION NODES
|
||||
@@ -4341,6 +4400,12 @@ equal(const void *a, const void *b)
|
||||
case T_JsonArgument:
|
||||
retval = _equalJsonArgument(a, b);
|
||||
break;
|
||||
case T_JsonTable:
|
||||
retval = _equalJsonTable(a, b);
|
||||
break;
|
||||
case T_JsonTableColumn:
|
||||
retval = _equalJsonTableColumn(a, b);
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d",
|
||||
|
||||
@@ -2466,6 +2466,8 @@ expression_tree_walker(Node *node,
|
||||
return true;
|
||||
if (walker(tf->coldefexprs, context))
|
||||
return true;
|
||||
if (walker(tf->colvalexprs, context))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case T_JsonValueExpr:
|
||||
@@ -3513,6 +3515,7 @@ expression_tree_mutator(Node *node,
|
||||
MUTATE(newnode->rowexpr, tf->rowexpr, Node *);
|
||||
MUTATE(newnode->colexprs, tf->colexprs, List *);
|
||||
MUTATE(newnode->coldefexprs, tf->coldefexprs, List *);
|
||||
MUTATE(newnode->colvalexprs, tf->colvalexprs, List *);
|
||||
return (Node *) newnode;
|
||||
}
|
||||
break;
|
||||
@@ -4530,6 +4533,30 @@ raw_expression_tree_walker(Node *node,
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case T_JsonTable:
|
||||
{
|
||||
JsonTable *jt = (JsonTable *) node;
|
||||
|
||||
if (walker(jt->common, context))
|
||||
return true;
|
||||
if (walker(jt->columns, context))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case T_JsonTableColumn:
|
||||
{
|
||||
JsonTableColumn *jtc = (JsonTableColumn *) node;
|
||||
|
||||
if (walker(jtc->typeName, context))
|
||||
return true;
|
||||
if (walker(jtc->on_empty, context))
|
||||
return true;
|
||||
if (walker(jtc->on_error, context))
|
||||
return true;
|
||||
if (jtc->coltype == JTC_NESTED && walker(jtc->columns, context))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d",
|
||||
(int) nodeTag(node));
|
||||
|
||||
@@ -1092,6 +1092,7 @@ _outTableFunc(StringInfo str, const TableFunc *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("TABLEFUNC");
|
||||
|
||||
WRITE_ENUM_FIELD(functype, TableFuncType);
|
||||
WRITE_NODE_FIELD(ns_uris);
|
||||
WRITE_NODE_FIELD(ns_names);
|
||||
WRITE_NODE_FIELD(docexpr);
|
||||
@@ -1102,7 +1103,9 @@ _outTableFunc(StringInfo str, const TableFunc *node)
|
||||
WRITE_NODE_FIELD(colcollations);
|
||||
WRITE_NODE_FIELD(colexprs);
|
||||
WRITE_NODE_FIELD(coldefexprs);
|
||||
WRITE_NODE_FIELD(colvalexprs);
|
||||
WRITE_BITMAPSET_FIELD(notnulls);
|
||||
WRITE_NODE_FIELD(plan);
|
||||
WRITE_INT_FIELD(ordinalitycol);
|
||||
WRITE_LOCATION_FIELD(location);
|
||||
}
|
||||
@@ -1866,6 +1869,26 @@ _outJsonItemCoercions(StringInfo str, const JsonItemCoercions *node)
|
||||
WRITE_NODE_FIELD(composite);
|
||||
}
|
||||
|
||||
static void
|
||||
_outJsonTableParent(StringInfo str, const JsonTableParent *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("JSONTABPNODE");
|
||||
|
||||
WRITE_NODE_FIELD(path);
|
||||
WRITE_NODE_FIELD(child);
|
||||
WRITE_INT_FIELD(colMin);
|
||||
WRITE_INT_FIELD(colMax);
|
||||
}
|
||||
|
||||
static void
|
||||
_outJsonTableSibling(StringInfo str, const JsonTableSibling *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("JSONTABSNODE");
|
||||
|
||||
WRITE_NODE_FIELD(larg);
|
||||
WRITE_NODE_FIELD(rarg);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Stuff from pathnodes.h.
|
||||
@@ -4714,6 +4737,12 @@ outNode(StringInfo str, const void *obj)
|
||||
case T_JsonItemCoercions:
|
||||
_outJsonItemCoercions(str, obj);
|
||||
break;
|
||||
case T_JsonTableParent:
|
||||
_outJsonTableParent(str, obj);
|
||||
break;
|
||||
case T_JsonTableSibling:
|
||||
_outJsonTableSibling(str, obj);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
|
||||
@@ -571,6 +571,7 @@ _readTableFunc(void)
|
||||
{
|
||||
READ_LOCALS(TableFunc);
|
||||
|
||||
READ_ENUM_FIELD(functype, TableFuncType);
|
||||
READ_NODE_FIELD(ns_uris);
|
||||
READ_NODE_FIELD(ns_names);
|
||||
READ_NODE_FIELD(docexpr);
|
||||
@@ -581,7 +582,9 @@ _readTableFunc(void)
|
||||
READ_NODE_FIELD(colcollations);
|
||||
READ_NODE_FIELD(colexprs);
|
||||
READ_NODE_FIELD(coldefexprs);
|
||||
READ_NODE_FIELD(colvalexprs);
|
||||
READ_BITMAPSET_FIELD(notnulls);
|
||||
READ_NODE_FIELD(plan);
|
||||
READ_INT_FIELD(ordinalitycol);
|
||||
READ_LOCATION_FIELD(location);
|
||||
|
||||
@@ -1532,6 +1535,30 @@ _readJsonExpr(void)
|
||||
READ_DONE();
|
||||
}
|
||||
|
||||
static JsonTableParent *
|
||||
_readJsonTableParent(void)
|
||||
{
|
||||
READ_LOCALS(JsonTableParent);
|
||||
|
||||
READ_NODE_FIELD(path);
|
||||
READ_NODE_FIELD(child);
|
||||
READ_INT_FIELD(colMin);
|
||||
READ_INT_FIELD(colMax);
|
||||
|
||||
READ_DONE();
|
||||
}
|
||||
|
||||
static JsonTableSibling *
|
||||
_readJsonTableSibling(void)
|
||||
{
|
||||
READ_LOCALS(JsonTableSibling);
|
||||
|
||||
READ_NODE_FIELD(larg);
|
||||
READ_NODE_FIELD(rarg);
|
||||
|
||||
READ_DONE();
|
||||
}
|
||||
|
||||
/*
|
||||
* _readJsonCoercion
|
||||
*/
|
||||
@@ -3194,6 +3221,10 @@ parseNodeString(void)
|
||||
return_value = _readJsonCoercion();
|
||||
else if (MATCH("JSONITEMCOERCIONS", 17))
|
||||
return_value = _readJsonItemCoercions();
|
||||
else if (MATCH("JSONTABPNODE", 12))
|
||||
return_value = _readJsonTableParent();
|
||||
else if (MATCH("JSONTABSNODE", 12))
|
||||
return_value = _readJsonTableSibling();
|
||||
else
|
||||
{
|
||||
elog(ERROR, "badly formatted node string \"%.32s\"...", token);
|
||||
|
||||
Reference in New Issue
Block a user