]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Check column list length in XMLTABLE/JSON_TABLE alias
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Wed, 18 May 2022 18:28:31 +0000 (20:28 +0200)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Wed, 18 May 2022 18:28:31 +0000 (20:28 +0200)
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

src/backend/parser/parse_clause.c
src/backend/parser/parse_relation.c
src/test/regress/expected/int2.out
src/test/regress/expected/join.out
src/test/regress/expected/with.out
src/test/regress/expected/xml.out
src/test/regress/sql/int2.sql
src/test/regress/sql/join.sql
src/test/regress/sql/with.sql
src/test/regress/sql/xml.sql

index d6b93f55dfd51c192206e5f17610a097ec492f65..361c4c78864d2f5631bb80d29ec244a7cbab8e75 100644 (file)
@@ -1466,21 +1466,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
                 */
index bf5df26009a45b137c37089e7142283c01c7a224..1e3fe64d99081dd0b2b443b63a5995b3e6a4b87f 100644 (file)
@@ -1685,6 +1685,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;
 
        /*
@@ -1834,6 +1840,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;
 
        /*
index 3ea4ed93a0aad5819b0f660fd619b6fa2ea4183f..f740f17b4917d8b67105b6f1f5833f52a4df2c6a 100644 (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   
 ------+--------
index 5d6a609da07af8a025b212cfa05e6e5055d93c8b..8361324aa8cbbba1981bf718f0158d4171b82dfa 100644 (file)
@@ -5437,6 +5437,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
index 10ef7c7cce13a3488b1d5c8fdb13d5d1dd5f2487..1880013578b5d14f8c861eff7d16ff5565358878 100644 (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;
index 39058a007f19f9dd016a7b247cb09bcd67145c2a..3854c2331498c2127f46a716b5139e19da935f7c 100644 (file)
@@ -1148,6 +1148,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'
index 7dbafb6dacc815e9f96bd5b0a7fddf9cbe03cfa9..23339aee089d868eae2e9c5a98edcca3542f9da4 100644 (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';
index 2051bf59b54f18caca10f4887f9bea01cca99083..ff4eeb301665eb93df8c8f5958c0e66ed918e750 100644 (file)
@@ -1789,6 +1789,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
index b9242b7913c4abfd554bb44e47076e33ba2f339d..d4723ba44f0e6a8c83c4b6ed0a69c381b44d3723 100644 (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;
index 9af7cd7aeb7f0d0683b579ed2c5e494a5c39691c..2ad15c6a923b7467646108a699e640f4f04a5837 100644 (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'