Skip to content

Commit 1e4b038

Browse files
committed
Improve behavior of WITH RECURSIVE with an untyped literal in the
non-recursive term. Per an example from Dickson S. Guedes.
1 parent 0814250 commit 1e4b038

File tree

3 files changed

+56
-5
lines changed

3 files changed

+56
-5
lines changed

src/backend/parser/parse_cte.c

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_cte.c,v 2.1 2008/10/04 21:56:54 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_cte.c,v 2.2 2008/10/05 22:50:55 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
1515
#include "postgres.h"
1616

17+
#include "catalog/pg_type.h"
1718
#include "nodes/nodeFuncs.h"
1819
#include "parser/analyze.h"
1920
#include "parser/parse_cte.h"
@@ -339,6 +340,8 @@ analyzeCTETargetList(ParseState *pstate, CommonTableExpr *cte, List *tlist)
339340
foreach(tlistitem, tlist)
340341
{
341342
TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
343+
Oid coltype;
344+
int32 coltypmod;
342345

343346
if (te->resjunk)
344347
continue;
@@ -351,10 +354,23 @@ analyzeCTETargetList(ParseState *pstate, CommonTableExpr *cte, List *tlist)
351354
attrname = pstrdup(te->resname);
352355
cte->ctecolnames = lappend(cte->ctecolnames, makeString(attrname));
353356
}
354-
cte->ctecoltypes = lappend_oid(cte->ctecoltypes,
355-
exprType((Node *) te->expr));
356-
cte->ctecoltypmods = lappend_int(cte->ctecoltypmods,
357-
exprTypmod((Node *) te->expr));
357+
coltype = exprType((Node *) te->expr);
358+
coltypmod = exprTypmod((Node *) te->expr);
359+
/*
360+
* If the CTE is recursive, force the exposed column type of any
361+
* "unknown" column to "text". This corresponds to the fact that
362+
* SELECT 'foo' UNION SELECT 'bar' will ultimately produce text.
363+
* We might see "unknown" as a result of an untyped literal in
364+
* the non-recursive term's select list, and if we don't convert
365+
* to text then we'll have a mismatch against the UNION result.
366+
*/
367+
if (cte->cterecursive && coltype == UNKNOWNOID)
368+
{
369+
coltype = TEXTOID;
370+
coltypmod = -1; /* should be -1 already, but be sure */
371+
}
372+
cte->ctecoltypes = lappend_oid(cte->ctecoltypes, coltype);
373+
cte->ctecoltypmods = lappend_int(cte->ctecoltypmods, coltypmod);
358374
}
359375
if (varattno < numaliases)
360376
ereport(ERROR,

src/test/regress/expected/with.out

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,30 @@ SELECT * FROM t LIMIT 10;
6969
10
7070
(10 rows)
7171

72+
-- Test behavior with an unknown-type literal in the WITH
73+
WITH q AS (SELECT 'foo' AS x)
74+
SELECT x, x IS OF (unknown) as is_unknown FROM q;
75+
x | is_unknown
76+
-----+------------
77+
foo | t
78+
(1 row)
79+
80+
WITH RECURSIVE t(n) AS (
81+
SELECT 'foo'
82+
UNION ALL
83+
SELECT n || ' bar' FROM t WHERE length(n) < 20
84+
)
85+
SELECT n, n IS OF (text) as is_text FROM t;
86+
n | is_text
87+
-------------------------+---------
88+
foo | t
89+
foo bar | t
90+
foo bar bar | t
91+
foo bar bar bar | t
92+
foo bar bar bar bar | t
93+
foo bar bar bar bar bar | t
94+
(6 rows)
95+
7296
--
7397
-- Some examples with a tree
7498
--

src/test/regress/sql/with.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ UNION ALL
3838
SELECT n+1 FROM t)
3939
SELECT * FROM t LIMIT 10;
4040

41+
-- Test behavior with an unknown-type literal in the WITH
42+
WITH q AS (SELECT 'foo' AS x)
43+
SELECT x, x IS OF (unknown) as is_unknown FROM q;
44+
45+
WITH RECURSIVE t(n) AS (
46+
SELECT 'foo'
47+
UNION ALL
48+
SELECT n || ' bar' FROM t WHERE length(n) < 20
49+
)
50+
SELECT n, n IS OF (text) as is_text FROM t;
51+
4152
--
4253
-- Some examples with a tree
4354
--

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy