Thread: Numerical variables in pqsql statements

Numerical variables in pqsql statements

From
"Michael Schmidt"
Date:
Folks,
I'm sure this is dumb, but I'm a little confused about use of numerical variables in pqsql.  It was my impression one had to use EXECUTE on a concatenated string including quote_literal() for the variable containing the value.  This can be quite a bit of trouble.  I just wrote a function that included the statement :
 
CREATE TEMPORARY TABLE author_names AS
      SELECT ra.ref_auth_key, a.last_name, a.first_name
      FROM ref_auth ra INNER JOIN authors a
      ON (ra.author_num = a.author_key)
      WHERE ra.ref_num = refer_num;
 
where refer_num is integer.  This worked (surprisingly, to me).  So, what is the rule regarding variables?  Would this query work if I concatenated a string together, including quote_literal(refer_num) and then EXECUTEd it?
 
Thanks and sorry to be so stupid.

Re: Numerical variables in pqsql statements

From
"Thomas F. O'Connell"
Date:
Michael,

PL/pgSQL variable interpolation works similarly to that in other
popular programming languages. If you have a statement -- whether
it's PERFORM, SELECT INTO, or EXECUTE -- a variable will get
interpolated during parsing if not escaped in a string. Per the
documentation, dynamic values in dynamic queries require special
handling since they might themselves contain quotes:

http://www.postgresql.org/docs/8.0/static/plpgsql-
statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN

But your temp table statement below is fine if you know that there
will never be quotes in refer_num.

And it would work similarly if you built it dynamically via string
concatenation as a query to be executed with quote_literal escaping
for refer_num.

Typically, you need to protect yourself against user input to a
function. If you're computing values in the function body that you
know to be safe or passing in safe values generated elsewhere in the
application, you're less likely to need to quote your variables
explicitly or to build queries dynamically.

--
Thomas F. O'Connell
Co-Founder, Information Architect
Sitening, LLC

Strategic Open Source: Open Your i™

http://www.sitening.com/
110 30th Avenue North, Suite 6
Nashville, TN 37203-6320
615-469-5150
615-469-5151 (fax)

On Aug 21, 2005, at 7:43 PM, Michael Schmidt wrote:

> Folks,
> I'm sure this is dumb, but I'm a little confused about use of
> numerical variables in pqsql.  It was my impression one had to use
> EXECUTE on a concatenated string including quote_literal() for the
> variable containing the value.  This can be quite a bit of
> trouble.  I just wrote a function that included the statement :
>
> CREATE TEMPORARY TABLE author_names AS
>       SELECT ra.ref_auth_key, a.last_name, a.first_name
>       FROM ref_auth ra INNER JOIN authors a
>       ON (ra.author_num = a.author_key)
>       WHERE ra.ref_num = refer_num;
>
> where refer_num is integer.  This worked (surprisingly, to me).
> So, what is the rule regarding variables?  Would this query work if
> I concatenated a string together, including quote_literal
> (refer_num) and then EXECUTEd it?
>
> Thanks and sorry to be so stupid.



Re: Numerical variables in pqsql statements

From
"Thomas F. O'Connell"
Date:
Well, browse through this list:

http://www.postgresql.org/docs/books/

I can't make any recommendations, as I am fairly familiar with the
online documentation, which, when supported by the community, seems
to be pretty good.

--
Thomas F. O'Connell
Co-Founder, Information Architect
Sitening, LLC

Strategic Open Source: Open Your i™

http://www.sitening.com/
110 30th Avenue North, Suite 6
Nashville, TN 37203-6320
615-469-5150
615-469-5151 (fax)

On Aug 29, 2005, at 4:05 PM, Michael Schmidt wrote:

> Mr. O'Connell,
> Thanks so much for the insights.  Sorry about the basic nature of
> the question - perhaps a "PostgreSQL for Dummies" book would help me!
> Michael Schmidt
>



plpgsql question

From
Postgres Admin
Date:
Can I do something like this:

CREATE TABLE sample (id SERIAL, node INTEGER, parent INTEGER);
INSERT INTO sample(node,parent) VALUES(1,0);
INSERT INTO sample(node,parent) VALUES(2,0);
INSERT INTO sample(node,parent) VALUES(3,1);
INSERT INTO sample(node,parent) VALUES(4,3)

CREATE OR REPLACE FUNCTION article_display(anyelement, anyelement)
RETURNS SETOF samle AS $$
    DECLARE
        articleRow sample%ROWTYPE;
    BEGIN
        FOR articleRow IN SELECT comments
        FROM theirry.articles
        ORDER BY article_id
        DESC LIMIT $1
        OFFSET $2 LOOP
    RETURN NEXT articleRow;
    END LOOP;
    RETURN;
    END;
$$ LANGUAGE plpgsql;

Thanks,
J

Re: [ADMIN] plpgsql question

From
Michael Fuhr
Date:
On Tue, Aug 30, 2005 at 12:15:54PM -0400, Postgres Admin wrote:
>
> Can I do something like this:

It's good that you gave an example, but it would also be good to
give a summary of what you're trying to do and what trouble you're
having so people don't have to guess.

> CREATE TABLE sample (id SERIAL, node INTEGER, parent INTEGER);
> INSERT INTO sample(node,parent) VALUES(1,0);
> INSERT INTO sample(node,parent) VALUES(2,0);
> INSERT INTO sample(node,parent) VALUES(3,1);
> INSERT INTO sample(node,parent) VALUES(4,3)
>
> CREATE OR REPLACE FUNCTION article_display(anyelement, anyelement)
> RETURNS SETOF samle AS $$

I assume you want to return "SETOF sample", not "samle".  When
posting code please post the actual code you're running so typos
don't distract from the real problem (unless a typo *is* part of
the problem).

>     DECLARE
>         articleRow sample%ROWTYPE;
>     BEGIN
>         FOR articleRow IN SELECT comments
>         FROM theirry.articles

You're selecting a column of one table (theirry.articles) into a
row type variable of another table (sample).  If the value of
comments can't be converted to an integer (the type of sample's
first column) then you'll get a syntax error.  And what about the
other columns of sample?  What are you really trying to do here?

>         ORDER BY article_id
>         DESC LIMIT $1
>         OFFSET $2 LOOP

If you're using the function's arguments like this, why did you
declare them as anyelement instead of integer?

>     RETURN NEXT articleRow;
>     END LOOP;
>     RETURN;
>     END;
> $$ LANGUAGE plpgsql;

It's not clear what you're trying to do nor what problems you're
having.  Is this example real or a contrived facsimile of what
you're really trying to do?  Could you provide some more information?

--
Michael Fuhr

Re: [ADMIN] plpgsql question

From
Postgres Admin
Date:
I have data in one table called articles and I would like to make a
function in which takes certain data from it and display the results.

Example:

CREATE TABLE articles (
article_id serial,
title varchar(200),
posted timestamp,
article_subject varchar(200),
article_body text,
allow_comments boolean,
comments smallint
);

I understand one way to display a results I would like is creating a
TYPE with the columns needed.

CREATE TYPE articles_output AS (
article_id int
title varchar(200),
article_body text,
comments smallint
);

Now I would like the function to display data using the LIMIT and OFFSET
option
ex: SELECT title, article_body, comments FROM articles ORDER BY
article_id DESC *LIMIT 4 OFFSET 0*;

this is function I created:

CREATE OR REPLACE FUNCTION article_display(integer, integer)
RETURNS SETOF article_output AS $$
    DECLARE
    articleRow article_output%ROWTYPE;
    sampleRow RECORD;
    BEGIN
        FOR sampleRow IN SELECT title, article_body, comments
        FROM articles
        ORDER BY article_id
        DESC LIMIT $1
        OFFSET $2 LOOP
    RETURN NEXT sampleRow;
    END LOOP;
    RETURN;
    END;
$$ LANGUAGE plpgsql;

this is the error ->
ERROR:  set-valued function called in context that cannot accept a set
CONTEXT:  PL/pgSQL function "article_sample" line 10 at return next

Can I do this.... or are there better options?

Thanks for the help,
J

Re: [ADMIN] plpgsql question

From
Michael Fuhr
Date:
On Tue, Aug 30, 2005 at 01:59:04PM -0400, Postgres Admin wrote:
> ERROR:  set-valued function called in context that cannot accept a set
> CONTEXT:  PL/pgSQL function "article_sample" line 10 at return next

You don't show what you did to get this error, but I'd guess you
called the function like this:

  SELECT article_display(10, 0);  -- wrong

You should have called it like this:

  SELECT * FROM article_display(10, 0);

The function as posted has a few other problems, like returning the
wrong type (you return a RECORD variable instead of an article_output
variable) and not selecting enough columns for the declared return
type.  The return type also doesn't match the type shown in the
CREATE TYPE statement, and the CREATE TYPE statement fails with a
syntax error due to a missing comma.  As I mentioned previously,
please post the *exact* code you're running so typographic errors
in the message don't distract from the real problem.  Those typos
prevent people from loading the code into their own database so
they can test it unless they correct the mistakes, and then they
can't be sure they're running the same thing you are.

--
Michael Fuhr