pg_get_viewdef() produces non-round-trippable SQL for views with USING join on mismatched integer types

From: Swirl Smog Dowry <swirl-smog-dowry(at)duck(dot)com>
To: pgsql-bugs(at)lists(dot)postgresql(dot)org
Subject: pg_get_viewdef() produces non-round-trippable SQL for views with USING join on mismatched integer types
Date: 2026-02-26 10:18:43
Message-ID: CA+-gibjCg_vjcq3hWTM0sLs3_TUZ6Q9rkv8+pe2yJrdh4o4uoQ@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

PostgreSQL version: 18.1 (also verified on 18.2)
OS: Linux

Description:
============
When a view uses a USING join on columns with different integer types
(integer vs
bigint) and the SELECT clause contains an explicit narrowing cast,
pg_get_viewdef()
produces SQL that PostgreSQL itself rejects. This makes pg_dump produce
dumps that
fail on restore for any such view.

The SELECT clause gets col::integer, while the GROUP BY gets (col::bigint)
— they
refer to the same underlying column but with different casts, so the GROUP
BY check
fails to recognise the SELECT expression as covered.

Minimal reproducer:
===================

CREATE TABLE t1 (year integer, val numeric);
CREATE TABLE t2 (year bigint, label text);
INSERT INTO t1 VALUES (2025, 100), (2025, 200), (2026, 300);
INSERT INTO t2 VALUES (2025, 'A'), (2026, 'B');

-- View creation succeeds and queries work fine:
CREATE VIEW v AS
SELECT year::integer AS year, t2.label, sum(val) AS total
FROM t1
LEFT JOIN t2 USING (year)
GROUP BY year, t2.label;

SELECT * FROM v; -- returns correct results

-- pg_get_viewdef output:
SELECT pg_get_viewdef('v'::regclass, true);

Output of pg_get_viewdef:
=========================

SELECT t1.year::integer AS year,
t2.label,
sum(t1.val) AS total
FROM t1
LEFT JOIN t2 USING (year)
GROUP BY (t1.year::bigint), t2.label;

Note: SELECT has t1.year::integer, GROUP BY has (t1.year::bigint).

Attempting to re-execute the pg_get_viewdef output fails:
=========================================================

CREATE VIEW v2 AS
SELECT t1.year::integer AS year,
t2.label,
sum(t1.val) AS total
FROM t1
LEFT JOIN t2 USING (year)
GROUP BY (t1.year::bigint), t2.label;

ERROR: column "t1.year" must appear in the GROUP BY clause or be used
in an aggregate function
LINE 2: SELECT t1.year::integer AS year,
^

Impact:
=======
pg_dump uses pg_get_viewdef() to serialise view definitions. Any database
containing such a view (USING join between integer and bigint columns, with
an explicit cast in SELECT) will produce a dump that fails during restore
with
the above error.

Without the explicit cast in SELECT (i.e. just SELECT year, ...)
pg_get_viewdef
emits t1.year::bigint in both SELECT and GROUP BY, and the round-trip works.
The bug is triggered specifically by the narrowing cast (bigint -> integer)
in
the SELECT list combined with a USING join.

Kind regards,

Swirl

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message Vik Fearing 2026-02-26 14:20:08 Re: BUG #19418: SQL/JSON JSON_VALUE() does not conform to ISO/IEC 9075-2:2023(E) 6.34 <JSON value constructor>
Previous Message PG Bug reporting form 2026-02-26 09:57:50 BUG #19418: SQL/JSON JSON_VALUE() does not conform to ISO/IEC 9075-2:2023(E) 6.34 <JSON value constructor>