Обсуждение: BUG #18451: NULL fails to coerce to string when performing string comparison
BUG #18451: NULL fails to coerce to string when performing string comparison
От
PG Bug reporting form
Дата:
The following bug has been logged on the website: Bug reference: 18451 Logged by: Darryl Dixon Email address: darryl.dixon@gmail.com PostgreSQL version: 14.11 Operating system: Ubuntu 22.04 64Bit Description: postdb=# select where 'ab' like '%a%'; -- (1 row) postdb=# select where 'ab'||NULL like '%a%'; -- (0 rows) postdb=# select where 'ab'||NULL::text like '%a%'; -- (0 rows) postdb=# select where 'ab'||format('%s', NULL::text) like '%a%'; -- (1 row) postdb=# select version(); version ---------------------------------------------------------------------------------------------------------------------------------------- PostgreSQL 14.11 (Ubuntu 14.11-0ubuntu0.22.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, 64-bit (1 row)
Re: BUG #18451: NULL fails to coerce to string when performing string comparison
От
"David G. Johnston"
Дата:
On Monday, April 29, 2024, PG Bug reporting form <noreply@postgresql.org> wrote:
The following bug has been logged on the website:
Bug reference: 18451
Logged by: Darryl Dixon
Email address: darryl.dixon@gmail.com
PostgreSQL version: 14.11
Operating system: Ubuntu 22.04 64Bit
Description:
postdb=# select where 'ab' like '%a%';
--
(1 row)
postdb=# select where 'ab'||NULL like '%a%';
--
(0 rows)
postdb=# select where 'ab'||NULL::text like '%a%';
--
(0 rows)
You are mistaken in believing that concatenation involving null produces a non-null result. It is rather an inherently “strict” operation.
postdb=# select where 'ab'||format('%s', NULL::text) like '%a%';
--
(1 row)
Whereas format() is not “strict” and you choice of %s results in the documented empty string substitution.
David J.
Re: BUG #18451: NULL fails to coerce to string when performing string comparison
От
Darryl Dixon
Дата:
Hi,
anynonarray || text → text
Converts the non-string input to text, then concatenates the two strings. (The non-string input cannot be of an array type, because that would create ambiguity with the array || operators. If you want to concatenate an array's text equivalent, cast it to text explicitly.)
'Value: ' || 42 → Value: 42"
There are a couple of notes regarding this:
1) There is an explicit CAST of NULL->text that silently fails (see original example)
2) This behaviour, if expected, is not well documented/contradicted by existing documentation. See the note here:
"Note
The string concatenation operator (||) will accept non-string input, so long as at least one input is of string type, as shown in Table 9.9. For other cases, inserting an explicit coercion to text can be used to have non-string input accepted."Further, the extended details in the referenced table say:
"text || anynonarray → text
anynonarray || text → text
Converts the non-string input to text, then concatenates the two strings. (The non-string input cannot be of an array type, because that would create ambiguity with the array || operators. If you want to concatenate an array's text equivalent, cast it to text explicitly.)
'Value: ' || 42 → Value: 42"
regards,
Darryl Dixon
On Wed, 1 May 2024 at 09:13, David G. Johnston <david.g.johnston@gmail.com> wrote:
On Monday, April 29, 2024, PG Bug reporting form <noreply@postgresql.org> wrote:The following bug has been logged on the website:
Bug reference: 18451
Logged by: Darryl Dixon
Email address: darryl.dixon@gmail.com
PostgreSQL version: 14.11
Operating system: Ubuntu 22.04 64Bit
Description:
postdb=# select where 'ab' like '%a%';
--
(1 row)
postdb=# select where 'ab'||NULL like '%a%';
--
(0 rows)
postdb=# select where 'ab'||NULL::text like '%a%';
--
(0 rows)You are mistaken in believing that concatenation involving null produces a non-null result. It is rather an inherently “strict” operation.
postdb=# select where 'ab'||format('%s', NULL::text) like '%a%';
--
(1 row)Whereas format() is not “strict” and you choice of %s results in the documented empty string substitution.David J.
Re: BUG #18451: NULL fails to coerce to string when performing string comparison
От
David Rowley
Дата:
On Wed, 1 May 2024 at 09:06, PG Bug reporting form <noreply@postgresql.org> wrote: > postdb=# select where 'ab'||NULL like '%a%'; > -- > (0 rows) > > postdb=# select where 'ab'||NULL::text like '%a%'; > -- > (0 rows) You've not mentioned where you think the bug is, but if you think it's in either of the above, PostgreSQL is following the SQL standard here. The SQL2016 copy I have here says: "6.31 <string value expression> If at least one of S1 and S2 is the null value, then the result of the <concatenation> is the null value." There are a few RDBMSs that are lax on this rule, perhaps you're here because PostgreSQL isn't doing what you're used to? David
Re: BUG #18451: NULL fails to coerce to string when performing string comparison
От
Darryl Dixon
Дата:
The bug is that:
1) The concatenation is not producing NULL, but rather Text, and yet the comparison fails regardless, and
1) The concatenation is not producing NULL, but rather Text, and yet the comparison fails regardless, and
2) The explicit CAST of NULL -> Text fails to remedy this.
Further examples below:
postdb=# SELECT pg_typeof(NULL);
pg_typeof
-----------
unknown
(1 row)
postdb=# SELECT pg_typeof(NULL::text);
pg_typeof
-----------
text
(1 row)
postdb=# SELECT pg_typeof('ab'||NULL::text);
pg_typeof
-----------
text
(1 row)
postdb=# SELECT pg_typeof('ab'||NULL);
pg_typeof
-----------
text
(1 row)
postdb=# select where 'ab'||(NULL::text) like '%a%';
--
(0 rows)
postdhb=# select version();
version
----------------------------------------------------------------------------------------------------------------------------------------
PostgreSQL 14.11 (Ubuntu 14.11-0ubuntu0.22.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, 64-bit
(1 row)
ems=#
pg_typeof
-----------
unknown
(1 row)
postdb=# SELECT pg_typeof(NULL::text);
pg_typeof
-----------
text
(1 row)
postdb=# SELECT pg_typeof('ab'||NULL::text);
pg_typeof
-----------
text
(1 row)
postdb=# SELECT pg_typeof('ab'||NULL);
pg_typeof
-----------
text
(1 row)
postdb=# select where 'ab'||(NULL::text) like '%a%';
--
(0 rows)
postdhb=# select version();
version
----------------------------------------------------------------------------------------------------------------------------------------
PostgreSQL 14.11 (Ubuntu 14.11-0ubuntu0.22.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, 64-bit
(1 row)
ems=#
Darryl Dixon
On Wed, 1 May 2024 at 09:25, Darryl Dixon <darryl.dixon@gmail.com> wrote:
Hi,There are a couple of notes regarding this:1) There is an explicit CAST of NULL->text that silently fails (see original example)2) This behaviour, if expected, is not well documented/contradicted by existing documentation. See the note here:"NoteThe string concatenation operator (||) will accept non-string input, so long as at least one input is of string type, as shown in Table 9.9. For other cases, inserting an explicit coercion to text can be used to have non-string input accepted."Further, the extended details in the referenced table say:"text || anynonarray → text
anynonarray || text → text
Converts the non-string input to text, then concatenates the two strings. (The non-string input cannot be of an array type, because that would create ambiguity with the array || operators. If you want to concatenate an array's text equivalent, cast it to text explicitly.)
'Value: ' || 42 → Value: 42"regards,Darryl DixonOn Wed, 1 May 2024 at 09:13, David G. Johnston <david.g.johnston@gmail.com> wrote:On Monday, April 29, 2024, PG Bug reporting form <noreply@postgresql.org> wrote:The following bug has been logged on the website:
Bug reference: 18451
Logged by: Darryl Dixon
Email address: darryl.dixon@gmail.com
PostgreSQL version: 14.11
Operating system: Ubuntu 22.04 64Bit
Description:
postdb=# select where 'ab' like '%a%';
--
(1 row)
postdb=# select where 'ab'||NULL like '%a%';
--
(0 rows)
postdb=# select where 'ab'||NULL::text like '%a%';
--
(0 rows)You are mistaken in believing that concatenation involving null produces a non-null result. It is rather an inherently “strict” operation.
postdb=# select where 'ab'||format('%s', NULL::text) like '%a%';
--
(1 row)Whereas format() is not “strict” and you choice of %s results in the documented empty string substitution.David J.
On Wed, 1 May 2024 at 09:34, David Rowley <dgrowleyml@gmail.com> wrote:
On Wed, 1 May 2024 at 09:06, PG Bug reporting form
<noreply@postgresql.org> wrote:
> postdb=# select where 'ab'||NULL like '%a%';
> --
> (0 rows)
>
> postdb=# select where 'ab'||NULL::text like '%a%';
> --
> (0 rows)
You've not mentioned where you think the bug is, but if you think it's
in either of the above, PostgreSQL is following the SQL standard here.
The SQL2016 copy I have here says:
"6.31 <string value expression>
If at least one of S1 and S2 is the null value, then the result of the
<concatenation> is the null value."
There are a few RDBMSs that are lax on this rule, perhaps you're here
because PostgreSQL isn't doing what you're used to?
David
Darryl Dixon <darryl.dixon@gmail.com> writes: > The bug is that: > 1) The concatenation is not producing NULL, but rather Text, and yet the > comparison fails regardless, and > 2) The explicit CAST of NULL -> Text fails to remedy this. I wonder what you think NULL means. You certainly don't appear to understand its semantics at all. Every SQL data type allows NULL as a value, so "casting NULL to text" doesn't change the value, only what type the parser deems it to have. > Further examples below: Every one of these looks as-expected to me. regards, tom lane
Re: BUG #18451: NULL fails to coerce to string when performing string comparison
От
David Rowley
Дата:
On Wed, 1 May 2024 at 10:01, Darryl Dixon <darryl.dixon@gmail.com> wrote: > > The bug is that: > 1) The concatenation is not producing NULL, but rather Text, and yet the comparison fails regardless, and I think you're just wrongly assuming casting an unknown NULL to a type is making it somehow non-NULL. That's just not the case. NULLs can have a type. They're still NULL. postgres=# select 'ab' || NULL::text is null; ?column? ---------- t David
Re: BUG #18451: NULL fails to coerce to string when performing string comparison
От
"David G. Johnston"
Дата:
On Tuesday, April 30, 2024, Darryl Dixon <darryl.dixon@gmail.com> wrote:
Hi,There are a couple of notes regarding this:1) There is an explicit CAST of NULL->text that silently fails (see original example)
It doesn’t fail. Casting null still results in null. (Null::integer)::text is valid, you end up with a null integer converted to a null of type text.
2) This behaviour, if expected, is not well documented/contradicted by existing documentation. See the note here:
Fair, we don’t explicitly document that ‘…’ || NULL yields NULL. It’s more of “unless otherwise noted doing stuff with null results in unknown/null outcomes”.
David J.
Re: BUG #18451: NULL fails to coerce to string when performing string comparison
От
Darryl Dixon
Дата:
Thanks Tom,
Yes, I realised after sending that that is what's going on.
The documentation Note on the PostgreSQL behavior got my brain running in the wrong direction initially and the confusion was downstream from that.
regards,
Darryl Dixon
On Wed, 1 May 2024 at 10:07, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Darryl Dixon <darryl.dixon@gmail.com> writes:
> The bug is that:
> 1) The concatenation is not producing NULL, but rather Text, and yet the
> comparison fails regardless, and
> 2) The explicit CAST of NULL -> Text fails to remedy this.
I wonder what you think NULL means. You certainly don't appear to
understand its semantics at all. Every SQL data type allows NULL
as a value, so "casting NULL to text" doesn't change the value,
only what type the parser deems it to have.
> Further examples below:
Every one of these looks as-expected to me.
regards, tom lane
"David G. Johnston" <david.g.johnston@gmail.com> writes: > Fair, we don’t explicitly document that ‘…’ || NULL yields NULL. It’s more > of “unless otherwise noted doing stuff with null results in unknown/null > outcomes”. Yeah, there's a documentation gap here. I dug around a little and really couldn't find anything anywhere in our SGML docs that explains NULL in any detail; we tend to assume that you've already heard of it. There are a couple of parenthetical remarks in func.sgml that reference the notion that NULL means "unknown", but you'd never find those if you were looking for an explanation of what NULL is. Perhaps that'd be worth a few paras somewhere, though I'm not very sure where's a good place. regards, tom lane
Re: BUG #18451: NULL fails to coerce to string when performing string comparison
От
David Rowley
Дата:
On Wed, 1 May 2024 at 10:30, Tom Lane <tgl@sss.pgh.pa.us> wrote: > > "David G. Johnston" <david.g.johnston@gmail.com> writes: > > Fair, we don’t explicitly document that ‘…’ || NULL yields NULL. It’s more > > of “unless otherwise noted doing stuff with null results in unknown/null > > outcomes”. > > Yeah, there's a documentation gap here. I dug around a little and > really couldn't find anything anywhere in our SGML docs that explains > NULL in any detail; we tend to assume that you've already heard of it. > There are a couple of parenthetical remarks in func.sgml that > reference the notion that NULL means "unknown", but you'd never > find those if you were looking for an explanation of what NULL is. > Perhaps that'd be worth a few paras somewhere, though I'm not > very sure where's a good place. What is really generic enough about SQL NULLs to put somewhere generic? I mean NULL = NULL is NULL rather than true, but NULLs are treated as equal in DISTINCT and GROUP BY. It seems to me it would be hard to generically write something about it without referencing specific situations, and if we have to do that, why don't we just write it specifically in that location? I see we already mention that false and NULL don't match in a WHERE clause in [1], per "(i.e., if the result is false or null)". Maybe that could be expanded to elaborate more on 3-way SQL boolean logic and [2] could be expanded to mention that concatenating a NULL yields NULL. David [1] https://www.postgresql.org/docs/current/queries-table-expressions.html#QUERIES-WHERE [2] https://www.postgresql.org/docs/current/functions-string.html
David Rowley <dgrowleyml@gmail.com> writes: > On Wed, 1 May 2024 at 10:30, Tom Lane <tgl@sss.pgh.pa.us> wrote: >> Yeah, there's a documentation gap here. I dug around a little and >> really couldn't find anything anywhere in our SGML docs that explains >> NULL in any detail; we tend to assume that you've already heard of it. > What is really generic enough about SQL NULLs to put somewhere > generic? I think the key points I'd want to get across include: * Any value can be NULL rather than a "normal" value of its datatype. * There are various ways to think about the meaning of NULL, but an often-useful viewpoint is that it represents an unknown value. * A majority of SQL operations, including nearly all built-in functions and operators, are strict meaning they yield NULL if any input is NULL. This is consistent with interpreting NULL as "unknown". Depending on how ambitious we wanted to be, we could add examples illustrating these points. For instance we could explain the behavior of the boolean operators (such as "true OR null => true", "true AND null => null") as being consistent with the "unknown" interpretation. Some of this material could be moved or copied from existing text. There is attraction in centralizing the treatment, but on the other hand those examples are all pretty on-point where they are. I wouldn't have a problem with being a bit repetitious, though. It's not like these facts are going to change and need updates. > I mean NULL = NULL is NULL rather than true, but NULLs are > treated as equal in DISTINCT and GROUP BY. It would not hurt to say that the SQL standard isn't 100% logically consistent about how it handles NULLs. But this particular point isn't that bad: we could introduce the definition of distinctness ("IS [NOT] DISTINCT FROM") and then say that grouping operations use that behavior rather than what "=" does. The bottom line is that I think nowadays a lot of people learn SQL from our documentation, rather than coming to our docs with pre-existing SQL knowledge. So we need to fill in these sorts of explanatory gaps. regards, tom lane
Re: BUG #18451: NULL fails to coerce to string when performing string comparison
От
"David G. Johnston"
Дата:
On Tue, Apr 30, 2024 at 7:53 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
David Rowley <dgrowleyml@gmail.com> writes:
> On Wed, 1 May 2024 at 10:30, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> Yeah, there's a documentation gap here. I dug around a little and
>> really couldn't find anything anywhere in our SGML docs that explains
>> NULL in any detail; we tend to assume that you've already heard of it.
> What is really generic enough about SQL NULLs to put somewhere
> generic?
I think the key points I'd want to get across include:
I got the ball rolling here:
incorporating roughly all the points listed below, though not necessarily in the exact form shown or envisioned.
David J.