Thread: Best way to create a sequence generator at run time?
Hi all, I am trying to write plpgsql that must create a sequence generators during runtime. The min/max values are provided as functionparameters. The following isn't working for me and I'm not too surprised, but not sure of the best way to proceed. I am guessing I needto use PERFORM, EXECUTE or cursors or something? == create or replace function my_number_assigner( p_floor int, p_ceiling int ) returns void as $$ create sequence num_generator minvalue p_floor maxvalue p_ceiling start with p_floor; end $$ language plpgsql; == ERROR: syntax error at or near "$1" LINE 1: create sequence num_generator minvalue $1 maxvalue $2 s... ^ QUERY: create sequence num_generator minvalue $1 maxvalue $2 start with $1 CONTEXT: SQL statement in PL/PgSQL function "my_number_assigner" near line 35 I presume that the create sequence expression wants to see literals instead of variables, right? I knew I was going to runinto this situation sooner or later. What should I be doing here? - Leon
Leon Starr <leon_starr@modelint.com> writes: > I presume that the create sequence expression wants to see literals instead of variables, right? I knew I was going torun into this situation sooner or later. What should I be doing here? You need to construct the CREATE SEQUENCE command as a string then EXECUTE it. CREATE SEQUENCE, like most other utility commands, doesn't handle parameters well. regards, tom lane
Thanks, Tom! Makes perfect sense. I would like to do something now, just a bit more advanced, but I can't help thinking that there must be a standard solutionand thought maybe you could point me in the right direction. I want to number a relvar (table) as a sub sequence of another relvar. So if I have Department and Document with Documentsnumbered within each Department, I am wondering what is the best approach. It's easy enough to just slap a sequencetype on Department.Number. But what about Document? I would need a new sequence object for each relation (row)in Department, since each Department handles its own document sequence. It's almost like I should have an attributeof Department of type 'sequence generator'. Is that doable? Otherwise, I am thinking of just using a naming scheme where each Department's sequence generator would be named somethinglike this: <dept_<dept_number>_docnumbering_seq The question then is simply: Am I heading down the right road? Or is there a simpler solution that is commonly appliedin this case or some cool trick I am missing? Thanks. - Leon On Sep 21, 2010, at 2:56 PM, Tom Lane wrote: > Leon Starr <leon_starr@modelint.com> writes: >> I presume that the create sequence expression wants to see literals instead of variables, right? I knew I was going torun into this situation sooner or later. What should I be doing here? > > You need to construct the CREATE SEQUENCE command as a string then > EXECUTE it. CREATE SEQUENCE, like most other utility commands, doesn't > handle parameters well. > > regards, tom lane > > -- > Sent via pgsql-novice mailing list (pgsql-novice@postgresql.org) > To make changes to your subscription: > http://www.postgresql.org/mailpref/pgsql-novice
I'm converging on a good solution, but have just one (hopefully) problem left. I need to get the nextval for a sequence whose name has been stored, and is thus not available prior to runtime. I am trying to use EXECUTE, but can't seem to get it right. Suggestions? Here's the function extract in question: create or replace function ... ) returns bigint as $$ declare self subsystem%rowtype; -- has an attribute where the sequence name is stored begin select * from subsystem into strict self where (name = p_subsystem and domain = p_domain); -- self.cnum_generator is a text value holding the name of the previously created sequence -- I've tested to ensure that it is holding the correct value, so no worries there, it is a valid sequence -- Now here is the trouble - none of these statements seem to work or parse correctly: return execute 'nextval(' || self.cnum_generator || ')'; -- NOPE new_num := nextval(self.cnum_generator); -- I didn't expect this one to work, but might as well try, NOPE return query execute 'nextval( $1 )' using self.cnum_generator; -- no good either return query execute 'nextval(' || self.cnum_generator || ')'; -- NOPE -- accck! Phhht! Help!
Well I guess I'll be answering all my own questions today ;) And the correct answer turns out to be.... execute 'select nextval(' || quote_literal(self.cnum_generator) || ')' into my_cnum; return my_cnum; Was hoping to avoid the temporary variable (my_cnum), but hey, it works! And I'm off to the 9.0 release party in SF, see everyone there even though I won't know who anyone is! - Leon > I'm converging on a good solution, but have just one (hopefully) problem left. > I need to get the nextval for a sequence whose name has been stored, and is thus > not available prior to runtime. I am trying to use EXECUTE, but can't seem to get > it right. Suggestions? > > Here's the function extract in question: > > create or replace function ... > ) returns bigint as > $$ > declare > self subsystem%rowtype; -- has an attribute where the sequence name is stored > begin > select * from subsystem into strict self where (name = p_subsystem and domain = p_domain); > > -- self.cnum_generator is a text value holding the name of the previously created sequence > -- I've tested to ensure that it is holding the correct value, so no worries there, it is a valid sequence > > -- Now here is the trouble - none of these statements seem to work or parse correctly: > > return execute 'nextval(' || self.cnum_generator || ')'; -- NOPE > > new_num := nextval(self.cnum_generator); -- I didn't expect this one to work, but might as well try, NOPE > > return query execute 'nextval( $1 )' using self.cnum_generator; -- no good either > > return query execute 'nextval(' || self.cnum_generator || ')'; -- NOPE > > -- accck! Phhht! Help!