-- Indexes and constraints -- Generated: 2025-10-15T12:24:56.570321 -- Primary key constraints for metadata tables ALTER TABLE meta.instruments ADD CONSTRAINT instruments_pkey PRIMARY KEY (symbol, exchange); ALTER TABLE meta.exchanges ADD CONSTRAINT exchanges_pkey PRIMARY KEY (id); ALTER TABLE meta.sessions ADD CONSTRAINT sessions_pkey PRIMARY KEY (name); -- Identity constraints for the series registry and reference tables. -- -- These are small registries, not timeseries data: a btree key here costs -- almost nothing. This is unrelated to the deliberate decision NOT to put a -- unique constraint on series timestamps, where BRIN is used precisely -- because a btree would be prohibitive at millions of rows per series. -- -- Without these, duplicate registry rows were possible and the add_* methods -- advertised "already exists" errors that no constraint could raise. ALTER TABLE meta.series ADD CONSTRAINT series_pkey PRIMARY KEY (table_id); ALTER TABLE meta.series ADD CONSTRAINT series_schema_table_key UNIQUE (db_schema, table_name); ALTER TABLE meta.currencies ADD CONSTRAINT currencies_pkey PRIMARY KEY (code); ALTER TABLE meta.security_types ADD CONSTRAINT security_types_pkey PRIMARY KEY (code); ALTER TABLE meta.timezones ADD CONSTRAINT timezones_pkey PRIMARY KEY (iana_name); -- Series schema registry. Names follow the table-name rule shared by both -- clients: lower case, [a-z_][a-z0-9_]*, at most 63 bytes, never quoted. ALTER TABLE meta.series_schemas ADD CONSTRAINT series_schemas_pkey PRIMARY KEY (name); ALTER TABLE meta.series_schemas ADD CONSTRAINT series_schemas_name_check CHECK (name ~ '^[a-z_][a-z0-9_]*$' AND octet_length(name) <= 63); -- A series may only live in a registered schema -- enforced here, so no -- client can bypass it. RESTRICT: a schema cannot be unregistered while it -- still holds series. ALTER TABLE meta.series ADD CONSTRAINT series_db_schema_fkey FOREIGN KEY (db_schema) REFERENCES meta.series_schemas (name) ON UPDATE RESTRICT ON DELETE RESTRICT; -- Table names follow the same rule (Core contract 6 in both clients). ALTER TABLE meta.series ADD CONSTRAINT series_table_name_check CHECK (table_name ~ '^[a-z_][a-z0-9_]*$' AND octet_length(table_name) <= 63); -- Holiday calendar registry (1.5.0). citext keys: unique and referenced -- case-insensitively, stored as given. ALTER TABLE meta.holiday_calendars ADD CONSTRAINT holiday_calendars_pkey PRIMARY KEY (name); ALTER TABLE meta.holiday_calendars ADD CONSTRAINT holiday_calendars_name_check CHECK (name <> '' AND name::text = btrim(name::text) AND char_length(name::text) <= 50); ALTER TABLE meta.holiday_calendars ADD CONSTRAINT holiday_calendars_coverage_check CHECK ((covered_from IS NULL) = (covered_to IS NULL) AND (covered_from IS NULL OR covered_from <= covered_to)); -- Holidays belong to their calendar: dropping the calendar drops them. ALTER TABLE meta.holidays ADD CONSTRAINT holidays_calendar_fkey FOREIGN KEY (calendar_name) REFERENCES meta.holiday_calendars (name) ON UPDATE CASCADE ON DELETE CASCADE; -- A calendar still named by an exchange or instrument cannot be dropped. ALTER TABLE meta.exchanges ADD CONSTRAINT exchanges_holiday_calendar_fkey FOREIGN KEY (default_holiday_calendar) REFERENCES meta.holiday_calendars (name) ON UPDATE CASCADE ON DELETE RESTRICT; ALTER TABLE meta.instruments ADD CONSTRAINT instruments_holiday_calendar_fkey FOREIGN KEY (holiday_calendar) REFERENCES meta.holiday_calendars (name) ON UPDATE CASCADE ON DELETE RESTRICT; CREATE INDEX idx_event_log_series_timestamp ON log.event_log USING btree (series_name, "timestamp" DESC); CREATE INDEX idx_event_log_timestamp ON log.event_log USING btree ("timestamp" DESC); CREATE INDEX idx_event_log_event_type ON log.event_log USING btree (event_type); CREATE INDEX idx_series_create_timestamp_desc ON meta.series USING btree (create_timestamp DESC NULLS LAST); CREATE INDEX idx_series_db_schema ON meta.series USING btree (db_schema) WHERE ((db_schema IS NOT NULL) AND ((db_schema)::text <> ''::text)); CREATE INDEX idx_series_exchange_pattern ON meta.series USING btree (lower((exchange)::text) text_pattern_ops) WHERE ((exchange IS NOT NULL) AND ((exchange)::text <> ''::text)); CREATE INDEX idx_series_frequency_pattern ON meta.series USING btree (lower((frequency)::text) text_pattern_ops) WHERE ((frequency IS NOT NULL) AND ((frequency)::text <> ''::text)); CREATE INDEX idx_series_symbol_exchange ON meta.series USING btree (lower((symbol)::text), lower((exchange)::text)) WHERE ((symbol IS NOT NULL) AND ((symbol)::text <> ''::text) AND (exchange IS NOT NULL) AND ((exchange)::text <> ''::text)); CREATE INDEX idx_series_symbol_pattern ON meta.series USING btree (lower((symbol)::text) text_pattern_ops) WHERE ((symbol IS NOT NULL) AND ((symbol)::text <> ''::text)); CREATE INDEX idx_series_symbol_trgm ON meta.series USING gin (symbol public.gin_trgm_ops) WHERE ((symbol IS NOT NULL) AND ((symbol)::text <> ''::text)); CREATE INDEX idx_series_table_name_trgm ON meta.series USING gin (table_name public.gin_trgm_ops) WHERE ((table_name IS NOT NULL) AND ((table_name)::text <> ''::text)); CREATE INDEX idx_series_type_pattern ON meta.series USING btree (lower((type)::text) text_pattern_ops) WHERE ((type IS NOT NULL) AND ((type)::text <> ''::text));