Skip to content

Commit 9362516

Browse files
committed
feat: add pg_stat_statements and improve schema safety
- Add pg_stat_statements extension to prepare-db (with IF NOT EXISTS) - Remove IF NOT EXISTS from postgres_ai schema creation (fails if exists, prompting user to run unprepare-db first) - Add tests to verify pg_stat_statements is not dropped by unprepare-db - Add tests to verify schema creation fails if exists
1 parent 8ccba96 commit 9362516

File tree

2 files changed

+49
-1
lines changed

2 files changed

+49
-1
lines changed

cli/sql/02.permissions.sql

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,18 @@
33
-- Allow connect
44
grant connect on database {{DB_IDENT}} to {{ROLE_IDENT}};
55

6+
-- Enable pg_stat_statements for query performance monitoring
7+
-- Note: Uses IF NOT EXISTS because extension may already be installed
8+
create extension if not exists pg_stat_statements;
9+
610
-- Standard monitoring privileges
711
grant pg_monitor to {{ROLE_IDENT}};
812
grant select on pg_catalog.pg_index to {{ROLE_IDENT}};
913

1014
-- Create postgres_ai schema for our objects
11-
create schema if not exists postgres_ai;
15+
-- Note: We intentionally do NOT use "IF NOT EXISTS" here.
16+
-- If the schema already exists, this will fail - user should run unprepare-db first.
17+
create schema postgres_ai;
1218
grant usage on schema postgres_ai to {{ROLE_IDENT}};
1319

1420
-- For bloat analysis: expose pg_statistic via a view

cli/test/init.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,48 @@ describe("init module", () => {
537537
expect(result.errors.length).toBe(1);
538538
expect(result.errors[0]).toMatch(/02\.revoke_permissions.*division by zero/);
539539
});
540+
541+
test("buildInitPlan includes pg_stat_statements extension", async () => {
542+
const plan = await init.buildInitPlan({
543+
database: "mydb",
544+
monitoringUser: DEFAULT_MONITORING_USER,
545+
monitoringPassword: "pw",
546+
includeOptionalPermissions: false,
547+
});
548+
549+
const permStep = plan.steps.find((s) => s.name === "02.permissions");
550+
expect(permStep).toBeTruthy();
551+
// Should create pg_stat_statements with IF NOT EXISTS
552+
expect(permStep!.sql).toMatch(/create extension if not exists pg_stat_statements/i);
553+
});
554+
555+
test("buildInitPlan does NOT use IF NOT EXISTS for postgres_ai schema", async () => {
556+
const plan = await init.buildInitPlan({
557+
database: "mydb",
558+
monitoringUser: DEFAULT_MONITORING_USER,
559+
monitoringPassword: "pw",
560+
includeOptionalPermissions: false,
561+
});
562+
563+
const permStep = plan.steps.find((s) => s.name === "02.permissions");
564+
expect(permStep).toBeTruthy();
565+
// Should create schema WITHOUT IF NOT EXISTS (will fail if exists)
566+
expect(permStep!.sql).toMatch(/create schema postgres_ai;/i);
567+
expect(permStep!.sql).not.toMatch(/create schema if not exists postgres_ai/i);
568+
});
569+
570+
test("buildUninitPlan does NOT drop pg_stat_statements extension", async () => {
571+
const plan = await init.buildUninitPlan({
572+
database: "mydb",
573+
monitoringUser: DEFAULT_MONITORING_USER,
574+
dropRole: true,
575+
});
576+
577+
// Check all steps - none should drop pg_stat_statements
578+
for (const step of plan.steps) {
579+
expect(step.sql.toLowerCase()).not.toMatch(/drop extension.*pg_stat_statements/);
580+
}
581+
});
540582
});
541583

542584
describe("CLI commands", () => {

0 commit comments

Comments
 (0)