cxt.pathNameId = 0;
+ /*
+ * Collect the user-supplied path and column names, checking that they are
+ * distinct. If the row pattern path has an explicit name, it shares this
+ * namespace, so seed the list with it.
+ */
+ if (rootPathSpec->name != NULL)
+ cxt.pathNames = list_make1(rootPathSpec->name);
+ CheckDuplicateColumnOrPathNames(&cxt, jt->columns);
+
/*
* Generate a name for the row pattern path if it was not given one. Path
* names are optional for every path, including when a PLAN clause is
* present; a specific PLAN() can only reference named paths, so an
* unnamed path that the plan must mention is caught later as a path name
- * mismatch or a path not covered by the plan.
+ * mismatch or a path not covered by the plan. We generate the name only
+ * after collecting the user-supplied names above, so that it cannot
+ * collide with any of them.
*/
if (rootPathSpec->name == NULL)
rootPathSpec->name = generateJsonTablePathName(&cxt);
- cxt.pathNames = list_make1(rootPathSpec->name);
- CheckDuplicateColumnOrPathNames(&cxt, jt->columns);
-
/*
* We make lateral_only names of this level visible, whether or not the
* RangeTableFunc is explicitly marked LATERAL. This is needed for SQL
generateJsonTablePathName(JsonTableParseContext *cxt)
{
char namebuf[32];
- char *name = namebuf;
+ char *name;
- snprintf(namebuf, sizeof(namebuf), "json_table_path_%d",
- cxt->pathNameId++);
+ /*
+ * Bump the counter until we produce a name that is not already used as a
+ * path or column name. Otherwise a generated name could coincide with a
+ * user-supplied one, which would confuse PLAN clause matching and could
+ * silently drop a column.
+ */
+ do
+ {
+ snprintf(namebuf, sizeof(namebuf), "json_table_path_%d",
+ cxt->pathNameId++);
+ } while (LookupPathOrColumnName(cxt, namebuf));
- name = pstrdup(name);
+ name = pstrdup(namebuf);
cxt->pathNames = lappend(cxt->pathNames, name);
return name;
LINE 12: PLAN ((p1 INNER (p12 CROSS p11)) CROSS (p2 INNER p21)...
^
DETAIL: Expected INNER or OUTER.
+-- An unnamed NESTED path whose generated name would clash with a
+-- user-supplied path name must not silently drop columns: the generated
+-- name is made unique, so the still-uncovered path is reported instead.
+SELECT * FROM JSON_TABLE(
+ jsonb '[{"x":[1],"y":[2]}]', '$[*]' AS p0
+ COLUMNS (
+ NESTED PATH '$.x[*]' AS json_table_path_0 COLUMNS (x int PATH '$'),
+ NESTED PATH '$.y[*]' COLUMNS (y int PATH '$')
+ )
+ PLAN (p0 OUTER json_table_path_0)
+) jt;
+ERROR: invalid JSON_TABLE specification
+LINE 5: NESTED PATH '$.y[*]' COLUMNS (y int PATH '$')
+ ^
+DETAIL: PLAN clause for nested path json_table_path_1 was not found.
+-- A user-supplied name matching the pattern of generated path names must not
+-- trigger a spurious duplicate-name error: the unnamed row pattern path is
+-- named only after the user-supplied names are collected, so its generated
+-- name avoids them.
+SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (json_table_path_0 int PATH '$')) jt;
+ json_table_path_0
+-------------------
+ 1
+(1 row)
+
-- JSON_TABLE: plan execution
CREATE TEMP TABLE jsonb_table_test (js jsonb);
INSERT INTO jsonb_table_test
PLAN ((p1 INNER (p12 CROSS p11)) CROSS (p2 INNER p21))
) jt;
+-- An unnamed NESTED path whose generated name would clash with a
+-- user-supplied path name must not silently drop columns: the generated
+-- name is made unique, so the still-uncovered path is reported instead.
+SELECT * FROM JSON_TABLE(
+ jsonb '[{"x":[1],"y":[2]}]', '$[*]' AS p0
+ COLUMNS (
+ NESTED PATH '$.x[*]' AS json_table_path_0 COLUMNS (x int PATH '$'),
+ NESTED PATH '$.y[*]' COLUMNS (y int PATH '$')
+ )
+ PLAN (p0 OUTER json_table_path_0)
+) jt;
+
+-- A user-supplied name matching the pattern of generated path names must not
+-- trigger a spurious duplicate-name error: the unnamed row pattern path is
+-- named only after the user-supplied names are collected, so its generated
+-- name avoids them.
+SELECT * FROM JSON_TABLE(jsonb '1', '$' COLUMNS (json_table_path_0 int PATH '$')) jt;
+
-- JSON_TABLE: plan execution
CREATE TEMP TABLE jsonb_table_test (js jsonb);