Thread: CREATE SEQUENCE fails in plpgsql function

CREATE SEQUENCE fails in plpgsql function

From
Erik Erkelens
Date:
Hi,

I need a table to hold the last n INSERTs into it. 

To keep track of how many entries there are, and to
provide a unique id to order the records in the table,
I use a sequence. A trigger function deletes and entry
on an insert if the table is full.  

The number n maybe changed, so I implemented this
PL/PgSQL function:

CREATE OR REPLACE FUNCTION set_max_records(integer)
RETURNS integer AS '   DECLARE        new_max_records ALIAS FOR $1;   BEGIN       DROP SEQUENCE my_sequence;
--CREATESEQUENCE my_sequence MAXVALUE 4
 
CYCLE;       CREATE SEQUENCE my_sequence MAXVALUE
new_max_records CYCLE;       RETURN 0;   END;   
' LANGUAGE 'plpgsql';

(I left out the part where the table is shrunk and
renumbered if n goes down).


rdb=# select set_max_records(3);
LOG:  query: CREATE SEQUENCE my_sequence MAXVALUE  $1 
CYCLE
LOG:  statement: select set_max_records(3);
WARNING:  Error occurred while executing PL/pgSQL
function set_max_records
LOG:  statement: select set_max_records(3);
WARNING:  line 6 at SQL statement
LOG:  statement: select set_max_records(3);
DEBUG:  AbortCurrentTransaction
ERROR:  parser: parse error at or near "$1" at
character 39

If I don't use the variable new_max_records, it works
(the commented out line). What could be the problem ?

Also, if there is a better mechanism to implement
this, I'm all ears...

Erik Erkelens.

__________________________________
Do you Yahoo!?
SBC Yahoo! DSL - Now only $29.95 per month!
http://sbc.yahoo.com


Re: CREATE SEQUENCE fails in plpgsql function

From
Stephan Szabo
Date:
On Mon, 30 Jun 2003, Erik Erkelens wrote:

>         new_max_records ALIAS FOR $1;
>     BEGIN
>         DROP SEQUENCE my_sequence;
>         --CREATE SEQUENCE my_sequence MAXVALUE 4
> CYCLE;
>         CREATE SEQUENCE my_sequence MAXVALUE
> new_max_records CYCLE;

Most of the creates/drops/etc... don't directly work with
variables/arguments.  You can probably do this with execute
however.




Re: CREATE SEQUENCE fails in plpgsql function

From
Tom Lane
Date:
Erik Erkelens <erik_erkelens@yahoo.com> writes:
>     DECLARE 
>         new_max_records ALIAS FOR $1;
>     BEGIN
>         CREATE SEQUENCE my_sequence MAXVALUE new_max_records CYCLE;

> ERROR:  parser: parse error at or near "$1" at character 39

You'll need to use EXECUTE to construct and execute that CREATE
SEQUENCE.  Utility statements generally don't accept runtime parameters,
which is what the plpgsql variable looks like to the main parser.

> Also, if there is a better mechanism to implement
> this, I'm all ears...

There's an ALTER SEQUENCE command in CVS tip, though I'm not sure
I trust it in concurrent-usage scenarios :-(
        regards, tom lane


Re: CREATE SEQUENCE fails in plpgsql function

From
Rod Taylor
Date:
On Tue, 2003-07-01 at 13:33, Tom Lane wrote:
> Erik Erkelens <erik_erkelens@yahoo.com> writes:
> >     DECLARE
> >         new_max_records ALIAS FOR $1;
> >     BEGIN
> >         CREATE SEQUENCE my_sequence MAXVALUE new_max_records CYCLE;
>
> > ERROR:  parser: parse error at or near "$1" at character 39
>
> You'll need to use EXECUTE to construct and execute that CREATE
> SEQUENCE.  Utility statements generally don't accept runtime parameters,
> which is what the plpgsql variable looks like to the main parser.
>
> > Also, if there is a better mechanism to implement
> > this, I'm all ears...
>
> There's an ALTER SEQUENCE command in CVS tip, though I'm not sure
> I trust it in concurrent-usage scenarios :-(

It shouldn't be trusted anymore than setval() should be. That is,
changes take place immediately.

Seems to me you might be better off just creating a 'count' table.
Update the single row when it changes.  By dropping / recreating the
sequence you've already blocked concurrent transactions.  The single row
would have less to vacuum, where the sequence has quite a bit more.

Another alternative is to use setval() on the sequence BUT first pull a
FOR UPDATE lock on some blocking row (for concurrency reasons).

SELECT * FROM pg_class WHERE relname = 'sequence name' FOR UPDATE;
SELECT setval(<max number>);

This would work equally well with ALTER SEQUENCE in 7.4.

--
Rod Taylor <rbt@rbt.ca>

PGP Key: http://www.rbt.ca/rbtpub.asc