Thread: Postgres 7.3.5 and count('x')

Postgres 7.3.5 and count('x')

From
ramirez@idconcepts.org (Edwin S. Ramirez)
Date:
Hello,

It appears that the count('x') will no longer work without a type
cast.  Is this on purpose?  I've already modified my code to use
count(*) instead, but I decided to mention it anyway.

warehouse=# select count('x') ;
ERROR:  cannot accept a value of type any
warehouse=# select count('x'::text) ;count
-------    1
(1 row)


Re: Postgres 7.3.5 and count('x')

From
Tom Lane
Date:
ramirez@idconcepts.org (Edwin S. Ramirez) writes:
> It appears that the count('x') will no longer work without a type
> cast.  Is this on purpose?

> warehouse=# select count('x') ;
> ERROR:  cannot accept a value of type any

Hm, that query seems like it should be legal.  (You get the same
from "select count('x') from some_table", so it's not the lack of
a table to iterate over that's the issue.)

The most direct fix is probably to make any_in() return some random
value (may as well be ((Datum) 0)) instead of producing an error.
I can't offhand see any real downside to doing so, but I'm a little
worried that it might introduce a gap in the type system.  Can anyone
see a reason not to do that?  Or a better fix for Edwin's complaint?
        regards, tom lane


Re: Postgres 7.3.5 and count('x')

From
Bruce Momjian
Date:
Tom Lane wrote:
> ramirez@idconcepts.org (Edwin S. Ramirez) writes:
> > It appears that the count('x') will no longer work without a type
> > cast.  Is this on purpose?
> 
> > warehouse=# select count('x') ;
> > ERROR:  cannot accept a value of type any
> 
> Hm, that query seems like it should be legal.  (You get the same
> from "select count('x') from some_table", so it's not the lack of
> a table to iterate over that's the issue.)
> 
> The most direct fix is probably to make any_in() return some random
> value (may as well be ((Datum) 0)) instead of producing an error.
> I can't offhand see any real downside to doing so, but I'm a little
> worried that it might introduce a gap in the type system.  Can anyone
> see a reason not to do that?  Or a better fix for Edwin's complaint?

What is COUNT('x') supposed to return?  1?  Is that legal SQL?

--  Bruce Momjian                        |  http://candle.pha.pa.us pgman@candle.pha.pa.us               |  (610)
359-1001+  If your life is a hard drive,     |  13 Roberts Road +  Christ can be your backup.        |  Newtown Square,
Pennsylvania19073
 


Re: Postgres 7.3.5 and count('x')

From
Tom Lane
Date:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> What is COUNT('x') supposed to return?  1?  Is that legal SQL?

Why not?  Vanilla SQL would assume the string is CHAR type.
        regards, tom lane


Re: Postgres 7.3.5 and count('x')

From
Peter Eisentraut
Date:
Tom Lane wrote:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > What is COUNT('x') supposed to return?  1?  Is that legal SQL?
>
> Why not?

Because there is nothing to count.

In general,

SELECT count(expr) FROM table1;

counts the number of rows in table1 where expr evaluates to not null.  
If table1 is not specified, that rule no longer holds.  At best you 
could assume that table1 is empty and return 0.  But a result of 1 I 
cannot see justified.



Re: Postgres 7.3.5 and count('x')

From
Tom Lane
Date:
Peter Eisentraut <peter_e@gmx.net> writes:
> In general,
> SELECT count(expr) FROM table1;
> counts the number of rows in table1 where expr evaluates to not null.  

Right.  Edwin obscured the datatype issue by leaving off a table, but
the issue is real anyway:

regression=# select count(1) from tenk1;count
-------10000
(1 row)

regression=# select count('x') from tenk1;
ERROR:  cannot accept a value of type any

We need to do something about that, I think.  The "long form" solution
would be to cause 'x' to be promoted to type text in this context, but
I think it may be enough to remove the elog() in any_in() and just let
a dummy value be returned.

> If table1 is not specified, that rule no longer holds.  At best you 
> could assume that table1 is empty and return 0.  But a result of 1 I 
> cannot see justified.

Mumble.  An Oracle person would say that our locution 
"SELECT expression" is a shorthand for "SELECT expression FROM dual"
(or whatever the name of that standard one-row table of theirs is).
With that understanding, the behavior of "SELECT count(1)" is entirely
proper.  If you assume that "SELECT expression" means to select from
a dummy table of no rows, then it should produce no result rows,
which would be pretty useless.  So I don't see the argument for saying
that count() should produce zero in that case.

I could see an argument for putting in a special case to error out if
an aggregate appears in this context ... but the current behavior seems
perfectly okay to me.  Except for the datatype problem.
        regards, tom lane


Re: Postgres 7.3.5 and count('x')

From
"Edwin S. Ramirez"
Date:
I tried :<br /> select count('x') from patients;<br /><br /> And I get the same error.  <br /><br /> select
count('x');should return the same as select count(*); which returns 1.<br /><br /> Previous Postgres versions returned
1.<br/><br /> -ESR-<br /><br /> Peter Eisentraut wrote:<br /><blockquote cite="mid200312061746.37190.peter_e@gmx.net"
type="cite"><prewrap="">Tom Lane wrote: </pre><blockquote type="cite"><pre wrap="">Bruce Momjian <a
class="moz-txt-link-rfc2396E"href="mailto:pgman@candle.pha.pa.us"><pgman@candle.pha.pa.us></a> writes:
</pre><blockquotetype="cite"><pre wrap="">What is COUNT('x') supposed to return?  1?  Is that legal SQL?
</pre></blockquote><prewrap="">Why not?   </pre></blockquote><pre wrap="">
 
Because there is nothing to count.

In general,

SELECT count(expr) FROM table1;

counts the number of rows in table1 where expr evaluates to not null.  
If table1 is not specified, that rule no longer holds.  At best you 
could assume that table1 is empty and return 0.  But a result of 1 I 
cannot see justified.
 </pre></blockquote>

Re: Postgres 7.3.5 and count('x')

From
Tom Lane
Date:
I said:
> ramirez@idconcepts.org (Edwin S. Ramirez) writes:
> [ "select count('x') from some_table" fails ]

> The most direct fix is probably to make any_in() return some random
> value (may as well be ((Datum) 0)) instead of producing an error.

After further investigation I have decided that this is really just an
issue of incorrect ordering of tests in parse_coerce.c.  The attached
proposed patch arranges for the ANY/ANYELEMENT/ANYARRAY short-circuit
path to be taken before we check for UNKNOWN-type literals and Params.
The net effect is that coercion to ANY/ANYELEMENT/ANYARRAY will have
*no effect* on an UNKNOWN literal.  This seems reasonable, since in
these contexts we don't really know any more than we did before about
the type of the literal; it's really still UNKNOWN.

One side effect besides fixing Edwin's gripe is that where before,

regression=# select 'x'::unknown::anyelement;
ERROR:  cannot accept a value of type anyelement

now you get a result:

regression=# select 'x'::unknown::anyelement;anyelement
------------x
(1 row)

I think this is reasonable, since coercion of other objects besides
unknown literals to anyelement is a no-op:

regression=# select 'x'::text::anyelement;anyelement
------------x
(1 row)

regression=# select 2::anyelement;anyelement
------------         2
(1 row)

Comments?  Any objections to the patch?
        regards, tom lane


*** src/backend/parser/parse_coerce.c~    Mon Dec  8 15:37:30 2003
--- src/backend/parser/parse_coerce.c    Sat Dec 13 13:21:41 2003
***************
*** 153,158 ****
--- 153,166 ----         /* no conversion needed */         return node;     }
+     if (targetTypeId == ANYOID ||
+         targetTypeId == ANYARRAYOID ||
+         targetTypeId == ANYELEMENTOID)
+     {
+         /* assume can_coerce_type verified that implicit coercion is okay */
+         /* NB: we do NOT want a RelabelType here */
+         return node;
+     }     if (inputTypeId == UNKNOWNOID && IsA(node, Const))     {         /*
***************
*** 260,273 ****         param->paramtype = targetTypeId;         return (Node *) param;     }
-     if (targetTypeId == ANYOID ||
-         targetTypeId == ANYARRAYOID ||
-         targetTypeId == ANYELEMENTOID)
-     {
-         /* assume can_coerce_type verified that implicit coercion is okay */
-         /* NB: we do NOT want a RelabelType here */
-         return node;
-     }     if (find_coercion_pathway(targetTypeId, inputTypeId, ccontext,                               &funcId))
{
--- 268,273 ----
***************
*** 372,388 ****         if (!typeidIsValid(targetTypeId))             return false; 
-         /*
-          * If input is an untyped string constant, assume we can convert
-          * it to anything except a class type.
-          */
-         if (inputTypeId == UNKNOWNOID)
-         {
-             if (ISCOMPLEX(targetTypeId))
-                 return false;
-             continue;
-         }
-          /* accept if target is ANY */         if (targetTypeId == ANYOID)             continue;
--- 372,377 ----
***************
*** 396,401 ****
--- 385,401 ----         }          /*
+          * If input is an untyped string constant, assume we can convert
+          * it to anything except a class type.
+          */
+         if (inputTypeId == UNKNOWNOID)
+         {
+             if (ISCOMPLEX(targetTypeId))
+                 return false;
+             continue;
+         }
+ 
+         /*          * If pg_cast shows that we can coerce, accept.  This test now          * covers both
binary-compatibleand coercion-function cases.          */