Skip to content

Commit

Permalink
Check column list length in XMLTABLE/JSON_TABLE alias
Browse files Browse the repository at this point in the history
We weren't checking the length of the column list in the alias clause of
an XMLTABLE or JSON_TABLE function (a "tablefunc" RTE), and it was
possible to make the server crash by passing an overly long one.  Fix it
by throwing an error in that case, like the other places that deal with
alias lists.

In passing, modify the equivalent test used for join RTEs to look like
the other ones, which was different for no apparent reason.

This bug came in when XMLTABLE was born in version 10; backpatch to all
stable versions.

Reported-by: Wang Ke <krking@zju.edu.cn>
Discussion: https://postgr.es/m/17480-1c9d73565bb28e90@postgresql.org
  • Loading branch information
alvherre committed May 18, 2022
1 parent 2e9559b commit 80656f0
Show file tree
Hide file tree
Showing 10 changed files with 40 additions and 15 deletions.
15 changes: 0 additions & 15 deletions src/backend/parser/parse_clause.c
Expand Up @@ -1434,21 +1434,6 @@ transformFromClauseItem(ParseState *pstate, Node *n,
&res_colnames, &res_colvars,
res_nscolumns + res_colindex);

/*
* Check alias (AS clause), if any.
*/
if (j->alias)
{
if (j->alias->colnames != NIL)
{
if (list_length(j->alias->colnames) > list_length(res_colnames))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("column alias list for \"%s\" has too many entries",
j->alias->aliasname)));
}
}

/*
* Now build an RTE and nsitem for the result of the join.
* res_nscolumns isn't totally done yet, but that's OK because
Expand Down
12 changes: 12 additions & 0 deletions src/backend/parser/parse_relation.c
Expand Up @@ -1963,6 +1963,12 @@ addRangeTableEntryForTableFunc(ParseState *pstate,
eref->colnames = list_concat(eref->colnames,
list_copy_tail(tf->colnames, numaliases));

if (numaliases > list_length(tf->colnames))
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("%s function has %d columns available but %d columns specified",
"XMLTABLE", list_length(tf->colnames), numaliases)));

rte->eref = eref;

/*
Expand Down Expand Up @@ -2140,6 +2146,12 @@ addRangeTableEntryForJoin(ParseState *pstate,
eref->colnames = list_concat(eref->colnames,
list_copy_tail(colnames, numaliases));

if (numaliases > list_length(colnames))
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("join expression \"%s\" has %d columns available but %d columns specified",
eref->aliasname, list_length(colnames), numaliases)));

rte->eref = eref;

/*
Expand Down
4 changes: 4 additions & 0 deletions src/test/regress/expected/int2.out
Expand Up @@ -51,6 +51,10 @@ SELECT '' AS five, * FROM INT2_TBL;
| -32767
(5 rows)

SELECT * FROM INT2_TBL AS f(a, b);
ERROR: table "f" has 1 columns available but 2 columns specified
SELECT * FROM (TABLE int2_tbl) AS s (a, b);
ERROR: table "s" has 1 columns available but 2 columns specified
SELECT '' AS four, i.* FROM INT2_TBL i WHERE i.f1 <> int2 '0';
four | f1
------+--------
Expand Down
3 changes: 3 additions & 0 deletions src/test/regress/expected/join.out
Expand Up @@ -5788,6 +5788,9 @@ select * from
3 | 3
(6 rows)

-- check the number of columns specified
SELECT * FROM (int8_tbl i cross join int4_tbl j) ss(a,b,c,d);
ERROR: join expression "ss" has 3 columns available but 4 columns specified
-- check we don't try to do a unique-ified semijoin with LATERAL
explain (verbose, costs off)
select * from
Expand Down
5 changes: 5 additions & 0 deletions src/test/regress/expected/with.out
Expand Up @@ -1015,6 +1015,11 @@ DROP TABLE y;
--
-- error cases
--
WITH x(n, b) AS (SELECT 1)
SELECT * FROM x;
ERROR: WITH query "x" has 1 columns available but 2 columns specified
LINE 1: WITH x(n, b) AS (SELECT 1)
^
-- INTERSECT
WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT SELECT n+1 FROM x)
SELECT * FROM x;
Expand Down
3 changes: 3 additions & 0 deletions src/test/regress/expected/xml.out
Expand Up @@ -1145,6 +1145,9 @@ EXPLAIN (COSTS OFF, VERBOSE) SELECT * FROM xmltableview1;
Table Function Call: XMLTABLE(('/ROWS/ROW'::text) PASSING (xmldata.data) COLUMNS id integer PATH ('@id'::text), _id FOR ORDINALITY, country_name text PATH ('COUNTRY_NAME/text()'::text) NOT NULL, country_id text PATH ('COUNTRY_ID'::text), region_id integer PATH ('REGION_ID'::text), size double precision PATH ('SIZE'::text), unit text PATH ('SIZE/@unit'::text), premier_name text DEFAULT ('not specified'::text) PATH ('PREMIER_NAME'::text))
(7 rows)

-- errors
SELECT * FROM XMLTABLE (ROW () PASSING null COLUMNS v1 timestamp) AS f (v1, v2);
ERROR: XMLTABLE function has 1 columns available but 2 columns specified
-- XMLNAMESPACES tests
SELECT * FROM XMLTABLE(XMLNAMESPACES('http://x.y' AS zz),
'/zz:rows/zz:row'
Expand Down
4 changes: 4 additions & 0 deletions src/test/regress/sql/int2.sql
Expand Up @@ -29,6 +29,10 @@ INSERT INTO INT2_TBL(f1) VALUES ('');

SELECT '' AS five, * FROM INT2_TBL;

SELECT * FROM INT2_TBL AS f(a, b);

SELECT * FROM (TABLE int2_tbl) AS s (a, b);

SELECT '' AS four, i.* FROM INT2_TBL i WHERE i.f1 <> int2 '0';

SELECT '' AS four, i.* FROM INT2_TBL i WHERE i.f1 <> int4 '0';
Expand Down
3 changes: 3 additions & 0 deletions src/test/regress/sql/join.sql
Expand Up @@ -1971,6 +1971,9 @@ select * from
(select q1.v)
) as q2;

-- check the number of columns specified
SELECT * FROM (int8_tbl i cross join int4_tbl j) ss(a,b,c,d);

-- check we don't try to do a unique-ified semijoin with LATERAL
explain (verbose, costs off)
select * from
Expand Down
3 changes: 3 additions & 0 deletions src/test/regress/sql/with.sql
Expand Up @@ -454,6 +454,9 @@ DROP TABLE y;
-- error cases
--

WITH x(n, b) AS (SELECT 1)
SELECT * FROM x;

-- INTERSECT
WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT SELECT n+1 FROM x)
SELECT * FROM x;
Expand Down
3 changes: 3 additions & 0 deletions src/test/regress/sql/xml.sql
Expand Up @@ -384,6 +384,9 @@ SELECT * FROM xmltableview1;
EXPLAIN (COSTS OFF) SELECT * FROM xmltableview1;
EXPLAIN (COSTS OFF, VERBOSE) SELECT * FROM xmltableview1;

-- errors
SELECT * FROM XMLTABLE (ROW () PASSING null COLUMNS v1 timestamp) AS f (v1, v2);

-- XMLNAMESPACES tests
SELECT * FROM XMLTABLE(XMLNAMESPACES('http://x.y' AS zz),
'/zz:rows/zz:row'
Expand Down

0 comments on commit 80656f0

Please sign in to comment.