]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix deparsing FETCH FIRST <expr> ROWS WITH TIES
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 19 May 2025 15:50:26 +0000 (18:50 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 19 May 2025 15:50:54 +0000 (18:50 +0300)
In the grammar, <expr> is a c_expr, which accepts only a limited set
of integer literals and simple expressions without parens. The
deparsing logic didn't quite match the grammar rule, and failed to use
parens e.g. for "5::bigint".

To fix, always surround the expression with parens. Would be nice to
omit the parens in simple cases, but unfortunately it's non-trivial to
detect such simple cases. Even if the expression is a simple literal
123 in the original query, after parse analysis it becomes a FuncExpr
with COERCE_IMPLICIT_CAST rather than a simple Const.

Reported-by: yonghao lee
Backpatch-through: 13
Discussion: https://www.postgresql.org/message-id/18929-077d6b7093b176e2@postgresql.org

src/backend/utils/adt/ruleutils.c
src/test/regress/expected/limit.out
src/test/regress/sql/limit.sql

index 55330047ccee7d5118b33627a56809d3651ad4e2..6c62d70e740a0c0c46f68182504db0968a858c9a 100644 (file)
@@ -5662,9 +5662,19 @@ get_select_query_def(Query *query, deparse_context *context,
        {
                if (query->limitOption == LIMIT_OPTION_WITH_TIES)
                {
+                       /*
+                        * The limitCount arg is a c_expr, so it needs parens. Simple
+                        * literals and function expressions would not need parens, but
+                        * unfortunately it's hard to tell if the expression will be
+                        * printed as a simple literal like 123 or as a typecast
+                        * expression, like '-123'::int4. The grammar accepts the former
+                        * without quoting, but not the latter.
+                        */
                        appendContextKeyword(context, " FETCH FIRST ",
                                                                 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
+                       appendStringInfoChar(buf, '(');
                        get_rule_expr(query->limitCount, context, false);
+                       appendStringInfoChar(buf, ')');
                        appendStringInfoString(buf, " ROWS WITH TIES");
                }
                else
index 8a98bbea8eb97ce6cc66526a106fda6210f1db24..d10c912d12e402a757105b8fc77587f843525085 100644 (file)
@@ -643,7 +643,7 @@ View definition:
   WHERE onek.thousand < 995
   ORDER BY onek.thousand
  OFFSET 10
- FETCH FIRST 5 ROWS WITH TIES;
+ FETCH FIRST (5) ROWS WITH TIES;
 
 CREATE VIEW limit_thousand_v_2 AS SELECT thousand FROM onek WHERE thousand < 995
                ORDER BY thousand OFFSET 10 FETCH FIRST 5 ROWS ONLY;
@@ -675,15 +675,29 @@ View definition:
    FROM onek
   WHERE onek.thousand < 995
   ORDER BY onek.thousand
- FETCH FIRST (NULL::integer + 1) ROWS WITH TIES;
+ FETCH FIRST ((NULL::integer + 1)) ROWS WITH TIES;
 
 CREATE VIEW limit_thousand_v_4 AS SELECT thousand FROM onek WHERE thousand < 995
-               ORDER BY thousand FETCH FIRST NULL ROWS ONLY;
+               ORDER BY thousand FETCH FIRST (5::bigint) ROWS WITH TIES;
 \d+ limit_thousand_v_4
                       View "public.limit_thousand_v_4"
   Column  |  Type   | Collation | Nullable | Default | Storage | Description 
 ----------+---------+-----------+----------+---------+---------+-------------
  thousand | integer |           |          |         | plain   | 
+View definition:
+ SELECT onek.thousand
+   FROM onek
+  WHERE onek.thousand < 995
+  ORDER BY onek.thousand
+ FETCH FIRST (5::bigint) ROWS WITH TIES;
+
+CREATE VIEW limit_thousand_v_5 AS SELECT thousand FROM onek WHERE thousand < 995
+               ORDER BY thousand FETCH FIRST NULL ROWS ONLY;
+\d+ limit_thousand_v_5
+                      View "public.limit_thousand_v_5"
+  Column  |  Type   | Collation | Nullable | Default | Storage | Description 
+----------+---------+-----------+----------+---------+---------+-------------
+ thousand | integer |           |          |         | plain   | 
 View definition:
  SELECT onek.thousand
    FROM onek
index 6f0cda98701559d13d620d68855f24a15914f0ba..603910fe6d11c10350a0f6e148a1f50b52504268 100644 (file)
@@ -196,6 +196,9 @@ CREATE VIEW limit_thousand_v_3 AS SELECT thousand FROM onek WHERE thousand < 995
                ORDER BY thousand FETCH FIRST (NULL+1) ROWS WITH TIES;
 \d+ limit_thousand_v_3
 CREATE VIEW limit_thousand_v_4 AS SELECT thousand FROM onek WHERE thousand < 995
-               ORDER BY thousand FETCH FIRST NULL ROWS ONLY;
+               ORDER BY thousand FETCH FIRST (5::bigint) ROWS WITH TIES;
 \d+ limit_thousand_v_4
+CREATE VIEW limit_thousand_v_5 AS SELECT thousand FROM onek WHERE thousand < 995
+               ORDER BY thousand FETCH FIRST NULL ROWS ONLY;
+\d+ limit_thousand_v_5
 -- leave these views