Check column list length in XMLTABLE/JSON_TABLE alias

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
This commit is contained in:
Alvaro Herrera 2022-05-18 20:28:31 +02:00
parent 7e59b12191
commit ade17703de
No known key found for this signature in database
GPG Key ID: 1C20ACB9D5C564AE
10 changed files with 40 additions and 15 deletions

View File

@ -1426,21 +1426,6 @@ transformFromClauseItem(ParseState *pstate, Node *n,
res_colnames = list_concat(res_colnames, r_colnames);
res_colvars = list_concat(res_colvars, r_colvars);
/*
* 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 for the result of the join
*/

View File

@ -1731,6 +1731,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;
/*
@ -1882,6 +1888,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;
/*

View File

@ -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
------+--------

View File

@ -5618,6 +5618,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

View File

@ -956,6 +956,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;

View File

@ -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'

View File

@ -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';

View File

@ -1892,6 +1892,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

View File

@ -410,6 +410,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;

View File

@ -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'