Re: BUG #8228: Unexpected "set-valued function" with varchar(n) but not varchar

From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: david(dot)g(dot)johnston(at)gmail(dot)com
Cc: pgsql-bugs(at)postgresql(dot)org
Subject: Re: BUG #8228: Unexpected "set-valued function" with varchar(n) but not varchar
Date: 2013-06-13 20:02:22
Message-ID: 16577.1371153742@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

david(dot)g(dot)johnston(at)gmail(dot)com writes:
> The following query results in "SQL Error: ERROR: set-valued function called
> in context that cannot accept a set"

> SELECT *, CASE WHEN id = 2 THEN
> (regexp_matches(input_string,'^0*([1-9]\d+)$'))[1] ELSE input_string
> END::varchar(30) AS o_l2_a
> FROM (
> VALUES (1,''), (2,'0000000049404'),(3,'FROM 10000000876')
> ) l0_src (id, input_string)

Hm, interesting example. What seems to be happening is that during
evaluation of the SELECT list for the first VALUES row, the CASE
expression doesn't call regexp_matches() but just returns the ELSE
expression. The ExecMakeFunctionResult() call for the cast function
then decides that the function's argument expression doesn't return a
set, so it changes the node execution pointer so that subsequent
executions go through the much simpler ExecMakeFunctionResultNoSets()
execution function. And then that spits up when on the next row, the
argument expression *does* return a set :-(

You could work around that using the trick documented in the
regexp_matches documentation to force it to return exactly one row,
ie interpose a sub-SELECT:

regression=# SELECT *, CASE WHEN id = 2 THEN
(select (regexp_matches(input_string,'^0*([1-9]\d+)$'))[1]) ELSE input_string
END::varchar(30) AS o_l2_a
FROM (
VALUES (1,''), (2,'0000000049404'),(3,'FROM 10000000876')
) l0_src (id, input_string);
id | input_string | o_l2_a
----+------------------+------------------
1 | |
2 | 0000000049404 | 49404
3 | FROM 10000000876 | FROM 10000000876
(3 rows)

Not sure about non-hack fixes. I guess we need to analyze
can-it-return-a-set statically instead of believing the first execution
result, but that might add an unpleasant amount of startup overhead.

regards, tom lane

In response to

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message matt.s 2013-06-13 20:48:05 BUG #8229: Dropuser and create user segfault for users in ldap
Previous Message Joshua Berry 2013-06-13 19:30:32 Re: [ODBC] Segmentation Fault in Postgres server when using psqlODBC