Canonical TSAPI series DB schema v1.0.0
Single source of truth for the timeseries PostgreSQL schema shared by the Python (TSAPI_SERIESDB_PG_PY) and C++ (TSAPI_POSTGRES_CPP) libraries. SQL seeded byte-for-byte from TSAPI_SERIESDB_PG_PY/tsapi_pgdb/sql on 2026-09-02. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
commit
eed06559c0
17 changed files with 2080 additions and 0 deletions
111
sql/migrate/migrate_metadata_identity.sql
Normal file
111
sql/migrate/migrate_metadata_identity.sql
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
-- Migration: add identity constraints to the series registry and reference tables
|
||||
--
|
||||
-- meta.series had no primary key and no unique constraint, so two rows could
|
||||
-- describe the same series -- and copy_series() actively created that, by
|
||||
-- copying the source's table_id and db_schema. meta.currencies,
|
||||
-- meta.security_types and meta.timezones had no key on their natural
|
||||
-- identifier either, while add_currency()/add_security_type()/add_timezone()
|
||||
-- all catch IntegrityError and promise an "already exists" error that no
|
||||
-- constraint could raise.
|
||||
--
|
||||
-- These are small registries, not timeseries data. A btree key here costs
|
||||
-- almost nothing, and this is unrelated to the deliberate decision NOT to
|
||||
-- constrain series timestamps, where BRIN is used precisely because a btree
|
||||
-- would be prohibitive at millions of rows per series.
|
||||
--
|
||||
-- New databases get these from 04_indexes.sql. Run this against any database
|
||||
-- initialised before the fix.
|
||||
--
|
||||
-- Safe to run more than once: each constraint is added only if absent.
|
||||
--
|
||||
-- IMPORTANT: this ABORTS if duplicate rows already exist, printing what
|
||||
-- collides. It does not guess which row to keep -- that is a data decision.
|
||||
-- Resolve the duplicates, then run it again.
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
dup_count integer;
|
||||
dup_list text;
|
||||
BEGIN
|
||||
----------------------------------------------------------------------
|
||||
-- Pre-flight: refuse to run if any natural key already collides.
|
||||
----------------------------------------------------------------------
|
||||
SELECT count(*), string_agg(format('%s.%s', db_schema, table_name), ', ')
|
||||
INTO dup_count, dup_list
|
||||
FROM (SELECT db_schema, table_name FROM meta.series
|
||||
GROUP BY db_schema, table_name HAVING count(*) > 1) d;
|
||||
IF dup_count > 0 THEN
|
||||
RAISE EXCEPTION
|
||||
'meta.series has % duplicated (db_schema, table_name): %. '
|
||||
'Remove the extra rows, then re-run this migration.',
|
||||
dup_count, dup_list;
|
||||
END IF;
|
||||
|
||||
SELECT count(*), string_agg(table_id::text, ', ')
|
||||
INTO dup_count, dup_list
|
||||
FROM (SELECT table_id FROM meta.series
|
||||
GROUP BY table_id HAVING count(*) > 1) d;
|
||||
IF dup_count > 0 THEN
|
||||
RAISE EXCEPTION
|
||||
'meta.series has % duplicated table_id: %. Most likely created by '
|
||||
'copy_series() before it was fixed. Reassign with '
|
||||
'UPDATE meta.series SET table_id = nextval(''meta._table_meta__table_id_seq'') '
|
||||
'WHERE ... , then re-run this migration.',
|
||||
dup_count, dup_list;
|
||||
END IF;
|
||||
|
||||
SELECT count(*), string_agg(code, ', ')
|
||||
INTO dup_count, dup_list
|
||||
FROM (SELECT code FROM meta.currencies GROUP BY code HAVING count(*) > 1) d;
|
||||
IF dup_count > 0 THEN
|
||||
RAISE EXCEPTION 'meta.currencies has % duplicated code: %', dup_count, dup_list;
|
||||
END IF;
|
||||
|
||||
SELECT count(*), string_agg(code, ', ')
|
||||
INTO dup_count, dup_list
|
||||
FROM (SELECT code FROM meta.security_types GROUP BY code HAVING count(*) > 1) d;
|
||||
IF dup_count > 0 THEN
|
||||
RAISE EXCEPTION 'meta.security_types has % duplicated code: %', dup_count, dup_list;
|
||||
END IF;
|
||||
|
||||
SELECT count(*), string_agg(iana_name, ', ')
|
||||
INTO dup_count, dup_list
|
||||
FROM (SELECT iana_name FROM meta.timezones GROUP BY iana_name HAVING count(*) > 1) d;
|
||||
IF dup_count > 0 THEN
|
||||
RAISE EXCEPTION 'meta.timezones has % duplicated iana_name: %', dup_count, dup_list;
|
||||
END IF;
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- Add the constraints, skipping any that already exist.
|
||||
----------------------------------------------------------------------
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'series_pkey'
|
||||
AND conrelid = 'meta.series'::regclass) THEN
|
||||
ALTER TABLE meta.series ADD CONSTRAINT series_pkey PRIMARY KEY (table_id);
|
||||
RAISE NOTICE 'added meta.series primary key on (table_id)';
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'series_schema_table_key'
|
||||
AND conrelid = 'meta.series'::regclass) THEN
|
||||
ALTER TABLE meta.series ADD CONSTRAINT series_schema_table_key
|
||||
UNIQUE (db_schema, table_name);
|
||||
RAISE NOTICE 'added meta.series unique constraint on (db_schema, table_name)';
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'currencies_pkey'
|
||||
AND conrelid = 'meta.currencies'::regclass) THEN
|
||||
ALTER TABLE meta.currencies ADD CONSTRAINT currencies_pkey PRIMARY KEY (code);
|
||||
RAISE NOTICE 'added meta.currencies primary key on (code)';
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'security_types_pkey'
|
||||
AND conrelid = 'meta.security_types'::regclass) THEN
|
||||
ALTER TABLE meta.security_types ADD CONSTRAINT security_types_pkey PRIMARY KEY (code);
|
||||
RAISE NOTICE 'added meta.security_types primary key on (code)';
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'timezones_pkey'
|
||||
AND conrelid = 'meta.timezones'::regclass) THEN
|
||||
ALTER TABLE meta.timezones ADD CONSTRAINT timezones_pkey PRIMARY KEY (iana_name);
|
||||
RAISE NOTICE 'added meta.timezones primary key on (iana_name)';
|
||||
END IF;
|
||||
END $$;
|
||||
Loading…
Add table
Add a link
Reference in a new issue