Funkcje te są obarczone niebezpieczeństwem, gdy nazwy sekwencji, nazwy kolumn, nazwy tabel lub nazwy schematów mają zabawne znaki, takie jak spacje, znaki interpunkcyjne i tym podobne. Napisałem to:
CREATE OR REPLACE FUNCTION sequence_max_value(oid) RETURNS bigint
VOLATILE STRICT LANGUAGE plpgsql AS $$
DECLARE
tabrelid oid;
colname name;
r record;
newmax bigint;
BEGIN
FOR tabrelid, colname IN SELECT attrelid, attname
FROM pg_attribute
WHERE (attrelid, attnum) IN (
SELECT adrelid::regclass,adnum
FROM pg_attrdef
WHERE oid IN (SELECT objid
FROM pg_depend
WHERE refobjid = $1
AND classid = 'pg_attrdef'::regclass
)
) LOOP
FOR r IN EXECUTE 'SELECT max(' || quote_ident(colname) || ') FROM ' || tabrelid::regclass LOOP
IF newmax IS NULL OR r.max > newmax THEN
newmax := r.max;
END IF;
END LOOP;
END LOOP;
RETURN newmax;
END; $$ ;
Możesz wywołać ją dla pojedynczej sekwencji, przekazując jej identyfikator OID, a ona zwróci najwyższy numer używany przez dowolną tabelę, która ma domyślną sekwencję; lub możesz uruchomić go z takim zapytaniem, aby zresetować wszystkie sekwencje w bazie danych:
select relname, setval(oid, sequence_max_value(oid))
from pg_class
where relkind = 'S';
Używając innej jakości możesz zresetować tylko sekwencję w określonym schemacie i tak dalej. Na przykład, jeśli chcesz dostosować sekwencje w schemacie „publicznym”:
select relname, setval(pg_class.oid, sequence_max_value(pg_class.oid))
from pg_class, pg_namespace
where pg_class.relnamespace = pg_namespace.oid and
nspname = 'public' and
relkind = 'S';
Zauważ, że z powodu działania setval () nie musisz dodawać 1 do wyniku.
Na zakończenie muszę ostrzec, że niektóre bazy danych wydają się mieć domyślne ustawienia łączące z sekwencjami w sposób, który nie pozwala katalogom systemowym mieć pełnych informacji na ich temat. Dzieje się tak, gdy widzisz takie rzeczy w psql \ d:
alvherre=# \d baz
Tabla «public.baz»
Columna | Tipo | Modificadores
---------+---------+------------------------------------------------
a | integer | default nextval(('foo_a_seq'::text)::regclass)
Zauważ, że wywołanie nextval () w tej domyślnej klauzuli ma rzutowanie :: text oprócz rzutowania :: regclass. Myślę, że jest to spowodowane tym, że bazy danych są pg_dump'ed ze starych wersji PostgreSQL. To, co się stanie, to funkcja powyższej tabeli sekwencja_max_value () zignoruje taką tabelę. Aby rozwiązać problem, możesz ponownie zdefiniować klauzulę DOMYŚLNĄ, aby odwoływała się do sekwencji bezpośrednio bez rzutowania:
alvherre=# alter table baz alter a set default nextval('foo_a_seq');
ALTER TABLE
Następnie psql wyświetla go poprawnie:
alvherre=# \d baz
Tabla «public.baz»
Columna | Tipo | Modificadores
---------+---------+----------------------------------------
a | integer | default nextval('foo_a_seq'::regclass)
Jak tylko to naprawisz, funkcja działa poprawnie dla tej tabeli, jak również dla wszystkich innych, które mogą używać tej samej sekwencji.