From d11a1dc0e8dc8d4838ca81fe8d4aa935cc1ed2df Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Thu, 14 May 2026 13:40:00 +0900 Subject: [PATCH] Re-add regression tests for ltree and intarray These tests have been removed by 906ea101d0d5, due to some of them being unstable in the buildfarm with low max_stack_depth values. These tests are reworked to be more portable. The tests to cover the findoprnd() overflows use a balanced tree to avoid using too much stack, per a suggestion by Tom Lane. Backpatch-through: 14 --- contrib/intarray/expected/_int.out | 15 +++++++++++++++ contrib/intarray/sql/_int.sql | 13 +++++++++++++ contrib/ltree/expected/ltree.out | 24 ++++++++++++++++++++++++ contrib/ltree/sql/ltree.sql | 20 ++++++++++++++++++++ 4 files changed, 72 insertions(+) diff --git a/contrib/intarray/expected/_int.out b/contrib/intarray/expected/_int.out index d0e68d0447fb..fb4086a95caf 100644 --- a/contrib/intarray/expected/_int.out +++ b/contrib/intarray/expected/_int.out @@ -398,6 +398,21 @@ SELECT '1&(2&(4&(5|!6)))'::query_int; 1 & 2 & 4 & ( 5 | !6 ) (1 row) +-- Test for overflow of the int16 "left" field in findoprnd(). +-- This query uses a balanced binary tree to avoid using too much stack. +DO $$ +DECLARE + e text := '1'; +BEGIN + FOR i IN 1..15 LOOP + e := '(' || e || '&' || e || ')'; + END LOOP; + PERFORM ('0|' || e)::query_int; +END; +$$; +ERROR: query_int expression is too complex +CONTEXT: SQL statement "SELECT ('0|' || e)::query_int" +PL/pgSQL function inline_code_block line 8 at PERFORM -- test non-error-throwing input SELECT str as "query_int", pg_input_is_valid(str,'query_int') as ok, diff --git a/contrib/intarray/sql/_int.sql b/contrib/intarray/sql/_int.sql index 5668ab407045..0d30914725e1 100644 --- a/contrib/intarray/sql/_int.sql +++ b/contrib/intarray/sql/_int.sql @@ -75,6 +75,19 @@ SELECT '1&2&4&5&6'::query_int; SELECT '1&(2&(4&(5|6)))'::query_int; SELECT '1&(2&(4&(5|!6)))'::query_int; +-- Test for overflow of the int16 "left" field in findoprnd(). +-- This query uses a balanced binary tree to avoid using too much stack. +DO $$ +DECLARE + e text := '1'; +BEGIN + FOR i IN 1..15 LOOP + e := '(' || e || '&' || e || ')'; + END LOOP; + PERFORM ('0|' || e)::query_int; +END; +$$; + -- test non-error-throwing input SELECT str as "query_int", diff --git a/contrib/ltree/expected/ltree.out b/contrib/ltree/expected/ltree.out index d2a566284755..15b9131a7506 100644 --- a/contrib/ltree/expected/ltree.out +++ b/contrib/ltree/expected/ltree.out @@ -1283,6 +1283,21 @@ SELECT 'tree.awdfg_qwerty'::ltree @ 'tree & aw_rw%*'::ltxtquery; f (1 row) +-- Test for overflow of the int16 "left" field in findoprnd(). +-- This query uses a balanced binary tree to avoid using too much stack. +DO $$ +DECLARE + e text := 'a'; +BEGIN + FOR i IN 1..14 LOOP + e := '(' || e || '&' || e || ')'; + END LOOP; + PERFORM ('b|' || e)::ltxtquery; +END; +$$; +ERROR: ltxtquery is too large +CONTEXT: SQL statement "SELECT ('b|' || e)::ltxtquery" +PL/pgSQL function inline_code_block line 8 at PERFORM --arrays SELECT '{1.2.3}'::ltree[] @> '1.2.3.4'; ?column? @@ -8202,3 +8217,12 @@ FROM (VALUES ('.2.3', 'ltree'), !tree & aWdf@* | ltxtquery | t | | | | (8 rows) +-- Test for overflow of lquery_level.totallen. +SELECT (repeat('x', 255) || repeat('|' || repeat('x', 255), 256))::lquery; +ERROR: lquery level is too large +DETAIL: Total size of level exceeds the maximum allowed (65535 bytes). +--- Test for overflow of lquery_level.numvar, with a set of single-char +--- variants in one level. +SELECT (repeat('a|', 65535) || 'a')::lquery; +ERROR: lquery level has too many variants +DETAIL: Number of variants exceeds the maximum allowed (65535). diff --git a/contrib/ltree/sql/ltree.sql b/contrib/ltree/sql/ltree.sql index 77e6958c62a7..d0fade9d17d8 100644 --- a/contrib/ltree/sql/ltree.sql +++ b/contrib/ltree/sql/ltree.sql @@ -253,6 +253,19 @@ SELECT 'tree.awdfg'::ltree @ 'tree & aWdfg@'::ltxtquery; SELECT 'tree.awdfg_qwerty'::ltree @ 'tree & aw_qw%*'::ltxtquery; SELECT 'tree.awdfg_qwerty'::ltree @ 'tree & aw_rw%*'::ltxtquery; +-- Test for overflow of the int16 "left" field in findoprnd(). +-- This query uses a balanced binary tree to avoid using too much stack. +DO $$ +DECLARE + e text := 'a'; +BEGIN + FOR i IN 1..14 LOOP + e := '(' || e || '&' || e || ')'; + END LOOP; + PERFORM ('b|' || e)::ltxtquery; +END; +$$; + --arrays SELECT '{1.2.3}'::ltree[] @> '1.2.3.4'; @@ -457,3 +470,10 @@ FROM (VALUES ('.2.3', 'ltree'), ('!tree & aWdf@*','ltxtquery')) AS a(str,typ), LATERAL pg_input_error_info(a.str, a.typ) as errinfo; + +-- Test for overflow of lquery_level.totallen. +SELECT (repeat('x', 255) || repeat('|' || repeat('x', 255), 256))::lquery; + +--- Test for overflow of lquery_level.numvar, with a set of single-char +--- variants in one level. +SELECT (repeat('a|', 65535) || 'a')::lquery; -- 2.54.0