Обсуждение: the '::' cast doesn't work in the FROM clause

Поиск
Список
Период
Сортировка

the '::' cast doesn't work in the FROM clause

От
Alexey Klyukin
Дата:
Hello,

The following statement produces an error message in PostgreSQL 8.4 - 9.2 (=
head):

postgres=3D# select val from random()::integer as val;
ERROR:  syntax error at or near "::"
LINE 1: select val from random()::integer as val;

The same statement rewritten with CAST AS works as expected:
                                ^
postgres=3D# select val from CAST(random() as integer) as val;
 val
-----
   1
(1 row)

The '::' cast works normally when used in a target list:

postgres=3D# select random()::integer as val;
val
--------
      1
(1 row)

The documentation says these casts are equivalent, so either that's wrong, =
or this is a bug.
The target OS is Mac OS X 10.7.1 with llvm-gcc-4.2 used as a compiler.

--
Alexey Klyukin        http://www.commandprompt.com
The PostgreSQL Company =96 Command Prompt, Inc.

Re: the '::' cast doesn't work in the FROM clause

От
"Kevin Grittner"
Дата:
Alexey Klyukin  wrote:

> The following statement produces an error message in PostgreSQL 8.4
> - 9.2 (head):
>
> postgres=# select val from random()::integer as val;

> The same statement rewritten with CAST AS works as expected:
>
> postgres=# select val from CAST(random() as integer) as val;

> The documentation says these casts are equivalent, so either that's
> wrong, or this is a bug.

Please point out where you think the documentation says that.  The
way I read it, this is the correct syntax:

test=# select val from (select random()::integer) as x(val);
 val
-----
   1
(1 row)

Not only are you missing required parentheses and the SELECT keyword,
you're returning a record rather than a scalar value.

-Kevin

Re: the '::' cast doesn't work in the FROM clause

От
Alexey Klyukin
Дата:
On Aug 29, 2011, at 3:49 PM, Kevin Grittner wrote:

> Alexey Klyukin  wrote:
>=20
>> The following statement produces an error message in PostgreSQL 8.4
>> - 9.2 (head):
>>=20
>> postgres=3D# select val from random()::integer as val;
>=20
>> The same statement rewritten with CAST AS works as expected:
>>=20
>> postgres=3D# select val from CAST(random() as integer) as val;
>=20
>> The documentation says these casts are equivalent, so either that's
>> wrong, or this is a bug.
>=20
> Please point out where you think the documentation says that.

Here:

>=20
> A type cast specifies a conversion from one data type to another. Postgre=
SQL accepts two equivalent syntaxes for type casts:
>=20
> CAST ( expression AS type )
> expression::type
>=20

http://www.postgresql.org/docs/9.0/interactive/sql-expressions.html#SQL-SYN=
TAX-TYPE-CASTS


>  The way I read it, this is the correct syntax:
>=20
> test=3D# select val from (select random()::integer) as x(val);
> val=20
> -----
>   1
> (1 row)
>=20
> Not only are you missing required parentheses and the SELECT keyword,
> you're returning a record rather than a scalar value.

SELECT val FROM random() AS val (same as the problematic query, but w/o cas=
ts)  doesn't produce any errors and IMO is a  valid syntax. Here's a quote =
from the SELECT documentation:

> Function calls can appear in the FROM clause. (This is especially useful =
for functions that return result sets, but any function can be used.) This =
acts as though its output were created as a temporary table for the duratio=
n of this single SELECT command.=20

http://www.postgresql.org/docs/9.0/interactive/sql-select.html

The problem is that 2 types of casts behave differently when applied to ran=
dom() in this query.

--
Alexey Klyukin        http://www.commandprompt.com
The PostgreSQL Company =96 Command Prompt, Inc.

Re: the '::' cast doesn't work in the FROM clause

От
Merlin Moncure
Дата:
On Mon, Aug 29, 2011 at 7:49 AM, Kevin Grittner
<Kevin.Grittner@wicourts.gov> wrote:
> Alexey Klyukin =A0wrote:
>
>> The following statement produces an error message in PostgreSQL 8.4
>> - 9.2 (head):
>>
>> postgres=3D# select val from random()::integer as val;
>
>> The same statement rewritten with CAST AS works as expected:
>>
>> postgres=3D# select val from CAST(random() as integer) as val;
>
>> The documentation says these casts are equivalent, so either that's
>> wrong, or this is a bug.
>
> Please point out where you think the documentation says that. =A0The
> way I read it, this is the correct syntax:
>
> test=3D# select val from (select random()::integer) as x(val);
> =A0val
> -----
> =A0 1
> (1 row)
>
> Not only are you missing required parentheses and the SELECT keyword,
> you're returning a record rather than a scalar value.

yeah, that's the correct way, but why does this work?
select val from random() as val;

That's illegal IMO, and walls you off from syntax (like::) you
normally should be able to use.

merlin

Re: the '::' cast doesn't work in the FROM clause

От
"Kevin Grittner"
Дата:
Merlin Moncure <mmoncure@gmail.com> wrote:

> yeah, that's the correct way, but why does this work?
> select val from random() as val;

If you look at the PostgreSQL reference docs for the SELECT
statement, a from_item can be a SELECT statement in parentheses or a
function call (among other things).  It cannot be an arbitrary
expression containing operators (like ::).

-Kevin

Re: the '::' cast doesn't work in the FROM clause

От
"Kevin Grittner"
Дата:
Alexey Klyukin <alexk@commandprompt.com> wrote:

> Function calls can appear in the FROM clause. (This is especially
> useful for functions that return result sets, but any function can
> be used.) This acts as though its output were created as a
> temporary table for the duration of this single SELECT command.

It doesn't say that operators which provide equivalent functionality
to functions can also be used.

-Kevin

Re: the '::' cast doesn't work in the FROM clause

От
Alexey Klyukin
Дата:
On Aug 29, 2011, at 5:02 PM, Kevin Grittner wrote:

> Alexey Klyukin <alexk@commandprompt.com> wrote:
>=20
>> Function calls can appear in the FROM clause. (This is especially
>> useful for functions that return result sets, but any function can
>> be used.) This acts as though its output were created as a
>> temporary table for the duration of this single SELECT command.
>=20
> It doesn't say that operators which provide equivalent functionality
> to functions can also be used.

I agree, but why is it possible to use the type casting with CAST there? Do=
esn't this break the promise of equivalency between the 'CAST .. ' and '::'?

select val from CAST(random() as integer) as val;
 val=20
-----
   1
(1 row)

--
Alexey Klyukin        http://www.commandprompt.com
The PostgreSQL Company =96 Command Prompt, Inc.

Re: the '::' cast doesn't work in the FROM clause

От
"Kevin Grittner"
Дата:
Alexey Klyukin <alexk@commandprompt.com> wrote:
> On Aug 29, 2011, at 5:02 PM, Kevin Grittner wrote:
>
>> Alexey Klyukin <alexk@commandprompt.com> wrote:
>>
>>> Function calls can appear in the FROM clause. (This is
>>> especially useful for functions that return result sets, but any
>>> function can be used.) This acts as though its output were
>>> created as a temporary table for the duration of this single
>>> SELECT command.
>>
>> It doesn't say that operators which provide equivalent
>> functionality to functions can also be used.
>
> I agree, but why is it possible to use the type casting with CAST
> there?

Because the syntax is that of a function, which is allowed.

> Doesn't this break the promise of equivalency between the
> 'CAST .. ' and '::'?

No.  Equivalent functionality doesn't imply that the different
syntax forms can be used in the same places; just that they do the
same thing when used.   This is hardly unique to casting.
Comparison of two text values is done through the texteq function.

test=# select val from texteq('a', 'a') as val;
 val
-----
 t
(1 row)

test=# select val from 'a' = 'a' as val;
ERROR:  syntax error at or near "'a'"
LINE 1: select val from 'a' = 'a' as val;
                        ^
test=# select val from (select 'a' = 'a') as val;
 val
-----
 (t)
(1 row)

> select val from CAST(random() as integer) as val;
>  val
> -----
>    1
> (1 row)

Right.  A function is allowed as a from_item.  Arbitrary expressions
using operators which happen to provide equivalent services are not.

-Kevin

Re: the '::' cast doesn't work in the FROM clause

От
"Kevin Grittner"
Дата:
"Kevin Grittner" <Kevin.Grittner@wicourts.gov> wrote:

> test=# select val from (select 'a' = 'a') as val;
>  val
> -----
>  (t)
> (1 row)

Also note the difference between a record and a scalar here.  I
forgot to write it to return val as a scalar, which seems to be what
you're after.  It should have been:

test=# select val from (select 'a' = 'a') as x(val);
 val
-----
 t
(1 row)

-Kevin

Re: the '::' cast doesn't work in the FROM clause

От
Tom Lane
Дата:
"Kevin Grittner" <Kevin.Grittner@wicourts.gov> writes:
> Merlin Moncure <mmoncure@gmail.com> wrote:
>> yeah, that's the correct way, but why does this work?
>> select val from random() as val;

> If you look at the PostgreSQL reference docs for the SELECT
> statement, a from_item can be a SELECT statement in parentheses or a
> function call (among other things).  It cannot be an arbitrary
> expression containing operators (like ::).

Right.  We also accept things that look syntactically like function
calls, so as to avoid debates with newbies about whether, say,
COALESCE(...) is a function or not.  CAST() falls into that category,
while :: doesn't.

There is actually a practical reason for this policy beyond the question
of whether CAST is a function call or not: the structure name(...) has
a well-defined syntactic extent, so there are no issues of operator
precedence to worry about when it's embedded in a larger construct.
IIRC, we ran into exactly that problem with the CREATE INDEX syntax,
which is why an expression index column has to be parenthesized unless
it looks like a function call.

So IMO there is no syntax bug here.  There is a dump/reload bug though
:-( ... if you were to do

create view vv as select val from CAST(random() as integer) as val;

you will find that the system prints it out with the :: syntax,
which won't work.

            regards, tom lane

Re: the '::' cast doesn't work in the FROM clause

От
Alexey Klyukin
Дата:
On Aug 29, 2011, at 5:47 PM, Tom Lane wrote:

> "Kevin Grittner" <Kevin.Grittner@wicourts.gov> writes:
>> Merlin Moncure <mmoncure@gmail.com> wrote:
>>> yeah, that's the correct way, but why does this work?
>>> select val from random() as val;
>=20
>> If you look at the PostgreSQL reference docs for the SELECT
>> statement, a from_item can be a SELECT statement in parentheses or a
>> function call (among other things).  It cannot be an arbitrary
>> expression containing operators (like ::).
>=20
> Right.  We also accept things that look syntactically like function
> calls, so as to avoid debates with newbies about whether, say,
> COALESCE(...) is a function or not.  CAST() falls into that category,
> while :: doesn't.

I was wondering exactly why CAST() is permitted, while it's not a function =
(in Kevin's example, texteq is a function) and the explanation above answer=
s my question.=20

>=20
> There is actually a practical reason for this policy beyond the question
> of whether CAST is a function call or not: the structure name(...) has
> a well-defined syntactic extent, so there are no issues of operator
> precedence to worry about when it's embedded in a larger construct.
> IIRC, we ran into exactly that problem with the CREATE INDEX syntax,
> which is why an expression index column has to be parenthesized unless
> it looks like a function call.
>=20
> So IMO there is no syntax bug here.=20=20

I agree, thank you and Kevin for the great explanation!


> There is a dump/reload bug though :-( ... if you were to do
>=20
> create view vv as select val from CAST(random() as integer) as val;=20
>=20
> you will find that the system prints it out with the :: syntax,
> which won't work.

Would it be acceptable/sufficient to output  CAST(...) instead of '::'  for=
 all casts in pg_dump to fix this problem, assuming that CAST can be used a=
nywhere where '::' is accepted?

--
Alexey Klyukin        http://www.commandprompt.com
The PostgreSQL Company =96 Command Prompt, Inc.

Re: the '::' cast doesn't work in the FROM clause

От
Tom Lane
Дата:
Alexey Klyukin <alexk@commandprompt.com> writes:
> On Aug 29, 2011, at 5:47 PM, Tom Lane wrote:
>> There is a dump/reload bug though :-( ... if you were to do
>>
>> create view vv as select val from CAST(random() as integer) as val;
>>
>> you will find that the system prints it out with the :: syntax,
>> which won't work.

> Would it be acceptable/sufficient to output  CAST(...) instead of '::'  for all casts in pg_dump to fix this problem,
assumingthat CAST can be used anywhere where '::' is accepted? 

I'm not really excited about that; CAST is more verbose and not
particularly more readable (at least IMO).  What I was wondering about
was altering the internal representation to remember which format had
been used, and reverse-listing in that same format.  That would both fix
this issue, and please users who have a stylistic preference for one or
the other format.

            regards, tom lane

Re: the '::' cast doesn't work in the FROM clause

От
Merlin Moncure
Дата:
On Mon, Aug 29, 2011 at 9:00 AM, Kevin Grittner
<Kevin.Grittner@wicourts.gov> wrote:
> Merlin Moncure <mmoncure@gmail.com> wrote:
>
>> yeah, that's the correct way, but why does this work?
>> select val from random() as val;
>
> If you look at the PostgreSQL reference docs for the SELECT
> statement, a from_item can be a SELECT statement in parentheses or a
> function call (among other things). =A0It cannot be an arbitrary
> expression containing operators (like ::).


right -- duh.  I knew that...the canonical case for this is the
definition of pg_locks view.  I've just never seen it used for a
regular scalar function.  The whole thing is pretty peculiar IMO (but
useful occasionally).

merlin