Tuesday, February 16 2010
PostgreSQL, catalogs

Resetting sequences. All of them, please!

So, after restoring a production dump with intermediate filtering, none of our sequences were set to the right value. I could have tried to review the process of filtering the dump here, but it's a one-shot action and you know what that sometimes mean. With some pressure you don't script enough of it and you just crawl more and more.

Still, I think how I solved it is worthy of a blog entry. Not that it's about a super unusual clever trick, quite the contrary, because questions involving this trick are often encountered on the support IRC.

The idea is to query the catalog for all sequences, and produce from there the SQL command you will have to issue for each of them. Once you have this query, it's quite easy to arrange from the psql prompt as if you had dynamic scripting capabilities. Of course in 9.0 you will have inline anonymous DO blocks.

#> \o /tmp/sequences.sql
#> \t
Showing only tuples.
#> YOUR QUERY HERE
#> \o
#> \t
Tuples only is off.

Once you have the /tmp/sequences.sql file, you can ask psql to execute its command as you're used to, that's using \i in an explicit transaction block.

Now, the interresting part if you got here attracted by the blog entry title is in fact the query itself. A nice way to start is to \set ECHO_HIDDEN then describe some table, you now have a catalog example query to work with. Then you tweak it somehow and get this:

SELECT 'select ' 
        || trim(trailing ')' 
           from replace(pg_get_expr(d.adbin, d.adrelid),
                        'nextval', 'setval'))
        || ', (select max( ' || a.attname || ') from only '
        || nspname || '.' || relname || '));' 
  FROM pg_class c 
       JOIN pg_namespace n on n.oid = c.relnamespace 
       JOIN pg_attribute a on a.attrelid = c.oid
       JOIN pg_attrdef d on d.adrelid = a.attrelid 
                          and d.adnum = a.attnum
                          and a.atthasdef 
 WHERE relkind = 'r' and a.attnum > 0 
       and pg_get_expr(d.adbin, d.adrelid) ~ '^nextval';

Coming next, a recode based script in order to get from SQL_ASCII to UTF-8, and some strange looking queries too.

recode.sh [-npdf0TI] [-U user ] -s schema [-m mintable] pattern

Stay tuned!