]> 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 2a6b2ff153bb3b784845b7d921ac06d5a0e85326..7e9216142a190a873b55448950065061c0717bdf 100644 (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
                 */
index 77a48b039d9994c96129fca2f05fb749831e791c..2643060bed7939493edc8c47bb78a6b547b487f5 100644 (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;
 
        /*
index 8c255b9e4dd499043f1b4518e45279557e33f0d2..ff8e76b5fe2151a63d48ae9fad130d76365a74d6 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 772028748be6cce77e9eec77e3a277c6d305d545..d2db9804e41f69711f9fc67c66bd33799e716f8f 100644 (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
index 98c8314c86f7789ed627b4837cc10b3134a0b48b..8f6545449bec95a3ebeff1f5fad7594457fdbd5b 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 55b65ef324d28de8d3fd55c6fe35058f2b865869..55ac49be261c3b6080ffc45b08b0b5f54e38a1f5 100644 (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'
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 fde993a17021548775e7f2c10656f49a4f710814..16c9b2e4322c33c1371ede3a7e0b041b6fc6bc23 100644 (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
index 4243903581d271cdc1e9cb4648fff98053704461..2edc53d878a388b5fcbd8e38131ded65452e2d91 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 f3f83c7827d1a724cb640fc134f49b38102f931c..e3f90db4d568d0b0d9a6029c6723b5d85568f621 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'