BUG #19767: pg_get_viewdef prints ORDER BY (- '3'::int4) as (- 3), which reparses as column position -3

From: PG Bug reporting form <noreply(at)postgresql(dot)org>
To: pgsql-bugs(at)lists(dot)postgresql(dot)org
Cc: alpkeles99(at)gmail(dot)com
Subject: BUG #19767: pg_get_viewdef prints ORDER BY (- '3'::int4) as (- 3), which reparses as column position -3
Date: 2026-10-16 15:59:56
Message-ID: 19767-f1189fd6a83254b7@postgresql.org
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

The following bug has been logged on the website:

Bug reference: 19767
Logged by: Alperen Keles
Email address: alpkeles99(at)gmail(dot)com
PostgreSQL version: 18.6
Operating system: Ubuntu 24.04 x86_64 (also macOS 26 arm64)
Description:

Hello,

In ORDER BY and GROUP BY, a bare integer constant is a column position
(ORDER BY 2), while "ORDER BY (- '3'::int4)" is an expression, the negation
of a typed literal, so it sorts by a constant -3.

pg_get_viewdef() prints that term as "(- 3)". When that text is parsed
again, the grammar folds "- 3" into the integer constant -3 (doNegate),
which ORDER BY then reads as a column position. So the printed
definition of a valid view is not a valid view, and pg_dump, which
prints views the same way, writes a dump that does not restore.

```
CREATE TABLE t (a int);
INSERT INTO t VALUES (1), (2);
CREATE VIEW o AS SELECT a FROM t ORDER BY (- '3'::int4);
CREATE VIEW g AS SELECT count(*) AS n FROM t GROUP BY (- '3'::int4);
SELECT * FROM o; -- 1, 2
SELECT * FROM g; -- 2

SELECT pg_get_viewdef('o'::regclass);
SELECT a
FROM t
ORDER BY (- 3);
SELECT pg_get_viewdef('g'::regclass);
SELECT count(*) AS n
FROM t
GROUP BY (- 3);
```

Creating each view again from its own printed definition fails:

```
CREATE VIEW o2 AS SELECT a FROM t ORDER BY (- 3);
ERROR: ORDER BY position -3 is not in select list
CREATE VIEW g2 AS SELECT count(*) AS n FROM t GROUP BY (- 3);
ERROR: GROUP BY position -3 is not in select list
```

That is what happens on restore: pg_dump of that database writes
```
CREATE VIEW public.o AS
SELECT a
FROM public.t
ORDER BY (- 3);
```

and restoring it with psql into an empty database gives
```
psql:dump.sql:44: ERROR: ORDER BY position -3 is not in select list
psql:dump.sql:67: ERROR: GROUP BY position -3 is not in select list
```

followed by "relation does not exist" for the views' ALTER OWNER and for
a view built on top of o, so those views are lost. pg_restore of a -Fc
dump fails the same way.

When the folded constant is a position that exists, the text silently
means something else. "- (- '1'::int4)" prints as "(- (- 1))", which
folds to 1:
```
CREATE TABLE t2 (a int, b int);
INSERT INTO t2 VALUES (1, 10), (2, 20), (1, 30);
CREATE VIEW v AS SELECT DISTINCT ON (- (- '1'::int4)) a, b FROM t2
ORDER BY - (- '1'::int4), b DESC;
SELECT * FROM v; -- one row: (1,30)
```

Its definition, run again (or restored from a dump), becomes
DISTINCT ON (a) ... ORDER BY a, b DESC and returns (1,30) and (2,20).

Reproduced on 18.6 (REL_18_STABLE dfbc1507cdb), 19rc1 (REL_19_STABLE
1212d5d33b1), 14.24 (REL_14_STABLE 14904052e65) and master a261fc2b722,
Ubuntu 24.04 x86_64, --enable-cassert, with pg_dump of the same version;
also on 18.6 and master on macOS arm64.

Found with a query fuzzer.

Regards,
Alperen Keles

Browse pgsql-bugs by date

  From Date Subject
Previous Message PG Bug reporting form 2026-10-16 15:24:16 BUG #19766: Assert in shm_toc_insert: EXPLAIN ANALYZE of a SubPlan shared by Parallel Append children