Datatypes in PL/PSQL functions with multiple arguments

Started by Benjamin Holmbergalmost 21 years ago16 messagesgeneral
Jump to latest
#1Benjamin Holmberg
benjamin.holmberg@gmail.com

Hello-

This is my first foray into pl/psql so forgive me if I sound totally
incompetent.

I've been writing a few functions, and have come across some screwing data
typing issues.

When creating a function which accepts a single argument, things work just
fine, variable can be used throughout the function as expected with no
modification.
When creating functions containing two or more arguments, I have to
explicity cast the arguments whenever I use them (loading/casting into
another variable is an option, haven't tried though) to prevent runtime
errors. The functions get called just fine, but then run into problems using
any of the given arguments.

Has anyone had any experience with this? Please advise!

Thanks!
Benjamin

select version();
version
--------------------------------------------------------------------------------------------------------
PostgreSQL 7.4.7 on i686-pc-linux-gnu, compiled by GCC gcc (GCC)
3.4.1(Mandrakelinux
10.1 3.4.1-4mdk)

#2Richard Huxton
dev@archonet.com
In reply to: Benjamin Holmberg (#1)
Re: Datatypes in PL/PSQL functions with multiple arguments

Benjamin Holmberg wrote:

Hello-

This is my first foray into pl/psql so forgive me if I sound totally
incompetent.

I've been writing a few functions, and have come across some screwing data
typing issues.

When creating a function which accepts a single argument, things work just
fine, variable can be used throughout the function as expected with no
modification.
When creating functions containing two or more arguments, I have to
explicity cast the arguments whenever I use them (loading/casting into
another variable is an option, haven't tried though) to prevent runtime
errors. The functions get called just fine, but then run into problems using
any of the given arguments.

Could you perhaps give an example function? Something with one or two
lines of code perhaps. Oh, and how you are calling it too.

--
Richard Huxton
Archonet Ltd

#3Michael Fuhr
mike@fuhr.org
In reply to: Benjamin Holmberg (#1)
Re: Datatypes in PL/PSQL functions with multiple arguments

On Tue, Apr 19, 2005 at 10:01:26AM -0500, Benjamin Holmberg wrote:

When creating a function which accepts a single argument, things work just
fine, variable can be used throughout the function as expected with no
modification.
When creating functions containing two or more arguments, I have to
explicity cast the arguments whenever I use them (loading/casting into
another variable is an option, haven't tried though) to prevent runtime
errors. The functions get called just fine, but then run into problems using
any of the given arguments.

Please post an example of what you're doing: a simple function, how
you're invoking it, and the error message(s).

--
Michael Fuhr
http://www.fuhr.org/~mfuhr/

#4Benjamin Holmberg
benjamin.holmberg@gmail.com
In reply to: Benjamin Holmberg (#1)
Re: Datatypes in PL/PSQL functions with multiple arguments

This is one of the "bad" ones hacked up to work like it should...

I would call it like the following:
SELECT SIMPLE_date_used('5/11/06','5');

beginning_date and ending_date are date columns in MyTable. The function is
checking to see if given_date falls within a date range that has already
been established in another row, with the exclusion of the row defined by
arg_id.

==============
CREATE FUNCTION SIMPLE_date_used (date,integer) RETURNS text AS '
DECLARE
given_date ALIAS for $1;
arg_id ALIAS for $2;
result boolean;
BEGIN
IF arg_production_schedule_id != 0 THEN
SELECT INTO result ((CAST(given_date AS date) >= beginning_date) AND
(CAST(given_date AS date) <= ending_date)) FROM MyTable WHERE
((((CAST(given_date AS date) >= beginning_date) AND (CAST(given_date AS
date) <= ending_date)) = TRUE) AND MyTable.arg_id != (CAST(arg_id AS
integer)));
IF result = TRUE THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END;
' LANGUAGE 'plpgsql';
This is how I would think it should work changed (CAST(arg_id AS integer)) TO
MyTable.arg_id != ''arg_id'':

CREATE FUNCTION SIMPLE_date_used (date,integer) RETURNS text AS '
DECLARE
given_date ALIAS for $1;
arg_id ALIAS for $2;
result boolean;
BEGIN
IF arg_production_schedule_id != 0 THEN
SELECT INTO result ((CAST(given_date AS date) >= beginning_date) AND
(CAST(given_date AS date) <= ending_date)) FROM MyTable WHERE
((((CAST(given_date AS date) >= beginning_date) AND (CAST(given_date AS
date) <= ending_date)) = TRUE) AND MyTable.arg_id != ''arg_id'');
IF result = TRUE THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END;
' LANGUAGE 'plpgsql';

This is the error message I'm getting by using: ''arg_id'' instead of:
(CAST(arg_id
AS integer))
SELECT production_scheduled_for_date('2005-05-12', '49');
ERROR: invalid input syntax for integer: "arg_id"
CONTEXT: PL/pgSQL function "SIMPLE_date_used" line 10 at select into
variables

Any thoughts?

Show quoted text

On 4/19/05, Richard Huxton <dev@archonet.com> wrote:

Benjamin Holmberg wrote:

Hello-

This is my first foray into pl/psql so forgive me if I sound totally
incompetent.

I've been writing a few functions, and have come across some screwing

data

typing issues.

When creating a function which accepts a single argument, things work

just

fine, variable can be used throughout the function as expected with no
modification.
When creating functions containing two or more arguments, I have to
explicity cast the arguments whenever I use them (loading/casting into
another variable is an option, haven't tried though) to prevent runtime
errors. The functions get called just fine, but then run into problems

using

any of the given arguments.

Could you perhaps give an example function? Something with one or two
lines of code perhaps. Oh, and how you are calling it too.

--
Richard Huxton
Archonet Ltd

#5Richard Huxton
dev@archonet.com
In reply to: Benjamin Holmberg (#1)
Re: Datatypes in PL/PSQL functions with multiple arguments

Don't forget to cc: the list...

Benjamin Holmberg wrote:

This is one of the "bad" ones...

I would call it like the following:
SELECT SIMPLE_date_used('5/11/06','5');

Well, you're trying to call it with two text-values here (or at least
two unknown values).

SELECT simple_date_used('5/11/06'::date, 5)

beginning_date and ending_date are date columns in MyTable. The function is
checking to see if given_date falls within a date range that has already
been established in another row, with the exclusion of the row defined by
arg_id.

==============
CREATE FUNCTION SIMPLE_date_used (date,integer) RETURNS text AS '
DECLARE
given_date ALIAS for $1;
arg_id ALIAS for $2;

You've got a column called arg_id below, so it's best to call this
something else (p_arg_id or something). That stops both me and plpgsql
from getting confused :-)

result boolean;
BEGIN
IF arg_production_schedule_id != 0 THEN
SELECT INTO result ((CAST(given_date AS date) >= beginning_date) AND

Now, these casts shouldn't be necessary. Are you saying you get errors
when you just use "given_date <= ending_date"?

(CAST(given_date AS date) <= ending_date)) FROM MyTable WHERE
((((CAST(given_date AS date) >= beginning_date) AND (CAST(given_date AS
date) <= ending_date)) = TRUE) AND MyTable.arg_id != (CAST(arg_id AS
integer)));
IF result = TRUE THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END;
' LANGUAGE 'plpgsql';

I've got to say I'd write the function more like:

SELECT INTO result true FROM MyTable
WHERE p_given_date >= beginning_date AND p_given_date <= ending_date
AND arg_id <> p_arg_id
RETURN FOUND;

The "FOUND" variable gets set when a query returns results.

--
Richard Huxton
Archonet Ltd

#6Richard Huxton
dev@archonet.com
In reply to: Benjamin Holmberg (#4)
Re: Datatypes in PL/PSQL functions with multiple arguments

Benjamin Holmberg wrote:

This is the error message I'm getting by using: ''arg_id'' instead of:
(CAST(arg_id
AS integer))
SELECT production_scheduled_for_date('2005-05-12', '49');
ERROR: invalid input syntax for integer: "arg_id"

That's because ''arg_id'' is the string value "arg_id", those six
characters rather than the value of any variable.

--
Richard Huxton
Archonet Ltd

#7Benjamin Holmberg
benjamin.holmberg@gmail.com
In reply to: Richard Huxton (#6)
Re: Datatypes in PL/PSQL functions with multiple arguments

Then I guess I need to know how one can encapsulate variables in quotes, yet
let the pl/pgsql interpreter interpolate.
In the case of my SELECT INTO, are the quotes even needed to avoid potential
confusion with column names?

Show quoted text

On 4/19/05, Richard Huxton <dev@archonet.com> wrote:

Benjamin Holmberg wrote:

This is the error message I'm getting by using: ''arg_id'' instead of:
(CAST(arg_id
AS integer))
SELECT production_scheduled_for_date('2005-05-12', '49');
ERROR: invalid input syntax for integer: "arg_id"

That's because ''arg_id'' is the string value "arg_id", those six
characters rather than the value of any variable.

--
Richard Huxton
Archonet Ltd

#8David Gagnon
dgagnon@siunik.com
In reply to: Richard Huxton (#6)
Regular expression. How to disable ALL meta-character in a regular expression

Hi all,

I have a web interface with offers a search field. This search field
will look for the string X in 12 different columns. If the string is
found anywhere I return the row.

The problem is that the user is eable to put spacial character like : [*
This create invalid regular expression and make my sql crash.
ICNUM~* #descriptionOrKeyword#

Is there a way to disable all meta-character. I found this in the
manual .. but haven't found example :-(:
: ....with ***=, the rest of the RE is taken to be a literal string,
with all characters
considered ordinary characters.

I know my question si basic . but I search around and haven't found so
far .. please help :-)

Thanks
/David

\Richard Huxton wrote:

Show quoted text

Benjamin Holmberg wrote:

This is the error message I'm getting by using: ''arg_id'' instead of:
(CAST(arg_id
AS integer))
SELECT production_scheduled_for_date('2005-05-12', '49');
ERROR: invalid input syntax for integer: "arg_id"

That's because ''arg_id'' is the string value "arg_id", those six
characters rather than the value of any variable.

--
Richard Huxton
Archonet Ltd

---------------------------(end of broadcast)---------------------------
TIP 4: Don't 'kill -9' the postmaster

#9Michael Fuhr
mike@fuhr.org
In reply to: David Gagnon (#8)
Re: Regular expression. How to disable ALL meta-character in a regular expression

On Wed, Apr 20, 2005 at 11:28:28AM -0400, David Gagnon wrote:

I have a web interface with offers a search field. This search field
will look for the string X in 12 different columns. If the string is
found anywhere I return the row.

The problem is that the user is eable to put spacial character like : [*
This create invalid regular expression and make my sql crash.
ICNUM~* #descriptionOrKeyword#

Is there a way to disable all meta-character.

Why are you doing a regular expression search if you don't want to
allow regular expressions?

I found this in the manual .. but haven't found example :-(:
: ....with ***=, the rest of the RE is taken to be a literal string,
with all characters considered ordinary characters.

Read again the entire sentence, especially the first few words:

If an RE begins with ***=, the rest of the RE is taken to be a
literal string, with all characters considered ordinary characters.

Here are some examples:

SELECT 'test string' ~ 'test[*';
ERROR: invalid regular expression: brackets [] not balanced

SELECT 'test string' ~ '***=test[*';
?column?
----------
f
(1 row)

SELECT 'test[* string' ~ '***=test[*';
?column?
----------
t
(1 row)

--
Michael Fuhr
http://www.fuhr.org/~mfuhr/

#10David Gagnon
dgagnon@siunik.com
In reply to: Michael Fuhr (#9)
Re: Regular expression. How to disable ALL meta-character

Michael Fuhr wrote:

On Wed, Apr 20, 2005 at 11:28:28AM -0400, David Gagnon wrote:

I have a web interface with offers a search field. This search field
will look for the string X in 12 different columns. If the string is
found anywhere I return the row.

The problem is that the user is eable to put spacial character like : [*
This create invalid regular expression and make my sql crash.
ICNUM~* #descriptionOrKeyword#

Is there a way to disable all meta-character.

Why are you doing a regular expression search if you don't want to
allow regular expressions?

Maybe there is a simple way to to this but I want find string X in
different column. The search must not be case sensitive.

So that searching "aBc" in "abcDef" return true. I don't want
META-CHaracter. Or at least I don't want meta-character to cause errors
(i.e.: No

ERROR: invalid regular expression: brackets [] not balanced.

Thanks for your help
/David

Show quoted text

I found this in the manual .. but haven't found example :-(:
: ....with ***=, the rest of the RE is taken to be a literal string,
with all characters considered ordinary characters.

Read again the entire sentence, especially the first few words:

If an RE begins with ***=, the rest of the RE is taken to be a
literal string, with all characters considered ordinary characters.

Here are some examples:

SELECT 'test string' ~ 'test[*';
ERROR: invalid regular expression: brackets [] not balanced

SELECT 'test string' ~ '***=test[*';
?column?
----------
f
(1 row)

SELECT 'test[* string' ~ '***=test[*';
?column?
----------
t
(1 row)

#11Scott Marlowe
smarlowe@g2switchworks.com
In reply to: David Gagnon (#10)
Re: Regular expression. How to disable ALL

On Wed, 2005-04-20 at 12:36, David Gagnon wrote:

Michael Fuhr wrote:

On Wed, Apr 20, 2005 at 11:28:28AM -0400, David Gagnon wrote:

I have a web interface with offers a search field. This search field
will look for the string X in 12 different columns. If the string is
found anywhere I return the row.

The problem is that the user is eable to put spacial character like : [*
This create invalid regular expression and make my sql crash.
ICNUM~* #descriptionOrKeyword#

Is there a way to disable all meta-character.

Why are you doing a regular expression search if you don't want to
allow regular expressions?

Maybe there is a simple way to to this but I want find string X in
different column. The search must not be case sensitive.

So that searching "aBc" in "abcDef" return true. I don't want
META-CHaracter. Or at least I don't want meta-character to cause errors
(i.e.: No

ERROR: invalid regular expression: brackets [] not balanced.

I would generally scrub the input before it go to postgresql. Basically
do a simple string_replace type function that replaces anything that
ISN'T alphanum with nothing.

#12Scott Marlowe
smarlowe@g2switchworks.com
In reply to: Benjamin Holmberg (#1)
Re: Regular expression. How to disable

On Wed, 2005-04-20 at 13:05, David Gagnon wrote:

Hi Scott,

I would generally scrub the input before it go to postgresql. Basically
do a simple string_replace type function that replaces anything that
ISN'T alphanum with nothing.

If I change the original string the user may not get what he expects as
result. abc[d] is not the samething than abcd... am I right?

Then replace it with properly escaped strings:

abc[d] becomes abc\[d\]

#13David Gagnon
dgagnon@siunik.com
In reply to: Scott Marlowe (#11)
Re: Regular expression. How to disable ALL meta-character

Hi Scott,

I would generally scrub the input before it go to postgresql. Basically
do a simple string_replace type function that replaces anything that
ISN'T alphanum with nothing.

If I change the original string the user may not get what he expects as
result. abc[d] is not the samething than abcd... am I right?

Thanks for your help
/David

#14Chris Travers
chris@metatrontech.com
In reply to: David Gagnon (#10)
Re: Regular expression. How to disable ALL meta-character

David Gagnon wrote:

Maybe there is a simple way to to this but I want find string X in
different column. The search must not be case sensitive.

So that searching "aBc" in "abcDef" return true. I don't want
META-CHaracter. Or at least I don't want meta-character to cause
errors (i.e.: No

Ok, how about a better way to do this?

select * from mytable where lower(mycol) LIKE lower("%" || lower(X) || "%");

Does this work? It seems that this may be the best way to handle this
sort of thing.

Best Wishes,
Chris Travers
Metatron Technology Consulting

Show quoted text

ERROR: invalid regular expression: brackets [] not balanced.

Thanks for your help
/David

I found this in the manual .. but haven't found example :-(:
: ....with ***=, the rest of the RE is taken to be a literal string,
with all characters considered ordinary characters.

Read again the entire sentence, especially the first few words:

If an RE begins with ***=, the rest of the RE is taken to be a
literal string, with all characters considered ordinary characters.

Here are some examples:

SELECT 'test string' ~ 'test[*';
ERROR: invalid regular expression: brackets [] not balanced

SELECT 'test string' ~ '***=test[*';
?column? ----------
f
(1 row)

SELECT 'test[* string' ~ '***=test[*';
?column? ----------
t
(1 row)

---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings

#15David Gagnon
dgagnon@siunik.com
In reply to: Chris Travers (#14)
Re: Regular expression. How to disable ALL meta-character

Thanks for your help!

Just want to share the solution I got to solve my problem. I wanted to
be eable to search a string (say X) (non case sensitive) without having
meta-character involved. The X string come directy from the web so any
[%]* may cause error in regular expression (because they form non valid
expression)

1) Using like: select * from mytable where lower(mycol) LIKE lower("%"
|| lower(X) || "%");
Mostly perfect solution. Don't crash but % still have a special
meaning. Wich means anything
2)Using regular expression: select * from mytable where mycol ~*
('***=' || X)
For the test I did it doesn't, fit all my need. No meta character and
no escaping to do on X before launching the SQL request.

Thanks for your help!!!
Have a great day
/David

Chris Travers wrote:

Show quoted text

David Gagnon wrote:

Maybe there is a simple way to to this but I want find string X in
different column. The search must not be case sensitive.

So that searching "aBc" in "abcDef" return true. I don't want
META-CHaracter. Or at least I don't want meta-character to cause
errors (i.e.: No

Ok, how about a better way to do this?

select * from mytable where lower(mycol) LIKE lower("%" || lower(X) ||
"%");

Does this work? It seems that this may be the best way to handle this
sort of thing.

Best Wishes,
Chris Travers
Metatron Technology Consulting

ERROR: invalid regular expression: brackets [] not balanced.

Thanks for your help
/David

I found this in the manual .. but haven't found example :-(:
: ....with ***=, the rest of the RE is taken to be a literal
string, with all characters considered ordinary characters.

Read again the entire sentence, especially the first few words:

If an RE begins with ***=, the rest of the RE is taken to be a
literal string, with all characters considered ordinary characters.

Here are some examples:

SELECT 'test string' ~ 'test[*';
ERROR: invalid regular expression: brackets [] not balanced

SELECT 'test string' ~ '***=test[*';
?column? ----------
f
(1 row)

SELECT 'test[* string' ~ '***=test[*';
?column? ----------
t
(1 row)

---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings

#16Michael Fuhr
mike@fuhr.org
In reply to: David Gagnon (#15)
Re: Regular expression. How to disable ALL meta-character

On Thu, Apr 21, 2005 at 09:03:43AM -0400, David Gagnon wrote:

Just want to share the solution I got to solve my problem. I wanted to
be eable to search a string (say X) (non case sensitive) without having
meta-character involved. The X string come directy from the web so any
[%]* may cause error in regular expression (because they form non valid
expression)

1) Using like: select * from mytable where lower(mycol) LIKE lower("%"
|| lower(X) || "%");
Mostly perfect solution. Don't crash but % still have a special
meaning. Wich means anything

Have you considered using position() or strpos()? They do simple
substring searches without any metacharacters.

SELECT position(lower('AbC') in lower('aBcDeF'));
position
----------
1
(1 row)

SELECT position(lower('xYz') in lower('aBcDeF'));
position
----------
0
(1 row)

You might also want to look at the contrib/pg_trgm module to see
if it would be useful.

--
Michael Fuhr
http://www.fuhr.org/~mfuhr/