|
3 | 3 | -- Based on https://pgwat.ch/latest/howto/metrics_db_bootstrap.html |
4 | 4 |
|
5 | 5 | -- Create the pgwatch role for measurements database |
6 | | -CREATE ROLE pgwatch WITH LOGIN PASSWORD 'pgwatchadmin'; |
| 6 | +create role pgwatch with login password 'pgwatchadmin'; |
7 | 7 |
|
8 | 8 | -- Create the measurements database owned by pgwatch |
9 | | -CREATE DATABASE measurements OWNER pgwatch; |
| 9 | +create database measurements owner pgwatch; |
10 | 10 |
|
11 | 11 | -- Switch to the measurements database context |
12 | 12 | \c measurements; |
13 | 13 |
|
14 | 14 | -- Create extensions that might be useful for metrics storage |
15 | | -CREATE EXTENSION IF NOT EXISTS btree_gist; |
16 | | -CREATE EXTENSION IF NOT EXISTS pg_stat_statements; |
| 15 | +create extension if not exists btree_gist; |
| 16 | +create extension if not exists pg_stat_statements; |
17 | 17 |
|
18 | 18 | -- Grant necessary permissions to pgwatch user |
19 | | -GRANT ALL PRIVILEGES ON DATABASE measurements TO pgwatch; |
20 | | -GRANT ALL PRIVILEGES ON SCHEMA public TO pgwatch; |
| 19 | +grant all privileges on database measurements to pgwatch; |
| 20 | +grant all privileges on schema public to pgwatch; |
21 | 21 |
|
22 | 22 |
|
23 | 23 |
|
24 | 24 | -- Create a partitioned table for queryid-to-query mappings with LIST partitioning by dbname |
25 | | -CREATE TABLE IF NOT EXISTS public.pgss_queryid_queries ( |
26 | | - time TIMESTAMPTZ NOT NULL, |
27 | | - dbname TEXT NOT NULL, |
28 | | - data JSONB NOT NULL, |
29 | | - tag_data JSONB |
30 | | -) PARTITION BY LIST (dbname); |
| 25 | +create table if not exists public.pgss_queryid_queries ( |
| 26 | + time timestamptz not null, |
| 27 | + dbname text not null, |
| 28 | + data jsonb not null, |
| 29 | + tag_data jsonb |
| 30 | +) partition by list (dbname); |
31 | 31 |
|
32 | 32 | -- Create indexes for efficient lookups |
33 | | -CREATE INDEX IF NOT EXISTS pgss_queryid_queries_dbname_time_idx ON public.pgss_queryid_queries (dbname, time); |
| 33 | +create index if not exists pgss_queryid_queries_dbname_time_idx on public.pgss_queryid_queries (dbname, time); |
34 | 34 |
|
35 | 35 | -- Use existing subpartitions schema |
36 | 36 |
|
37 | 37 |
|
38 | 38 | -- Set ownership and grant permissions to pgwatch |
39 | | -ALTER TABLE public.pgss_queryid_queries OWNER TO pgwatch; |
40 | | -GRANT ALL PRIVILEGES ON TABLE public.pgss_queryid_queries TO pgwatch; |
| 39 | +alter table public.pgss_queryid_queries owner to pgwatch; |
| 40 | +grant all privileges on table public.pgss_queryid_queries to pgwatch; |
41 | 41 | -- Ensure pgwatch can use sequences (if any are created) |
42 | | -GRANT USAGE ON SCHEMA public TO pgwatch; |
| 42 | +grant usage on schema public to pgwatch; |
43 | 43 | -- Grant permissions on all future tables in public schema |
44 | | -ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO pgwatch; |
| 44 | +alter default privileges in schema public grant all on tables to pgwatch; |
45 | 45 |
|
46 | | -CREATE OR REPLACE FUNCTION enforce_queryid_uniqueness() |
47 | | -RETURNS TRIGGER AS $$ |
48 | | -DECLARE |
49 | | - queryid_value TEXT; |
50 | | -BEGIN |
| 46 | +create or replace function enforce_queryid_uniqueness() |
| 47 | +returns trigger as $$ |
| 48 | +declare |
| 49 | + queryid_value text; |
| 50 | +begin |
51 | 51 | -- Extract queryid from the data JSONB |
52 | | - queryid_value := NEW.data->>'queryid'; |
| 52 | + queryid_value := new.data->>'queryid'; |
53 | 53 |
|
54 | 54 | -- Allow NULL queryids through |
55 | | - IF queryid_value IS NULL THEN |
56 | | - RETURN NEW; |
57 | | - END IF; |
| 55 | + if queryid_value is null then |
| 56 | + return new; |
| 57 | + end if; |
58 | 58 |
|
59 | 59 | -- Silently skip if duplicate exists |
60 | | - IF EXISTS ( |
61 | | - SELECT 1 |
62 | | - FROM pgss_queryid_queries |
63 | | - WHERE dbname = NEW.dbname |
64 | | - AND data->>'queryid' = queryid_value |
65 | | - LIMIT 1 |
66 | | - ) THEN |
67 | | - RETURN NULL; -- Cancels INSERT silently |
68 | | - END IF; |
| 60 | + if exists ( |
| 61 | + select 1 |
| 62 | + from pgss_queryid_queries |
| 63 | + where dbname = new.dbname |
| 64 | + and data->>'queryid' = queryid_value |
| 65 | + limit 1 |
| 66 | + ) then |
| 67 | + return null; -- Cancels INSERT silently |
| 68 | + end if; |
69 | 69 |
|
70 | | - RETURN NEW; |
71 | | -END; |
72 | | -$$ LANGUAGE plpgsql; |
| 70 | + return new; |
| 71 | +end; |
| 72 | +$$ language plpgsql; |
73 | 73 |
|
74 | 74 |
|
75 | | -CREATE OR REPLACE TRIGGER enforce_queryid_uniqueness_trigger |
76 | | - BEFORE INSERT |
77 | | - ON pgss_queryid_queries |
78 | | - FOR EACH ROW |
79 | | - EXECUTE FUNCTION enforce_queryid_uniqueness(); |
| 75 | +create or replace trigger enforce_queryid_uniqueness_trigger |
| 76 | + before insert |
| 77 | + on pgss_queryid_queries |
| 78 | + for each row |
| 79 | + execute function enforce_queryid_uniqueness(); |
| 80 | + |
| 81 | +-- Create a partitioned table for index definitions with LIST partitioning by dbname |
| 82 | +create table if not exists public.index_definitions ( |
| 83 | + time timestamptz not null, |
| 84 | + dbname text not null, |
| 85 | + data jsonb not null, |
| 86 | + tag_data jsonb |
| 87 | +) partition by list (dbname); |
| 88 | + |
| 89 | +-- Create indexes for efficient lookups |
| 90 | +create index if not exists index_definitions_dbname_time_idx on public.index_definitions (dbname, time); |
| 91 | + |
| 92 | +-- Set ownership and grant permissions to pgwatch |
| 93 | +alter table public.index_definitions owner to pgwatch; |
| 94 | +grant all privileges on table public.index_definitions to pgwatch; |
| 95 | + |
| 96 | +-- Create function to enforce index definition uniqueness |
| 97 | +create or replace function enforce_index_definition_uniqueness() |
| 98 | +returns trigger as $$ |
| 99 | +declare |
| 100 | + index_name text; |
| 101 | + schema_name text; |
| 102 | + table_name text; |
| 103 | + index_definition text; |
| 104 | +begin |
| 105 | + -- Extract index information from the data JSONB |
| 106 | + index_name := new.data->>'indexrelname'; |
| 107 | + schema_name := new.data->>'schemaname'; |
| 108 | + table_name := new.data->>'relname'; |
| 109 | + index_definition := new.data->>'index_definition'; |
| 110 | + |
| 111 | + -- Allow NULL index names through |
| 112 | + if index_name is null then |
| 113 | + return new; |
| 114 | + end if; |
| 115 | + |
| 116 | + -- Silently skip if duplicate exists |
| 117 | + if exists ( |
| 118 | + select 1 |
| 119 | + from index_definitions |
| 120 | + where dbname = new.dbname |
| 121 | + and data->>'indexrelname' = index_name |
| 122 | + and data->>'schemaname' = schema_name |
| 123 | + and data->>'relname' = table_name |
| 124 | + and data->>'index_definition' = index_definition |
| 125 | + limit 1 |
| 126 | + ) then |
| 127 | + return null; -- Cancels INSERT silently |
| 128 | + end if; |
| 129 | + |
| 130 | + return new; |
| 131 | +end; |
| 132 | +$$ language plpgsql; |
| 133 | + |
| 134 | +create or replace trigger enforce_index_definition_uniqueness_trigger |
| 135 | + before insert |
| 136 | + on index_definitions |
| 137 | + for each row |
| 138 | + execute function enforce_index_definition_uniqueness(); |
80 | 139 |
|
81 | 140 |
|
0 commit comments