What are the rules governing how a bind variable can be used in Postgres and where is this defined?

Posted by Craig Miles on Stack Overflow See other posts from Stack Overflow or by Craig Miles
Published on 2013-10-18T03:24:05Z Indexed on 2013/10/18 3:54 UTC
Read the original article Hit count: 185

Filed under:
|

I can have a table and function defined as:

CREATE TABLE mytable
(
  mycol integer
);

INSERT INTO mytable VALUES (1);

CREATE OR REPLACE FUNCTION myfunction (l_myvar integer) RETURNS mytable AS $$

DECLARE
l_myrow mytable;

BEGIN

SELECT      *
INTO        l_myrow
FROM        mytable
WHERE       mycol = l_myvar;

RETURN l_myrow;

END;
$$ LANGUAGE plpgsql;

In this case l_myvar acts as a bind variable for the value passed when I call:

SELECT * FROM myfunction(1);

and returns the row where mycol = 1

If I redefine the function as:

CREATE OR REPLACE FUNCTION myfunction (l_myvar integer) RETURNS mytable AS $$

DECLARE
l_myrow mytable;

BEGIN

SELECT      *
INTO        l_myrow
FROM        mytable
WHERE       mycol IN (l_myvar);

RETURN l_myrow;

END;
$$ LANGUAGE plpgsql;

SELECT * FROM myfunction(1);

still returns the row where mycol = 1

However, if I now change the function definition to allow me to pass an integer array and try to this array in the IN clause, I get an error:

CREATE OR REPLACE FUNCTION myfunction (l_myvar integer[]) RETURNS mytable AS $$

DECLARE
l_myrow mytable;

BEGIN

SELECT      *
INTO        l_myrow
FROM        mytable
WHERE       mycol IN (array_to_string(l_myvar, ','));

RETURN l_myrow;

END;
$$ LANGUAGE plpgsql;

Analysis reveals that although:

SELECT array_to_string(ARRAY[1, 2], ',');

returns 1,2 as expected

SELECT * FROM myfunction(ARRAY[1, 2]);

returns the error

operator does not exist: integer = text

at the line:

WHERE       mycol IN (array_to_string(l_myvar, ','));

If I execute:

SELECT      *
FROM        mytable
WHERE       mycol IN (1,2);

I get the expected result.

Given that array_to_string(l_myvar, ',') evaluates to 1,2 as shown, why arent these statements equivalent.

From the error message it is something to do with datatypes, but doesnt the IN(variable) construct appear to be behaving differently from the = variable construct?

What are the rules here?

I know that I could build a statement to EXECUTE, treating everything as a string, to achieve what I want to do, so I am not looking for that as a solution. I do want to understand though what is going on in this example. Is there a modification to this approach to make it work, the particular example being to pass in an array of values to build a dynamic IN clause without resorting to EXECUTE?

Thanks in advance

Craig

© Stack Overflow or respective owner

Related posts about sql

Related posts about postgresql