Cast null to int4 upgrading from Version 7.2

Started by Dwight Emmonsabout 19 years ago6 messages
#1Dwight Emmons
demmons@instantbenefits.com

My company is currently using version 7.2 and would like to convert to the
latest version. Unfortunately, version 7.3 implicitly casts a null text to
an int4. For example:

Create table employee_table (

employee_id integer

employee_name text

employee_address text);

Select * from employee_table where employee_id = '';

When executing this select statement in version 7.2 the null will be
converted to an int zero and not fail. In version 8.2 it fails. We have
over 20,000 lines of code and do not want to modify and test all of it. Has
anyone come across this problem? (I am not interested in debating the
theory of nulls versus zero. I am just trying to avoid unnecessary costs).

I am not a DBA, and am looking for explicit instructions to solve this
problem. Is it possible to create a CAST after upgrading to version 8.2?
My research tells me the following cast was no longer implemented after
version 7.2. Will executing the following CAST solve my problem?

CREATE CAST (text AS int4) WITH FUNCTION int4(text);

If so, can someone give me instructions as to executing this statement?

Any help is appreciated..

Dwight

#2Andrew Dunstan
andrew@dunslane.net
In reply to: Dwight Emmons (#1)
Re: Cast null to int4 upgrading from Version 7.2

Dwight Emmons wrote:

[Why did you post this to pgsql-patches of all places? it should
properly have gone to pgsql-general, I think]

My company is currently using version 7.2 and would like to convert to
the latest version. Unfortunately, version 7.3 implicitly casts a null
text to an int4. For example:

Create table employee_table (

employee_id integer

employee_name text

employee_address text);

Select * from employee_table where employee_id = ��;

That's not a NULL at all, it's an empty string. You really need to
understand the difference between the two.

Old editions of postgres did take an empty string literal as a 0 for
ints, modern version quite rightly reject it as invalid. use NULL if you
mean NULL and 0 if you mean 0.

When executing this select statement in version 7.2 the null will be
converted to an int zero and not fail. In version 8.2 it fails. We
have over 20,000 lines of code and do not want to modify and test all
of it. Has anyone come across this problem? (I am not interested in
debating the theory of nulls versus zero. I am just trying to avoid
unnecessary costs).

I am not a DBA, and am looking for explicit instructions to solve this
problem. Is it possible to create a CAST after upgrading to version
8.2? My research tells me the following cast was no longer implemented
after version 7.2. Will executing the following CAST solve my problem?

CREATE CAST (text AS int4) WITH FUNCTION int4(text);

If so, can someone give me instructions as to executing this statement?

Any help is appreciated�.

This has nothing to do with casts, I believe - it has to to with what
the input routines accept.

I strongly suspect that renovating your code is your best choice, much
as that might pain you.

cheers

andrew

#3Neil Conway
neilc@samurai.com
In reply to: Dwight Emmons (#1)
Re: Cast null to int4 upgrading from Version 7.2

FYI, the pgsql-patches list is for proposed patches, not questions about
behavior.

On Thu, 2006-11-16 at 13:47 -0800, Dwight Emmons wrote:

Select * from employee_table where employee_id = οΏ½οΏ½;

When executing this select statement in version 7.2 the null will be
converted to an int zero and not fail.

Your statement does not include a "null" value, it includes an empty
string. The behavior you're depending on is that an empty string was
treated as zero in input to an integer type, which is no longer the
case. It has nothing to do with casting AFAICS.

In version 8.2 it fails. We have over 20,000 lines of code and do
not want to modify and test all of it. Has anyone come across this
problem?

Yes, this is a common problem for people upgrading from 7.2. I think the
long-term fix is to change your queries: comparing an integer with '' is
not sensible. That is:

SELECT * FROM employee_table WHERE employee_id = 0;

is the right way to write that query.

As a temporary fix, I suppose you could hack pg_atoi() to treat an empty
string as zero (src/backend/utils/adt/numutils.c).

-Neil

#4Jim Nasby
decibel@decibel.org
In reply to: Neil Conway (#3)
Re: Cast null to int4 upgrading from Version 7.2

On Nov 16, 2006, at 3:10 PM, Neil Conway wrote:

Yes, this is a common problem for people upgrading from 7.2. I
think the
long-term fix is to change your queries: comparing an integer with
'' is
not sensible. That is:

SELECT * FROM employee_table WHERE employee_id = 0;

is the right way to write that query.

As a temporary fix, I suppose you could hack pg_atoi() to treat an
empty
string as zero (src/backend/utils/adt/numutils.c).

As a less invasive alternative, I *think* you could create an SQL
function for casting text to int that treated '' as 0, and then
replace the built-in CAST with that. You'd also need to make the cast
implicit, which could cause other problems.

20k lines of code isn't all that much, though... you'll be much
better off fixing it.
--
Jim Nasby jim@nasby.net
EnterpriseDB http://enterprisedb.com 512.569.9461 (cell)

#5Peter Eisentraut
peter_e@gmx.net
In reply to: Jim Nasby (#4)
Re: Cast null to int4 upgrading from Version 7.2

Jim Nasby wrote:

As a less invasive alternative, I *think* you could create an SQL
function for casting text to int that treated '' as 0, and then
replace the built-in CAST with that.

Won't work. You need to replace the data type input function.

--
Peter Eisentraut
http://developer.postgresql.org/~petere/

#6Mario Weilguni
mweilguni@sime.com
In reply to: Dwight Emmons (#1)
1 attachment(s)
Re: Cast null to int4 upgrading from Version 7.2

you might be interested using the patch attached, it introduces a new GUC
variable named "empty_equals_0", allowing to set this per database:
alter database xyz set empty_equals_0 to true;

I've written and used this patch for internal purpose, and take no
responsibilty at all, but it's working (having 60000 lines old application
code using this)

Am Donnerstag, 16. November 2006 22:47 schrieb Dwight Emmons:

Show quoted text

My company is currently using version 7.2 and would like to convert to the
latest version. Unfortunately, version 7.3 implicitly casts a null text
to an int4. For example:

Create table employee_table (

employee_id integer

employee_name text

employee_address text);

Select * from employee_table where employee_id = '';

When executing this select statement in version 7.2 the null will be
converted to an int zero and not fail. In version 8.2 it fails. We have
over 20,000 lines of code and do not want to modify and test all of it.
Has anyone come across this problem? (I am not interested in debating the
theory of nulls versus zero. I am just trying to avoid unnecessary costs).

I am not a DBA, and am looking for explicit instructions to solve this
problem. Is it possible to create a CAST after upgrading to version 8.2?
My research tells me the following cast was no longer implemented after
version 7.2. Will executing the following CAST solve my problem?

CREATE CAST (text AS int4) WITH FUNCTION int4(text);

If so, can someone give me instructions as to executing this statement?

Any help is appreciated..

Dwight

Attachments:

postgresql-8.1.0-empty_equals_0.patchtext/x-diff; charset=utf-8; name=postgresql-8.1.0-empty_equals_0.patchDownload
diff -Nurb postgresql-8.1.4/src/backend/utils/adt/numutils.c postgresql-8.1.4-patched/src/backend/utils/adt/numutils.c
--- postgresql-8.1.4/src/backend/utils/adt/numutils.c	2005-12-01 00:10:16.000000000 +0100
+++ postgresql-8.1.4-patched/src/backend/utils/adt/numutils.c	2006-10-13 12:05:34.000000000 +0200
@@ -55,6 +55,9 @@
  * Unlike plain atoi(), this will throw ereport() upon bad input format or
  * overflow.
  */
+
+bool empty_equals_0;
+
 int32
 pg_atoi(char *s, int size, int c)
 {
@@ -68,6 +71,9 @@
 	if (s == NULL)
 		elog(ERROR, "NULL pointer");
 	if (*s == 0)
+		if(empty_equals_0)
+			return (int32)0;
+		else
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("invalid input syntax for integer: \"%s\"",
diff -Nurb postgresql-8.1.4/src/backend/utils/misc/guc.c postgresql-8.1.4-patched/src/backend/utils/misc/guc.c
--- postgresql-8.1.4/src/backend/utils/misc/guc.c	2006-05-21 22:11:02.000000000 +0200
+++ postgresql-8.1.4-patched/src/backend/utils/misc/guc.c	2006-10-13 12:05:57.000000000 +0200
@@ -97,6 +97,7 @@
 extern int	CommitSiblings;
 extern char *default_tablespace;
 extern bool fullPageWrites;
+extern bool empty_equals_0;
 
 #ifdef TRACE_SORT
 extern bool trace_sort;
@@ -395,6 +396,14 @@
 static struct config_bool ConfigureNamesBool[] =
 {
 	{
+                {"empty_equals_0", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
+                        gettext_noop("Treats the empty string as 0 when dealing with integers"),
+                        NULL
+                },
+                &empty_equals_0,
+                false, NULL, NULL
+        },
+	{
 		{"enable_seqscan", PGC_USERSET, QUERY_TUNING_METHOD,
 			gettext_noop("Enables the planner's use of sequential-scan plans."),
 			NULL