@neverinfamous/postgres-mcp 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +119 -46
- package/dist/__tests__/benchmarks/codemode.bench.js +3 -3
- package/dist/__tests__/benchmarks/codemode.bench.js.map +1 -1
- package/dist/__tests__/benchmarks/connection-pool.bench.js +3 -3
- package/dist/__tests__/benchmarks/connection-pool.bench.js.map +1 -1
- package/dist/__tests__/benchmarks/introspection-migration.bench.d.ts +11 -0
- package/dist/__tests__/benchmarks/introspection-migration.bench.d.ts.map +1 -0
- package/dist/__tests__/benchmarks/introspection-migration.bench.js +143 -0
- package/dist/__tests__/benchmarks/introspection-migration.bench.js.map +1 -0
- package/dist/__tests__/benchmarks/resource-prompts.bench.js +0 -64
- package/dist/__tests__/benchmarks/resource-prompts.bench.js.map +1 -1
- package/dist/__tests__/benchmarks/schema-parsing.bench.js +5 -5
- package/dist/__tests__/benchmarks/schema-parsing.bench.js.map +1 -1
- package/dist/__tests__/benchmarks/tool-filtering.bench.js +17 -8
- package/dist/__tests__/benchmarks/tool-filtering.bench.js.map +1 -1
- package/dist/__tests__/mocks/adapter.d.ts.map +1 -1
- package/dist/__tests__/mocks/adapter.js +2 -1
- package/dist/__tests__/mocks/adapter.js.map +1 -1
- package/dist/adapters/DatabaseAdapter.d.ts +6 -5
- package/dist/adapters/DatabaseAdapter.d.ts.map +1 -1
- package/dist/adapters/DatabaseAdapter.js +11 -20
- package/dist/adapters/DatabaseAdapter.js.map +1 -1
- package/dist/adapters/postgresql/PostgresAdapter.d.ts +5 -26
- package/dist/adapters/postgresql/PostgresAdapter.d.ts.map +1 -1
- package/dist/adapters/postgresql/PostgresAdapter.js +31 -526
- package/dist/adapters/postgresql/PostgresAdapter.js.map +1 -1
- package/dist/adapters/postgresql/prompts/index.js +1 -1
- package/dist/adapters/postgresql/prompts/index.js.map +1 -1
- package/dist/adapters/postgresql/resources/index.d.ts +1 -1
- package/dist/adapters/postgresql/resources/index.js +3 -3
- package/dist/adapters/postgresql/resources/index.js.map +1 -1
- package/dist/adapters/postgresql/schema-operations.d.ts +71 -0
- package/dist/adapters/postgresql/schema-operations.d.ts.map +1 -0
- package/dist/adapters/postgresql/schema-operations.js +561 -0
- package/dist/adapters/postgresql/schema-operations.js.map +1 -0
- package/dist/adapters/postgresql/schemas/admin.d.ts +4 -4
- package/dist/adapters/postgresql/schemas/admin.js +4 -4
- package/dist/adapters/postgresql/schemas/admin.js.map +1 -1
- package/dist/adapters/postgresql/schemas/backup.d.ts +2 -2
- package/dist/adapters/postgresql/schemas/backup.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/backup.js +1 -3
- package/dist/adapters/postgresql/schemas/backup.js.map +1 -1
- package/dist/adapters/postgresql/schemas/core/index.d.ts +6 -0
- package/dist/adapters/postgresql/schemas/core/index.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/core/index.js +6 -0
- package/dist/adapters/postgresql/schemas/core/index.js.map +1 -0
- package/dist/adapters/postgresql/schemas/{core.d.ts → core/queries.d.ts} +16 -171
- package/dist/adapters/postgresql/schemas/core/queries.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/{core.js → core/queries.js} +5 -213
- package/dist/adapters/postgresql/schemas/core/queries.js.map +1 -0
- package/dist/adapters/postgresql/schemas/core/transactions.d.ts +149 -0
- package/dist/adapters/postgresql/schemas/core/transactions.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/core/transactions.js +239 -0
- package/dist/adapters/postgresql/schemas/core/transactions.js.map +1 -0
- package/dist/adapters/postgresql/schemas/cron.d.ts +12 -12
- package/dist/adapters/postgresql/schemas/cron.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/cron.js +38 -10
- package/dist/adapters/postgresql/schemas/cron.js.map +1 -1
- package/dist/adapters/postgresql/schemas/extensions/citext.d.ts +222 -0
- package/dist/adapters/postgresql/schemas/extensions/citext.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/extensions/citext.js +306 -0
- package/dist/adapters/postgresql/schemas/extensions/citext.js.map +1 -0
- package/dist/adapters/postgresql/schemas/extensions/index.d.ts +15 -0
- package/dist/adapters/postgresql/schemas/extensions/index.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/extensions/index.js +20 -0
- package/dist/adapters/postgresql/schemas/extensions/index.js.map +1 -0
- package/dist/adapters/postgresql/schemas/extensions/kcache.d.ts +164 -0
- package/dist/adapters/postgresql/schemas/extensions/kcache.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/extensions/kcache.js +225 -0
- package/dist/adapters/postgresql/schemas/extensions/kcache.js.map +1 -0
- package/dist/adapters/postgresql/schemas/extensions/ltree.d.ts +253 -0
- package/dist/adapters/postgresql/schemas/extensions/ltree.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/extensions/ltree.js +430 -0
- package/dist/adapters/postgresql/schemas/extensions/ltree.js.map +1 -0
- package/dist/adapters/postgresql/schemas/extensions/pgcrypto.d.ts +251 -0
- package/dist/adapters/postgresql/schemas/extensions/pgcrypto.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/extensions/pgcrypto.js +294 -0
- package/dist/adapters/postgresql/schemas/extensions/pgcrypto.js.map +1 -0
- package/dist/adapters/postgresql/schemas/extensions/shared.d.ts +10 -0
- package/dist/adapters/postgresql/schemas/extensions/shared.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/extensions/shared.js +15 -0
- package/dist/adapters/postgresql/schemas/extensions/shared.js.map +1 -0
- package/dist/adapters/postgresql/schemas/index.d.ts +6 -6
- package/dist/adapters/postgresql/schemas/index.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/index.js +8 -8
- package/dist/adapters/postgresql/schemas/index.js.map +1 -1
- package/dist/adapters/postgresql/schemas/introspection.d.ts +19 -42
- package/dist/adapters/postgresql/schemas/introspection.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/introspection.js +72 -27
- package/dist/adapters/postgresql/schemas/introspection.js.map +1 -1
- package/dist/adapters/postgresql/schemas/jsonb/advanced.d.ts +270 -0
- package/dist/adapters/postgresql/schemas/jsonb/advanced.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/jsonb/advanced.js +371 -0
- package/dist/adapters/postgresql/schemas/jsonb/advanced.js.map +1 -0
- package/dist/adapters/postgresql/schemas/jsonb/basic.d.ts +283 -0
- package/dist/adapters/postgresql/schemas/jsonb/basic.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/jsonb/basic.js +456 -0
- package/dist/adapters/postgresql/schemas/jsonb/basic.js.map +1 -0
- package/dist/adapters/postgresql/schemas/jsonb/index.d.ts +6 -0
- package/dist/adapters/postgresql/schemas/jsonb/index.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/jsonb/index.js +6 -0
- package/dist/adapters/postgresql/schemas/jsonb/index.js.map +1 -0
- package/dist/adapters/postgresql/schemas/monitoring.d.ts +4 -4
- package/dist/adapters/postgresql/schemas/monitoring.js +2 -2
- package/dist/adapters/postgresql/schemas/monitoring.js.map +1 -1
- package/dist/adapters/postgresql/schemas/partitioning.d.ts +14 -14
- package/dist/adapters/postgresql/schemas/partitioning.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/partitioning.js +64 -46
- package/dist/adapters/postgresql/schemas/partitioning.js.map +1 -1
- package/dist/adapters/postgresql/schemas/partman.d.ts +16 -14
- package/dist/adapters/postgresql/schemas/partman.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/partman.js +9 -9
- package/dist/adapters/postgresql/schemas/partman.js.map +1 -1
- package/dist/adapters/postgresql/schemas/postgis/advanced.d.ts +429 -0
- package/dist/adapters/postgresql/schemas/postgis/advanced.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/postgis/advanced.js +495 -0
- package/dist/adapters/postgresql/schemas/postgis/advanced.js.map +1 -0
- package/dist/adapters/postgresql/schemas/{postgis.d.ts → postgis/basic.d.ts} +1 -423
- package/dist/adapters/postgresql/schemas/postgis/basic.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/{postgis.js → postgis/basic.js} +1 -486
- package/dist/adapters/postgresql/schemas/postgis/basic.js.map +1 -0
- package/dist/adapters/postgresql/schemas/postgis/index.d.ts +6 -0
- package/dist/adapters/postgresql/schemas/postgis/index.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/postgis/index.js +6 -0
- package/dist/adapters/postgresql/schemas/postgis/index.js.map +1 -0
- package/dist/adapters/postgresql/schemas/schema-mgmt.d.ts +35 -25
- package/dist/adapters/postgresql/schemas/schema-mgmt.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/schema-mgmt.js +57 -19
- package/dist/adapters/postgresql/schemas/schema-mgmt.js.map +1 -1
- package/dist/adapters/postgresql/schemas/stats/index.d.ts +6 -0
- package/dist/adapters/postgresql/schemas/stats/index.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/stats/index.js +6 -0
- package/dist/adapters/postgresql/schemas/stats/index.js.map +1 -0
- package/dist/adapters/postgresql/schemas/stats/input.d.ts +260 -0
- package/dist/adapters/postgresql/schemas/stats/input.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/{stats.js → stats/input.js} +2 -331
- package/dist/adapters/postgresql/schemas/stats/input.js.map +1 -0
- package/dist/adapters/postgresql/schemas/{stats.d.ts → stats/output.d.ts} +3 -246
- package/dist/adapters/postgresql/schemas/stats/output.d.ts.map +1 -0
- package/dist/adapters/postgresql/schemas/stats/output.js +334 -0
- package/dist/adapters/postgresql/schemas/stats/output.js.map +1 -0
- package/dist/adapters/postgresql/schemas/text-search.d.ts +18 -18
- package/dist/adapters/postgresql/schemas/text-search.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/text-search.js +12 -27
- package/dist/adapters/postgresql/schemas/text-search.js.map +1 -1
- package/dist/adapters/postgresql/schemas/vector.d.ts +10 -10
- package/dist/adapters/postgresql/schemas/vector.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/vector.js +9 -15
- package/dist/adapters/postgresql/schemas/vector.js.map +1 -1
- package/dist/adapters/postgresql/tools/backup/dump.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/backup/dump.js +95 -76
- package/dist/adapters/postgresql/tools/backup/dump.js.map +1 -1
- package/dist/adapters/postgresql/tools/backup/planning.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/backup/planning.js +345 -287
- package/dist/adapters/postgresql/tools/backup/planning.js.map +1 -1
- package/dist/adapters/postgresql/tools/citext/analysis.d.ts +24 -0
- package/dist/adapters/postgresql/tools/citext/analysis.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/{citext.js → citext/analysis.js} +50 -232
- package/dist/adapters/postgresql/tools/citext/analysis.js.map +1 -0
- package/dist/adapters/postgresql/tools/citext/index.d.ts +15 -0
- package/dist/adapters/postgresql/tools/citext/index.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/citext/index.js +23 -0
- package/dist/adapters/postgresql/tools/citext/index.js.map +1 -0
- package/dist/adapters/postgresql/tools/citext/setup.d.ts +16 -0
- package/dist/adapters/postgresql/tools/citext/setup.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/citext/setup.js +193 -0
- package/dist/adapters/postgresql/tools/citext/setup.js.map +1 -0
- package/dist/adapters/postgresql/tools/codemode/index.js +1 -1
- package/dist/adapters/postgresql/tools/codemode/index.js.map +1 -1
- package/dist/adapters/postgresql/tools/core/convenience.d.ts +12 -22
- package/dist/adapters/postgresql/tools/core/convenience.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/core/convenience.js +100 -210
- package/dist/adapters/postgresql/tools/core/convenience.js.map +1 -1
- package/dist/adapters/postgresql/tools/core/error-helpers.d.ts +1 -0
- package/dist/adapters/postgresql/tools/core/error-helpers.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/core/error-helpers.js +8 -1
- package/dist/adapters/postgresql/tools/core/error-helpers.js.map +1 -1
- package/dist/adapters/postgresql/tools/core/health.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/core/health.js +124 -114
- package/dist/adapters/postgresql/tools/core/health.js.map +1 -1
- package/dist/adapters/postgresql/tools/core/index.d.ts +2 -1
- package/dist/adapters/postgresql/tools/core/index.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/core/index.js +3 -2
- package/dist/adapters/postgresql/tools/core/index.js.map +1 -1
- package/dist/adapters/postgresql/tools/core/indexes.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/core/indexes.js +151 -127
- package/dist/adapters/postgresql/tools/core/indexes.js.map +1 -1
- package/dist/adapters/postgresql/tools/core/objects.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/core/objects.js +186 -161
- package/dist/adapters/postgresql/tools/core/objects.js.map +1 -1
- package/dist/adapters/postgresql/tools/core/query.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/core/query.js +37 -25
- package/dist/adapters/postgresql/tools/core/query.js.map +1 -1
- package/dist/adapters/postgresql/tools/core/schemas.d.ts +6 -3
- package/dist/adapters/postgresql/tools/core/schemas.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/core/schemas.js +11 -2
- package/dist/adapters/postgresql/tools/core/schemas.js.map +1 -1
- package/dist/adapters/postgresql/tools/core/tables.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/core/tables.js +156 -129
- package/dist/adapters/postgresql/tools/core/tables.js.map +1 -1
- package/dist/adapters/postgresql/tools/core/utility.d.ts +26 -0
- package/dist/adapters/postgresql/tools/core/utility.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/core/utility.js +174 -0
- package/dist/adapters/postgresql/tools/core/utility.js.map +1 -0
- package/dist/adapters/postgresql/tools/cron.js +90 -43
- package/dist/adapters/postgresql/tools/cron.js.map +1 -1
- package/dist/adapters/postgresql/tools/introspection/analysis.d.ts +12 -0
- package/dist/adapters/postgresql/tools/introspection/analysis.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/introspection/analysis.js +605 -0
- package/dist/adapters/postgresql/tools/introspection/analysis.js.map +1 -0
- package/dist/adapters/postgresql/tools/introspection/graph.d.ts +55 -0
- package/dist/adapters/postgresql/tools/introspection/graph.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/introspection/graph.js +621 -0
- package/dist/adapters/postgresql/tools/introspection/graph.js.map +1 -0
- package/dist/adapters/postgresql/tools/introspection/index.d.ts +21 -0
- package/dist/adapters/postgresql/tools/introspection/index.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/introspection/index.js +31 -0
- package/dist/adapters/postgresql/tools/introspection/index.js.map +1 -0
- package/dist/adapters/postgresql/tools/introspection/migration.d.ts +15 -0
- package/dist/adapters/postgresql/tools/introspection/migration.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/introspection/migration.js +575 -0
- package/dist/adapters/postgresql/tools/introspection/migration.js.map +1 -0
- package/dist/adapters/postgresql/tools/jsonb/analytics.d.ts +20 -0
- package/dist/adapters/postgresql/tools/jsonb/analytics.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/jsonb/analytics.js +367 -0
- package/dist/adapters/postgresql/tools/jsonb/analytics.js.map +1 -0
- package/dist/adapters/postgresql/tools/jsonb/index.d.ts +4 -2
- package/dist/adapters/postgresql/tools/jsonb/index.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/jsonb/index.js +8 -4
- package/dist/adapters/postgresql/tools/jsonb/index.js.map +1 -1
- package/dist/adapters/postgresql/tools/jsonb/read.d.ts +38 -0
- package/dist/adapters/postgresql/tools/jsonb/read.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/jsonb/{basic.js → read.js} +41 -482
- package/dist/adapters/postgresql/tools/jsonb/read.js.map +1 -0
- package/dist/adapters/postgresql/tools/jsonb/{advanced.d.ts → transform.d.ts} +1 -13
- package/dist/adapters/postgresql/tools/jsonb/transform.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/jsonb/{advanced.js → transform.js} +26 -357
- package/dist/adapters/postgresql/tools/jsonb/transform.js.map +1 -0
- package/dist/adapters/postgresql/tools/jsonb/write.d.ts +14 -0
- package/dist/adapters/postgresql/tools/jsonb/write.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/jsonb/write.js +468 -0
- package/dist/adapters/postgresql/tools/jsonb/write.js.map +1 -0
- package/dist/adapters/postgresql/tools/kcache.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/kcache.js +116 -51
- package/dist/adapters/postgresql/tools/kcache.js.map +1 -1
- package/dist/adapters/postgresql/tools/ltree.js +346 -260
- package/dist/adapters/postgresql/tools/ltree.js.map +1 -1
- package/dist/adapters/postgresql/tools/migration/index.d.ts +15 -0
- package/dist/adapters/postgresql/tools/migration/index.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/migration/index.js +23 -0
- package/dist/adapters/postgresql/tools/migration/index.js.map +1 -0
- package/dist/adapters/postgresql/tools/monitoring/analysis.d.ts +15 -0
- package/dist/adapters/postgresql/tools/monitoring/analysis.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/{monitoring.js → monitoring/analysis.js} +24 -359
- package/dist/adapters/postgresql/tools/monitoring/analysis.js.map +1 -0
- package/dist/adapters/postgresql/tools/monitoring/basic.d.ts +17 -0
- package/dist/adapters/postgresql/tools/monitoring/basic.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/monitoring/basic.js +432 -0
- package/dist/adapters/postgresql/tools/monitoring/basic.js.map +1 -0
- package/dist/adapters/postgresql/tools/monitoring/index.d.ts +16 -0
- package/dist/adapters/postgresql/tools/monitoring/index.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/monitoring/index.js +31 -0
- package/dist/adapters/postgresql/tools/monitoring/index.js.map +1 -0
- package/dist/adapters/postgresql/tools/partitioning/index.d.ts +15 -0
- package/dist/adapters/postgresql/tools/partitioning/index.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/partitioning/index.js +23 -0
- package/dist/adapters/postgresql/tools/partitioning/index.js.map +1 -0
- package/dist/adapters/postgresql/tools/partitioning/info.d.ts +11 -0
- package/dist/adapters/postgresql/tools/partitioning/info.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/partitioning/info.js +302 -0
- package/dist/adapters/postgresql/tools/partitioning/info.js.map +1 -0
- package/dist/adapters/postgresql/tools/partitioning/management.d.ts +28 -0
- package/dist/adapters/postgresql/tools/partitioning/management.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/{partitioning.js → partitioning/management.js} +48 -307
- package/dist/adapters/postgresql/tools/partitioning/management.js.map +1 -0
- package/dist/adapters/postgresql/tools/partman/helpers.d.ts +29 -0
- package/dist/adapters/postgresql/tools/partman/helpers.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/partman/helpers.js +59 -0
- package/dist/adapters/postgresql/tools/partman/helpers.js.map +1 -0
- package/dist/adapters/postgresql/tools/partman/index.d.ts +2 -1
- package/dist/adapters/postgresql/tools/partman/index.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/partman/index.js +4 -2
- package/dist/adapters/postgresql/tools/partman/index.js.map +1 -1
- package/dist/adapters/postgresql/tools/partman/maintenance.d.ts +20 -0
- package/dist/adapters/postgresql/tools/partman/maintenance.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/partman/maintenance.js +496 -0
- package/dist/adapters/postgresql/tools/partman/maintenance.js.map +1 -0
- package/dist/adapters/postgresql/tools/partman/management.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/partman/management.js +438 -383
- package/dist/adapters/postgresql/tools/partman/management.js.map +1 -1
- package/dist/adapters/postgresql/tools/partman/operations.d.ts +1 -13
- package/dist/adapters/postgresql/tools/partman/operations.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/partman/operations.js +171 -652
- package/dist/adapters/postgresql/tools/partman/operations.js.map +1 -1
- package/dist/adapters/postgresql/tools/performance/analysis.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/performance/analysis.js +69 -42
- package/dist/adapters/postgresql/tools/performance/analysis.js.map +1 -1
- package/dist/adapters/postgresql/tools/performance/anomaly-detection.d.ts +18 -0
- package/dist/adapters/postgresql/tools/performance/anomaly-detection.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/performance/anomaly-detection.js +533 -0
- package/dist/adapters/postgresql/tools/performance/anomaly-detection.js.map +1 -0
- package/dist/adapters/postgresql/tools/performance/diagnostics.d.ts +11 -0
- package/dist/adapters/postgresql/tools/performance/diagnostics.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/performance/diagnostics.js +332 -0
- package/dist/adapters/postgresql/tools/performance/diagnostics.js.map +1 -0
- package/dist/adapters/postgresql/tools/performance/index.d.ts +1 -1
- package/dist/adapters/postgresql/tools/performance/index.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/performance/index.js +7 -1
- package/dist/adapters/postgresql/tools/performance/index.js.map +1 -1
- package/dist/adapters/postgresql/tools/performance/monitoring.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/performance/monitoring.js +80 -55
- package/dist/adapters/postgresql/tools/performance/monitoring.js.map +1 -1
- package/dist/adapters/postgresql/tools/performance/optimization.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/performance/optimization.js +18 -11
- package/dist/adapters/postgresql/tools/performance/optimization.js.map +1 -1
- package/dist/adapters/postgresql/tools/performance/stats.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/performance/stats.js +439 -318
- package/dist/adapters/postgresql/tools/performance/stats.js.map +1 -1
- package/dist/adapters/postgresql/tools/pgcrypto.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/pgcrypto.js +45 -77
- package/dist/adapters/postgresql/tools/pgcrypto.js.map +1 -1
- package/dist/adapters/postgresql/tools/postgis/basic.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/postgis/basic.js +121 -93
- package/dist/adapters/postgresql/tools/postgis/basic.js.map +1 -1
- package/dist/adapters/postgresql/tools/schema/index.d.ts +16 -0
- package/dist/adapters/postgresql/tools/schema/index.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/schema/index.js +32 -0
- package/dist/adapters/postgresql/tools/schema/index.js.map +1 -0
- package/dist/adapters/postgresql/tools/schema/objects.d.ts +15 -0
- package/dist/adapters/postgresql/tools/schema/objects.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/schema/objects.js +378 -0
- package/dist/adapters/postgresql/tools/schema/objects.js.map +1 -0
- package/dist/adapters/postgresql/tools/schema/views.d.ts +15 -0
- package/dist/adapters/postgresql/tools/schema/views.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/{schema.js → schema/views.js} +64 -386
- package/dist/adapters/postgresql/tools/schema/views.js.map +1 -0
- package/dist/adapters/postgresql/tools/stats/advanced.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/stats/advanced.js +1 -218
- package/dist/adapters/postgresql/tools/stats/advanced.js.map +1 -1
- package/dist/adapters/postgresql/tools/stats/math-utils.d.ts +33 -0
- package/dist/adapters/postgresql/tools/stats/math-utils.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/stats/math-utils.js +225 -0
- package/dist/adapters/postgresql/tools/stats/math-utils.js.map +1 -0
- package/dist/adapters/postgresql/tools/text/index.d.ts +16 -0
- package/dist/adapters/postgresql/tools/text/index.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/text/index.js +33 -0
- package/dist/adapters/postgresql/tools/text/index.js.map +1 -0
- package/dist/adapters/postgresql/tools/text/matching.d.ts +17 -0
- package/dist/adapters/postgresql/tools/text/matching.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/text/matching.js +565 -0
- package/dist/adapters/postgresql/tools/text/matching.js.map +1 -0
- package/dist/adapters/postgresql/tools/text/search.d.ts +17 -0
- package/dist/adapters/postgresql/tools/text/search.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/text/search.js +653 -0
- package/dist/adapters/postgresql/tools/text/search.js.map +1 -0
- package/dist/adapters/postgresql/tools/transactions.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/transactions.js +11 -27
- package/dist/adapters/postgresql/tools/transactions.js.map +1 -1
- package/dist/adapters/postgresql/tools/vector/{basic.d.ts → data.d.ts} +10 -8
- package/dist/adapters/postgresql/tools/vector/data.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/vector/data.js +540 -0
- package/dist/adapters/postgresql/tools/vector/data.js.map +1 -0
- package/dist/adapters/postgresql/tools/vector/index.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/vector/index.js +6 -2
- package/dist/adapters/postgresql/tools/vector/index.js.map +1 -1
- package/dist/adapters/postgresql/tools/vector/management.d.ts +11 -0
- package/dist/adapters/postgresql/tools/vector/management.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/vector/management.js +425 -0
- package/dist/adapters/postgresql/tools/vector/management.js.map +1 -0
- package/dist/adapters/postgresql/tools/vector/query.d.ts +14 -0
- package/dist/adapters/postgresql/tools/vector/query.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/vector/query.js +767 -0
- package/dist/adapters/postgresql/tools/vector/query.js.map +1 -0
- package/dist/adapters/postgresql/tools/vector/{advanced.d.ts → search-advanced.d.ts} +4 -5
- package/dist/adapters/postgresql/tools/vector/search-advanced.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/vector/search-advanced.js +626 -0
- package/dist/adapters/postgresql/tools/vector/search-advanced.js.map +1 -0
- package/dist/auth/scopes.d.ts.map +1 -1
- package/dist/auth/scopes.js +3 -1
- package/dist/auth/scopes.js.map +1 -1
- package/dist/cli/args.d.ts +3 -2
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +4 -3
- package/dist/cli/args.js.map +1 -1
- package/dist/cli.js +16 -4
- package/dist/cli.js.map +1 -1
- package/dist/codemode/api/aliases.d.ts +14 -0
- package/dist/codemode/api/aliases.d.ts.map +1 -0
- package/dist/codemode/api/aliases.js +503 -0
- package/dist/codemode/api/aliases.js.map +1 -0
- package/dist/codemode/api/group-api.d.ts +23 -0
- package/dist/codemode/api/group-api.d.ts.map +1 -0
- package/dist/codemode/api/group-api.js +179 -0
- package/dist/codemode/api/group-api.js.map +1 -0
- package/dist/codemode/{api.d.ts → api/index.d.ts} +5 -4
- package/dist/codemode/api/index.d.ts.map +1 -0
- package/dist/codemode/api/index.js +195 -0
- package/dist/codemode/api/index.js.map +1 -0
- package/dist/codemode/api/maps.d.ts +47 -0
- package/dist/codemode/api/maps.d.ts.map +1 -0
- package/dist/codemode/api/maps.js +529 -0
- package/dist/codemode/api/maps.js.map +1 -0
- package/dist/codemode/api/normalize.d.ts +13 -0
- package/dist/codemode/api/normalize.d.ts.map +1 -0
- package/dist/codemode/api/normalize.js +120 -0
- package/dist/codemode/api/normalize.js.map +1 -0
- package/dist/codemode/index.d.ts +1 -1
- package/dist/codemode/index.d.ts.map +1 -1
- package/dist/codemode/index.js +1 -1
- package/dist/codemode/index.js.map +1 -1
- package/dist/codemode/sandbox.d.ts.map +1 -1
- package/dist/codemode/sandbox.js +8 -25
- package/dist/codemode/sandbox.js.map +1 -1
- package/dist/filtering/ToolConstants.d.ts +11 -11
- package/dist/filtering/ToolConstants.d.ts.map +1 -1
- package/dist/filtering/ToolConstants.js +28 -15
- package/dist/filtering/ToolConstants.js.map +1 -1
- package/dist/filtering/ToolFilter.d.ts +0 -32
- package/dist/filtering/ToolFilter.d.ts.map +1 -1
- package/dist/filtering/ToolFilter.js +0 -43
- package/dist/filtering/ToolFilter.js.map +1 -1
- package/dist/server/McpServer.d.ts +1 -1
- package/dist/server/McpServer.d.ts.map +1 -1
- package/dist/server/McpServer.js +1 -2
- package/dist/server/McpServer.js.map +1 -1
- package/dist/transports/http.d.ts +55 -10
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +301 -50
- package/dist/transports/http.js.map +1 -1
- package/dist/types/filtering.d.ts +1 -1
- package/dist/types/filtering.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/mcp.d.ts +0 -21
- package/dist/types/mcp.d.ts.map +1 -1
- package/dist/types/schema.d.ts +0 -79
- package/dist/types/schema.d.ts.map +1 -1
- package/dist/utils/fts-config.d.ts +0 -6
- package/dist/utils/fts-config.d.ts.map +1 -1
- package/dist/utils/fts-config.js +1 -1
- package/dist/utils/fts-config.js.map +1 -1
- package/dist/utils/icons.d.ts.map +1 -1
- package/dist/utils/icons.js +5 -0
- package/dist/utils/icons.js.map +1 -1
- package/dist/utils/identifiers.d.ts.map +1 -1
- package/dist/utils/identifiers.js +6 -6
- package/dist/utils/identifiers.js.map +1 -1
- package/dist/utils/logger.d.ts +6 -6
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +18 -15
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/progress-utils.d.ts +3 -14
- package/dist/utils/progress-utils.d.ts.map +1 -1
- package/dist/utils/progress-utils.js +2 -21
- package/dist/utils/progress-utils.js.map +1 -1
- package/dist/utils/version.d.ts +9 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +12 -0
- package/dist/utils/version.js.map +1 -0
- package/dist/utils/where-clause.d.ts +4 -0
- package/dist/utils/where-clause.d.ts.map +1 -1
- package/dist/utils/where-clause.js +16 -0
- package/dist/utils/where-clause.js.map +1 -1
- package/package.json +6 -4
- package/dist/adapters/postgresql/schemas/core.d.ts.map +0 -1
- package/dist/adapters/postgresql/schemas/core.js.map +0 -1
- package/dist/adapters/postgresql/schemas/extensions.d.ts +0 -852
- package/dist/adapters/postgresql/schemas/extensions.d.ts.map +0 -1
- package/dist/adapters/postgresql/schemas/extensions.js +0 -1202
- package/dist/adapters/postgresql/schemas/extensions.js.map +0 -1
- package/dist/adapters/postgresql/schemas/jsonb.d.ts +0 -541
- package/dist/adapters/postgresql/schemas/jsonb.d.ts.map +0 -1
- package/dist/adapters/postgresql/schemas/jsonb.js +0 -814
- package/dist/adapters/postgresql/schemas/jsonb.js.map +0 -1
- package/dist/adapters/postgresql/schemas/postgis.d.ts.map +0 -1
- package/dist/adapters/postgresql/schemas/postgis.js.map +0 -1
- package/dist/adapters/postgresql/schemas/stats.d.ts.map +0 -1
- package/dist/adapters/postgresql/schemas/stats.js.map +0 -1
- package/dist/adapters/postgresql/tools/citext.d.ts +0 -18
- package/dist/adapters/postgresql/tools/citext.d.ts.map +0 -1
- package/dist/adapters/postgresql/tools/citext.js.map +0 -1
- package/dist/adapters/postgresql/tools/introspection.d.ts +0 -15
- package/dist/adapters/postgresql/tools/introspection.d.ts.map +0 -1
- package/dist/adapters/postgresql/tools/introspection.js +0 -1682
- package/dist/adapters/postgresql/tools/introspection.js.map +0 -1
- package/dist/adapters/postgresql/tools/jsonb/advanced.d.ts.map +0 -1
- package/dist/adapters/postgresql/tools/jsonb/advanced.js.map +0 -1
- package/dist/adapters/postgresql/tools/jsonb/basic.d.ts +0 -20
- package/dist/adapters/postgresql/tools/jsonb/basic.d.ts.map +0 -1
- package/dist/adapters/postgresql/tools/jsonb/basic.js.map +0 -1
- package/dist/adapters/postgresql/tools/monitoring.d.ts +0 -13
- package/dist/adapters/postgresql/tools/monitoring.d.ts.map +0 -1
- package/dist/adapters/postgresql/tools/monitoring.js.map +0 -1
- package/dist/adapters/postgresql/tools/partitioning.d.ts +0 -13
- package/dist/adapters/postgresql/tools/partitioning.d.ts.map +0 -1
- package/dist/adapters/postgresql/tools/partitioning.js.map +0 -1
- package/dist/adapters/postgresql/tools/schema.d.ts +0 -13
- package/dist/adapters/postgresql/tools/schema.d.ts.map +0 -1
- package/dist/adapters/postgresql/tools/schema.js.map +0 -1
- package/dist/adapters/postgresql/tools/text.d.ts +0 -13
- package/dist/adapters/postgresql/tools/text.d.ts.map +0 -1
- package/dist/adapters/postgresql/tools/text.js +0 -1082
- package/dist/adapters/postgresql/tools/text.js.map +0 -1
- package/dist/adapters/postgresql/tools/vector/advanced.d.ts.map +0 -1
- package/dist/adapters/postgresql/tools/vector/advanced.js +0 -958
- package/dist/adapters/postgresql/tools/vector/advanced.js.map +0 -1
- package/dist/adapters/postgresql/tools/vector/basic.d.ts.map +0 -1
- package/dist/adapters/postgresql/tools/vector/basic.js +0 -1165
- package/dist/adapters/postgresql/tools/vector/basic.js.map +0 -1
- package/dist/codemode/api.d.ts.map +0 -1
- package/dist/codemode/api.js +0 -1544
- package/dist/codemode/api.js.map +0 -1
- package/dist/utils/promptGenerator.d.ts +0 -20
- package/dist/utils/promptGenerator.d.ts.map +0 -1
- package/dist/utils/promptGenerator.js +0 -81
- package/dist/utils/promptGenerator.js.map +0 -1
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { readOnly } from "../../../../utils/annotations.js";
|
|
6
6
|
import { getToolIcons } from "../../../../utils/icons.js";
|
|
7
|
+
import { formatPostgresError } from "../core/error-helpers.js";
|
|
7
8
|
import { IndexStatsOutputSchema, TableStatsOutputSchema, StatStatementsOutputSchema, StatActivityOutputSchema, UnusedIndexesOutputSchema, DuplicateIndexesOutputSchema, VacuumStatsOutputSchema, QueryPlanStatsOutputSchema, } from "../../schemas/index.js";
|
|
8
9
|
// Helper to handle undefined params (allows tools to be called without {})
|
|
9
10
|
const defaultToEmpty = (val) => val ?? {};
|
|
@@ -41,7 +42,7 @@ export function createIndexStatsTool(adapter) {
|
|
|
41
42
|
table: z.string().optional().describe("Table name to filter indexes"),
|
|
42
43
|
schema: z.string().optional().describe("Schema name to filter indexes"),
|
|
43
44
|
limit: z
|
|
44
|
-
.
|
|
45
|
+
.any()
|
|
45
46
|
.optional()
|
|
46
47
|
.describe("Max rows to return (default: 50, use 0 for all)"),
|
|
47
48
|
});
|
|
@@ -55,61 +56,76 @@ export function createIndexStatsTool(adapter) {
|
|
|
55
56
|
annotations: readOnly("Index Stats"),
|
|
56
57
|
icons: getToolIcons("performance", readOnly("Index Stats")),
|
|
57
58
|
handler: async (params, _context) => {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
whereClause
|
|
81
|
-
|
|
82
|
-
|
|
59
|
+
try {
|
|
60
|
+
const parsed = IndexStatsSchemaLocal.parse(params);
|
|
61
|
+
let { table, schema } = parsed;
|
|
62
|
+
// Parse schema from table if it contains a dot (e.g., 'myschema.orders')
|
|
63
|
+
if (table?.includes(".")) {
|
|
64
|
+
const parts = table.split(".");
|
|
65
|
+
schema = schema ?? parts[0];
|
|
66
|
+
table = parts[1] ?? table;
|
|
67
|
+
}
|
|
68
|
+
const rawLimit = Number(parsed.limit);
|
|
69
|
+
const limit = parsed.limit === undefined
|
|
70
|
+
? 50
|
|
71
|
+
: isNaN(rawLimit)
|
|
72
|
+
? 50
|
|
73
|
+
: rawLimit === 0
|
|
74
|
+
? null
|
|
75
|
+
: rawLimit;
|
|
76
|
+
// P154: Validate table/schema existence before querying
|
|
77
|
+
const validationError = await validatePerformanceTableExists(adapter, table, schema);
|
|
78
|
+
if (validationError !== null) {
|
|
79
|
+
return { success: false, error: validationError };
|
|
80
|
+
}
|
|
81
|
+
let whereClause = "schemaname NOT IN ('pg_catalog', 'information_schema')";
|
|
82
|
+
const queryParams = [];
|
|
83
|
+
if (schema) {
|
|
84
|
+
queryParams.push(schema);
|
|
85
|
+
whereClause += ` AND schemaname = $${String(queryParams.length)}`;
|
|
86
|
+
}
|
|
87
|
+
if (table) {
|
|
88
|
+
queryParams.push(table);
|
|
89
|
+
whereClause += ` AND relname = $${String(queryParams.length)}`;
|
|
90
|
+
}
|
|
91
|
+
const sql = `SELECT schemaname, relname as table_name, indexrelname as index_name,
|
|
83
92
|
idx_scan as scans, idx_tup_read as tuples_read, idx_tup_fetch as tuples_fetched,
|
|
84
93
|
pg_size_pretty(pg_relation_size(indexrelid)) as size
|
|
85
94
|
FROM pg_stat_user_indexes
|
|
86
95
|
WHERE ${whereClause}
|
|
87
96
|
ORDER BY idx_scan DESC
|
|
88
97
|
${limit !== null ? `LIMIT ${String(limit)}` : ""}`;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
98
|
+
const result = await adapter.executeQuery(sql, queryParams);
|
|
99
|
+
// Coerce numeric fields to JavaScript numbers
|
|
100
|
+
const indexes = (result.rows ?? []).map((row) => ({
|
|
101
|
+
...row,
|
|
102
|
+
scans: toNum(row["scans"]),
|
|
103
|
+
tuples_read: toNum(row["tuples_read"]),
|
|
104
|
+
tuples_fetched: toNum(row["tuples_fetched"]),
|
|
105
|
+
}));
|
|
106
|
+
const response = {
|
|
107
|
+
indexes,
|
|
108
|
+
count: indexes.length,
|
|
109
|
+
};
|
|
110
|
+
// Add totalCount if results were limited
|
|
111
|
+
if (limit !== null && indexes.length === limit) {
|
|
112
|
+
const countSql = `SELECT COUNT(*) as total FROM pg_stat_user_indexes WHERE ${whereClause}`;
|
|
113
|
+
const countResult = await adapter.executeQuery(countSql, queryParams);
|
|
114
|
+
response["totalCount"] = toNum(countResult.rows?.[0]?.["total"]);
|
|
115
|
+
response["truncated"] = true;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
response["truncated"] = false;
|
|
119
|
+
response["totalCount"] = indexes.length;
|
|
120
|
+
}
|
|
121
|
+
return response;
|
|
107
122
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
123
|
+
catch (error) {
|
|
124
|
+
return {
|
|
125
|
+
success: false,
|
|
126
|
+
error: formatPostgresError(error, { tool: "pg_index_stats" }),
|
|
127
|
+
};
|
|
111
128
|
}
|
|
112
|
-
return response;
|
|
113
129
|
},
|
|
114
130
|
};
|
|
115
131
|
}
|
|
@@ -118,7 +134,7 @@ export function createTableStatsTool(adapter) {
|
|
|
118
134
|
table: z.string().optional().describe("Table name (all tables if omitted)"),
|
|
119
135
|
schema: z.string().optional().describe("Schema name"),
|
|
120
136
|
limit: z
|
|
121
|
-
.
|
|
137
|
+
.any()
|
|
122
138
|
.optional()
|
|
123
139
|
.describe("Max rows to return (default: 50, use 0 for all)"),
|
|
124
140
|
});
|
|
@@ -132,31 +148,39 @@ export function createTableStatsTool(adapter) {
|
|
|
132
148
|
annotations: readOnly("Table Stats"),
|
|
133
149
|
icons: getToolIcons("performance", readOnly("Table Stats")),
|
|
134
150
|
handler: async (params, _context) => {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
whereClause
|
|
158
|
-
|
|
159
|
-
|
|
151
|
+
try {
|
|
152
|
+
const parsed = TableStatsSchemaLocal.parse(params);
|
|
153
|
+
let { table, schema } = parsed;
|
|
154
|
+
// Parse schema from table if it contains a dot (e.g., 'myschema.orders')
|
|
155
|
+
if (table?.includes(".")) {
|
|
156
|
+
const parts = table.split(".");
|
|
157
|
+
schema = schema ?? parts[0];
|
|
158
|
+
table = parts[1] ?? table;
|
|
159
|
+
}
|
|
160
|
+
const rawLimit = Number(parsed.limit);
|
|
161
|
+
const limit = parsed.limit === undefined
|
|
162
|
+
? 50
|
|
163
|
+
: isNaN(rawLimit)
|
|
164
|
+
? 50
|
|
165
|
+
: rawLimit === 0
|
|
166
|
+
? null
|
|
167
|
+
: rawLimit;
|
|
168
|
+
// P154: Validate table/schema existence before querying
|
|
169
|
+
const validationError = await validatePerformanceTableExists(adapter, table, schema);
|
|
170
|
+
if (validationError !== null) {
|
|
171
|
+
return { success: false, error: validationError };
|
|
172
|
+
}
|
|
173
|
+
let whereClause = "schemaname NOT IN ('pg_catalog', 'information_schema')";
|
|
174
|
+
const queryParams = [];
|
|
175
|
+
if (schema) {
|
|
176
|
+
queryParams.push(schema);
|
|
177
|
+
whereClause += ` AND schemaname = $${String(queryParams.length)}`;
|
|
178
|
+
}
|
|
179
|
+
if (table) {
|
|
180
|
+
queryParams.push(table);
|
|
181
|
+
whereClause += ` AND relname = $${String(queryParams.length)}`;
|
|
182
|
+
}
|
|
183
|
+
const sql = `SELECT schemaname, relname as table_name,
|
|
160
184
|
seq_scan, seq_tup_read, idx_scan, idx_tup_fetch,
|
|
161
185
|
n_tup_ins as inserts, n_tup_upd as updates, n_tup_del as deletes,
|
|
162
186
|
n_live_tup as live_tuples, n_dead_tup as dead_tuples,
|
|
@@ -165,43 +189,50 @@ export function createTableStatsTool(adapter) {
|
|
|
165
189
|
WHERE ${whereClause}
|
|
166
190
|
ORDER BY seq_scan DESC
|
|
167
191
|
${limit !== null ? `LIMIT ${String(limit)}` : ""}`;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
+
const result = await adapter.executeQuery(sql, queryParams);
|
|
193
|
+
// Coerce numeric fields to JavaScript numbers
|
|
194
|
+
const tables = (result.rows ?? []).map((row) => ({
|
|
195
|
+
...row,
|
|
196
|
+
seq_scan: toNum(row["seq_scan"]),
|
|
197
|
+
seq_tup_read: toNum(row["seq_tup_read"]),
|
|
198
|
+
idx_scan: toNum(row["idx_scan"]),
|
|
199
|
+
idx_tup_fetch: toNum(row["idx_tup_fetch"]),
|
|
200
|
+
inserts: toNum(row["inserts"]),
|
|
201
|
+
updates: toNum(row["updates"]),
|
|
202
|
+
deletes: toNum(row["deletes"]),
|
|
203
|
+
live_tuples: toNum(row["live_tuples"]),
|
|
204
|
+
dead_tuples: toNum(row["dead_tuples"]),
|
|
205
|
+
}));
|
|
206
|
+
// Get total count if limited
|
|
207
|
+
const response = {
|
|
208
|
+
tables,
|
|
209
|
+
count: tables.length,
|
|
210
|
+
};
|
|
211
|
+
if (limit !== null && tables.length === limit) {
|
|
212
|
+
const countSql = `SELECT COUNT(*) as total FROM pg_stat_user_tables WHERE ${whereClause}`;
|
|
213
|
+
const countResult = await adapter.executeQuery(countSql, queryParams);
|
|
214
|
+
response["totalCount"] = toNum(countResult.rows?.[0]?.["total"]);
|
|
215
|
+
response["truncated"] = true;
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
response["truncated"] = false;
|
|
219
|
+
response["totalCount"] = tables.length;
|
|
220
|
+
}
|
|
221
|
+
return response;
|
|
192
222
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
223
|
+
catch (error) {
|
|
224
|
+
return {
|
|
225
|
+
success: false,
|
|
226
|
+
error: formatPostgresError(error, { tool: "pg_table_stats" }),
|
|
227
|
+
};
|
|
196
228
|
}
|
|
197
|
-
return response;
|
|
198
229
|
},
|
|
199
230
|
};
|
|
200
231
|
}
|
|
201
232
|
export function createStatStatementsTool(adapter) {
|
|
202
233
|
const StatStatementsSchemaBase = z.object({
|
|
203
234
|
limit: z
|
|
204
|
-
.
|
|
235
|
+
.any()
|
|
205
236
|
.optional()
|
|
206
237
|
.describe("Max statements to return (default: 20, use 0 for all)"),
|
|
207
238
|
orderBy: z
|
|
@@ -219,36 +250,51 @@ export function createStatStatementsTool(adapter) {
|
|
|
219
250
|
annotations: readOnly("Query Statistics"),
|
|
220
251
|
icons: getToolIcons("performance", readOnly("Query Statistics")),
|
|
221
252
|
handler: async (params, _context) => {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
253
|
+
try {
|
|
254
|
+
const parsed = StatStatementsSchema.parse(params);
|
|
255
|
+
const rawLimit = Number(parsed.limit);
|
|
256
|
+
const limit = parsed.limit === undefined
|
|
257
|
+
? 20
|
|
258
|
+
: isNaN(rawLimit)
|
|
259
|
+
? 20
|
|
260
|
+
: rawLimit === 0
|
|
261
|
+
? null
|
|
262
|
+
: rawLimit;
|
|
263
|
+
const orderBy = parsed.orderBy ?? "total_time";
|
|
264
|
+
const sql = `SELECT query, calls, total_exec_time as total_time,
|
|
226
265
|
mean_exec_time as mean_time, rows,
|
|
227
266
|
shared_blks_hit, shared_blks_read
|
|
228
267
|
FROM pg_stat_statements
|
|
229
268
|
ORDER BY ${orderBy === "total_time" ? "total_exec_time" : orderBy} DESC
|
|
230
269
|
${limit !== null ? `LIMIT ${String(limit)}` : ""}`;
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
270
|
+
const result = await adapter.executeQuery(sql);
|
|
271
|
+
// Coerce numeric fields to JavaScript numbers
|
|
272
|
+
const statements = (result.rows ?? []).map((row) => ({
|
|
273
|
+
...row,
|
|
274
|
+
calls: toNum(row["calls"]),
|
|
275
|
+
rows: toNum(row["rows"]),
|
|
276
|
+
shared_blks_hit: toNum(row["shared_blks_hit"]),
|
|
277
|
+
shared_blks_read: toNum(row["shared_blks_read"]),
|
|
278
|
+
}));
|
|
279
|
+
const response = {
|
|
280
|
+
statements,
|
|
281
|
+
count: statements.length,
|
|
282
|
+
};
|
|
283
|
+
// Add totalCount if results were limited
|
|
284
|
+
if (limit !== null && statements.length === limit) {
|
|
285
|
+
const countSql = `SELECT COUNT(*) as total FROM pg_stat_statements`;
|
|
286
|
+
const countResult = await adapter.executeQuery(countSql);
|
|
287
|
+
response["totalCount"] = toNum(countResult.rows?.[0]?.["total"]);
|
|
288
|
+
response["truncated"] = true;
|
|
289
|
+
}
|
|
290
|
+
return response;
|
|
291
|
+
}
|
|
292
|
+
catch (error) {
|
|
293
|
+
return {
|
|
294
|
+
success: false,
|
|
295
|
+
error: formatPostgresError(error, { tool: "pg_stat_statements" }),
|
|
296
|
+
};
|
|
250
297
|
}
|
|
251
|
-
return response;
|
|
252
298
|
},
|
|
253
299
|
};
|
|
254
300
|
}
|
|
@@ -266,9 +312,10 @@ export function createStatActivityTool(adapter) {
|
|
|
266
312
|
annotations: readOnly("Activity Stats"),
|
|
267
313
|
icons: getToolIcons("performance", readOnly("Activity Stats")),
|
|
268
314
|
handler: async (params, _context) => {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
315
|
+
try {
|
|
316
|
+
const parsed = StatActivitySchema.parse(params);
|
|
317
|
+
const idleClause = parsed.includeIdle === true ? "" : "AND state != 'idle'";
|
|
318
|
+
const sql = `SELECT pid, usename, datname, client_addr, state,
|
|
272
319
|
query_start, state_change,
|
|
273
320
|
now() - query_start as duration,
|
|
274
321
|
query
|
|
@@ -277,16 +324,23 @@ export function createStatActivityTool(adapter) {
|
|
|
277
324
|
AND backend_type = 'client backend'
|
|
278
325
|
${idleClause}
|
|
279
326
|
ORDER BY query_start`;
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
327
|
+
const result = await adapter.executeQuery(sql);
|
|
328
|
+
// Count background workers for metadata
|
|
329
|
+
const bgResult = await adapter.executeQuery(`SELECT COUNT(*)::int as count FROM pg_stat_activity
|
|
283
330
|
WHERE pid != pg_backend_pid() AND backend_type != 'client backend'`);
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
331
|
+
const bgCount = bgResult.rows?.[0]?.["count"] ?? 0;
|
|
332
|
+
return {
|
|
333
|
+
connections: result.rows,
|
|
334
|
+
count: result.rows?.length ?? 0,
|
|
335
|
+
backgroundWorkers: bgCount,
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
return {
|
|
340
|
+
success: false,
|
|
341
|
+
error: formatPostgresError(error, { tool: "pg_stat_activity" }),
|
|
342
|
+
};
|
|
343
|
+
}
|
|
290
344
|
},
|
|
291
345
|
};
|
|
292
346
|
}
|
|
@@ -301,7 +355,7 @@ export function createUnusedIndexesTool(adapter) {
|
|
|
301
355
|
.optional()
|
|
302
356
|
.describe('Minimum index size to include (e.g., "1 MB")'),
|
|
303
357
|
limit: z
|
|
304
|
-
.
|
|
358
|
+
.any()
|
|
305
359
|
.optional()
|
|
306
360
|
.describe("Max indexes to return (default: 20, use 0 for all)"),
|
|
307
361
|
summary: z
|
|
@@ -319,24 +373,32 @@ export function createUnusedIndexesTool(adapter) {
|
|
|
319
373
|
annotations: readOnly("Unused Indexes"),
|
|
320
374
|
icons: getToolIcons("performance", readOnly("Unused Indexes")),
|
|
321
375
|
handler: async (params, _context) => {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
376
|
+
try {
|
|
377
|
+
const parsed = UnusedIndexesSchema.parse(params);
|
|
378
|
+
const rawLimit = Number(parsed.limit);
|
|
379
|
+
const limit = parsed.limit === undefined
|
|
380
|
+
? 20
|
|
381
|
+
: isNaN(rawLimit)
|
|
382
|
+
? 20
|
|
383
|
+
: rawLimit === 0
|
|
384
|
+
? null
|
|
385
|
+
: rawLimit;
|
|
386
|
+
// P154: Validate schema existence before querying
|
|
387
|
+
if (parsed.schema !== undefined) {
|
|
388
|
+
const validationError = await validatePerformanceTableExists(adapter, undefined, parsed.schema);
|
|
389
|
+
if (validationError !== null) {
|
|
390
|
+
return { success: false, error: validationError };
|
|
391
|
+
}
|
|
329
392
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const summarySql = `SELECT schemaname,
|
|
393
|
+
let whereClause = "schemaname NOT IN ('pg_catalog', 'information_schema') AND idx_scan = 0";
|
|
394
|
+
const queryParams = [];
|
|
395
|
+
if (parsed.schema !== undefined) {
|
|
396
|
+
queryParams.push(parsed.schema);
|
|
397
|
+
whereClause += ` AND schemaname = $${String(queryParams.length)}`;
|
|
398
|
+
}
|
|
399
|
+
// Summary mode - return aggregated stats
|
|
400
|
+
if (parsed.summary === true) {
|
|
401
|
+
const summarySql = `SELECT schemaname,
|
|
340
402
|
COUNT(*) as unused_count,
|
|
341
403
|
pg_size_pretty(SUM(pg_relation_size(indexrelid))) as total_size,
|
|
342
404
|
SUM(pg_relation_size(indexrelid)) as total_size_bytes
|
|
@@ -345,24 +407,24 @@ export function createUnusedIndexesTool(adapter) {
|
|
|
345
407
|
${parsed.minSize !== undefined ? `AND pg_relation_size(indexrelid) >= pg_size_bytes('${parsed.minSize}')` : ""}
|
|
346
408
|
GROUP BY schemaname
|
|
347
409
|
ORDER BY SUM(pg_relation_size(indexrelid)) DESC`;
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
410
|
+
const summaryResult = await adapter.executeQuery(summarySql, queryParams);
|
|
411
|
+
const bySchema = (summaryResult.rows ?? []).map((row) => ({
|
|
412
|
+
schema: row["schemaname"],
|
|
413
|
+
unusedCount: toNum(row["unused_count"]),
|
|
414
|
+
totalSize: row["total_size"],
|
|
415
|
+
totalSizeBytes: toNum(row["total_size_bytes"]),
|
|
416
|
+
}));
|
|
417
|
+
const totalCount = bySchema.reduce((sum, s) => sum + (s.unusedCount ?? 0), 0);
|
|
418
|
+
const totalBytes = bySchema.reduce((sum, s) => sum + (s.totalSizeBytes ?? 0), 0);
|
|
419
|
+
return {
|
|
420
|
+
summary: true,
|
|
421
|
+
bySchema,
|
|
422
|
+
totalCount,
|
|
423
|
+
totalSizeBytes: totalBytes,
|
|
424
|
+
hint: "Use summary=false or omit to see individual indexes.",
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
const sql = `SELECT schemaname, relname as table_name, indexrelname as index_name,
|
|
366
428
|
idx_scan as scans, idx_tup_read as tuples_read,
|
|
367
429
|
pg_size_pretty(pg_relation_size(indexrelid)) as size,
|
|
368
430
|
pg_relation_size(indexrelid) as size_bytes
|
|
@@ -371,28 +433,35 @@ export function createUnusedIndexesTool(adapter) {
|
|
|
371
433
|
${parsed.minSize !== undefined ? `AND pg_relation_size(indexrelid) >= pg_size_bytes('${parsed.minSize}')` : ""}
|
|
372
434
|
ORDER BY pg_relation_size(indexrelid) DESC
|
|
373
435
|
${limit !== null ? `LIMIT ${String(limit)}` : ""}`;
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
436
|
+
const result = await adapter.executeQuery(sql, queryParams);
|
|
437
|
+
// Coerce numeric fields to JavaScript numbers
|
|
438
|
+
const unusedIndexes = (result.rows ?? []).map((row) => ({
|
|
439
|
+
...row,
|
|
440
|
+
scans: toNum(row["scans"]),
|
|
441
|
+
tuples_read: toNum(row["tuples_read"]),
|
|
442
|
+
size_bytes: toNum(row["size_bytes"]),
|
|
443
|
+
}));
|
|
444
|
+
const response = {
|
|
445
|
+
unusedIndexes,
|
|
446
|
+
count: unusedIndexes.length,
|
|
447
|
+
hint: "These indexes have never been used. Consider removing them to save disk space and improve write performance.",
|
|
448
|
+
};
|
|
449
|
+
// Add totalCount if results were limited
|
|
450
|
+
if (limit !== null && unusedIndexes.length === limit) {
|
|
451
|
+
const countSql = `SELECT COUNT(*) as total FROM pg_stat_user_indexes WHERE ${whereClause}
|
|
390
452
|
${parsed.minSize !== undefined ? `AND pg_relation_size(indexrelid) >= pg_size_bytes('${parsed.minSize}')` : ""}`;
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
453
|
+
const countResult = await adapter.executeQuery(countSql, queryParams);
|
|
454
|
+
response["totalCount"] = toNum(countResult.rows?.[0]?.["total"]);
|
|
455
|
+
response["truncated"] = true;
|
|
456
|
+
}
|
|
457
|
+
return response;
|
|
458
|
+
}
|
|
459
|
+
catch (error) {
|
|
460
|
+
return {
|
|
461
|
+
success: false,
|
|
462
|
+
error: formatPostgresError(error, { tool: "pg_unused_indexes" }),
|
|
463
|
+
};
|
|
394
464
|
}
|
|
395
|
-
return response;
|
|
396
465
|
},
|
|
397
466
|
};
|
|
398
467
|
}
|
|
@@ -403,7 +472,7 @@ export function createDuplicateIndexesTool(adapter) {
|
|
|
403
472
|
.optional()
|
|
404
473
|
.describe("Schema to filter (default: all user schemas)"),
|
|
405
474
|
limit: z
|
|
406
|
-
.
|
|
475
|
+
.any()
|
|
407
476
|
.optional()
|
|
408
477
|
.describe("Max rows to return (default: 50, use 0 for all)"),
|
|
409
478
|
});
|
|
@@ -417,22 +486,30 @@ export function createDuplicateIndexesTool(adapter) {
|
|
|
417
486
|
annotations: readOnly("Duplicate Indexes"),
|
|
418
487
|
icons: getToolIcons("performance", readOnly("Duplicate Indexes")),
|
|
419
488
|
handler: async (params, _context) => {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
489
|
+
try {
|
|
490
|
+
const parsed = DuplicateIndexesSchema.parse(params);
|
|
491
|
+
const rawLimit = Number(parsed.limit);
|
|
492
|
+
const limit = parsed.limit === undefined
|
|
493
|
+
? 50
|
|
494
|
+
: isNaN(rawLimit)
|
|
495
|
+
? 50
|
|
496
|
+
: rawLimit === 0
|
|
497
|
+
? null
|
|
498
|
+
: rawLimit;
|
|
499
|
+
// P154: Validate schema existence before querying
|
|
500
|
+
if (parsed.schema !== undefined) {
|
|
501
|
+
const validationError = await validatePerformanceTableExists(adapter, undefined, parsed.schema);
|
|
502
|
+
if (validationError !== null) {
|
|
503
|
+
return { success: false, error: validationError };
|
|
504
|
+
}
|
|
427
505
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
const sql = `WITH index_cols AS (
|
|
506
|
+
const queryParams = [];
|
|
507
|
+
const schemaFilter = parsed.schema !== undefined
|
|
508
|
+
? (queryParams.push(parsed.schema),
|
|
509
|
+
`AND n.nspname = $${String(queryParams.length)}`)
|
|
510
|
+
: "AND n.nspname NOT IN ('pg_catalog', 'information_schema')";
|
|
511
|
+
// Find indexes with the same leading column(s) on the same table
|
|
512
|
+
const sql = `WITH index_cols AS (
|
|
436
513
|
SELECT
|
|
437
514
|
n.nspname as schemaname,
|
|
438
515
|
t.relname as tablename,
|
|
@@ -467,16 +544,16 @@ export function createDuplicateIndexesTool(adapter) {
|
|
|
467
544
|
OR b.columns[1:array_length(a.columns, 1)] = a.columns)
|
|
468
545
|
ORDER BY a.schemaname, a.tablename, a.size_bytes DESC
|
|
469
546
|
${limit !== null ? `LIMIT ${String(limit)}` : ""}`;
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
547
|
+
const result = await adapter.executeQuery(sql, queryParams);
|
|
548
|
+
const duplicates = result.rows ?? [];
|
|
549
|
+
const response = {
|
|
550
|
+
duplicateIndexes: duplicates,
|
|
551
|
+
count: duplicates.length,
|
|
552
|
+
hint: "EXACT_DUPLICATE: Remove one. OVERLAPPING/SUBSET: Smaller index may be redundant.",
|
|
553
|
+
};
|
|
554
|
+
// Add totalCount if results were limited
|
|
555
|
+
if (limit !== null && duplicates.length === limit) {
|
|
556
|
+
const countSql = `WITH index_cols AS (
|
|
480
557
|
SELECT
|
|
481
558
|
n.nspname as schemaname,
|
|
482
559
|
t.relname as tablename,
|
|
@@ -500,11 +577,18 @@ export function createDuplicateIndexesTool(adapter) {
|
|
|
500
577
|
AND (a.columns = b.columns
|
|
501
578
|
OR a.columns[1:array_length(b.columns, 1)] = b.columns
|
|
502
579
|
OR b.columns[1:array_length(a.columns, 1)] = a.columns)`;
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
580
|
+
const countResult = await adapter.executeQuery(countSql, queryParams);
|
|
581
|
+
response["totalCount"] = toNum(countResult.rows?.[0]?.["total"]);
|
|
582
|
+
response["truncated"] = true;
|
|
583
|
+
}
|
|
584
|
+
return response;
|
|
585
|
+
}
|
|
586
|
+
catch (error) {
|
|
587
|
+
return {
|
|
588
|
+
success: false,
|
|
589
|
+
error: formatPostgresError(error, { tool: "pg_duplicate_indexes" }),
|
|
590
|
+
};
|
|
506
591
|
}
|
|
507
|
-
return response;
|
|
508
592
|
},
|
|
509
593
|
};
|
|
510
594
|
}
|
|
@@ -513,7 +597,7 @@ export function createVacuumStatsTool(adapter) {
|
|
|
513
597
|
schema: z.string().optional().describe("Schema to filter"),
|
|
514
598
|
table: z.string().optional().describe("Table name to filter"),
|
|
515
599
|
limit: z
|
|
516
|
-
.
|
|
600
|
+
.any()
|
|
517
601
|
.optional()
|
|
518
602
|
.describe("Max rows to return (default: 50, use 0 for all)"),
|
|
519
603
|
});
|
|
@@ -527,32 +611,40 @@ export function createVacuumStatsTool(adapter) {
|
|
|
527
611
|
annotations: readOnly("Vacuum Stats"),
|
|
528
612
|
icons: getToolIcons("performance", readOnly("Vacuum Stats")),
|
|
529
613
|
handler: async (params, _context) => {
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
whereClause
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
614
|
+
try {
|
|
615
|
+
const parsed = VacuumStatsSchema.parse(params);
|
|
616
|
+
let table = parsed.table;
|
|
617
|
+
let schema = parsed.schema;
|
|
618
|
+
// Parse schema from table if it contains a dot (e.g., 'myschema.orders')
|
|
619
|
+
if (table?.includes(".")) {
|
|
620
|
+
const parts = table.split(".");
|
|
621
|
+
schema = schema ?? parts[0];
|
|
622
|
+
table = parts[1] ?? table;
|
|
623
|
+
}
|
|
624
|
+
const rawLimit = Number(parsed.limit);
|
|
625
|
+
const limit = parsed.limit === undefined
|
|
626
|
+
? 50
|
|
627
|
+
: isNaN(rawLimit)
|
|
628
|
+
? 50
|
|
629
|
+
: rawLimit === 0
|
|
630
|
+
? null
|
|
631
|
+
: rawLimit;
|
|
632
|
+
let whereClause = "schemaname NOT IN ('pg_catalog', 'information_schema')";
|
|
633
|
+
const queryParams = [];
|
|
634
|
+
if (schema !== undefined) {
|
|
635
|
+
queryParams.push(schema);
|
|
636
|
+
whereClause += ` AND schemaname = $${String(queryParams.length)}`;
|
|
637
|
+
}
|
|
638
|
+
if (table !== undefined) {
|
|
639
|
+
queryParams.push(table);
|
|
640
|
+
whereClause += ` AND relname = $${String(queryParams.length)}`;
|
|
641
|
+
}
|
|
642
|
+
// P154: Validate table/schema existence before querying
|
|
643
|
+
const validationError = await validatePerformanceTableExists(adapter, table, schema);
|
|
644
|
+
if (validationError !== null) {
|
|
645
|
+
return { success: false, error: validationError };
|
|
646
|
+
}
|
|
647
|
+
const sql = `SELECT
|
|
556
648
|
s.schemaname, s.relname as table_name,
|
|
557
649
|
s.n_live_tup as live_tuples, s.n_dead_tup as dead_tuples,
|
|
558
650
|
CASE WHEN s.n_live_tup > 0 THEN round((100.0 * s.n_dead_tup / s.n_live_tup)::numeric, 2) ELSE 0 END as dead_pct,
|
|
@@ -572,45 +664,52 @@ export function createVacuumStatsTool(adapter) {
|
|
|
572
664
|
WHERE ${whereClause.replace(/schemaname/g, "s.schemaname").replace(/relname/g, "s.relname")}
|
|
573
665
|
ORDER BY s.n_dead_tup DESC
|
|
574
666
|
${limit !== null ? `LIMIT ${String(limit)}` : ""}`;
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
667
|
+
const result = await adapter.executeQuery(sql, queryParams);
|
|
668
|
+
// Coerce numeric fields to JavaScript numbers
|
|
669
|
+
const tables = (result.rows ?? []).map((row) => ({
|
|
670
|
+
...row,
|
|
671
|
+
live_tuples: toNum(row["live_tuples"]),
|
|
672
|
+
dead_tuples: toNum(row["dead_tuples"]),
|
|
673
|
+
dead_pct: toNum(row["dead_pct"]),
|
|
674
|
+
vacuum_count: toNum(row["vacuum_count"]),
|
|
675
|
+
autovacuum_count: toNum(row["autovacuum_count"]),
|
|
676
|
+
analyze_count: toNum(row["analyze_count"]),
|
|
677
|
+
autoanalyze_count: toNum(row["autoanalyze_count"]),
|
|
678
|
+
}));
|
|
679
|
+
const response = {
|
|
680
|
+
tables,
|
|
681
|
+
count: tables.length,
|
|
682
|
+
};
|
|
683
|
+
// Add totalCount if results were limited
|
|
684
|
+
if (limit !== null && tables.length === limit) {
|
|
685
|
+
const countSql = `SELECT COUNT(*) as total FROM pg_stat_user_tables WHERE ${whereClause}`;
|
|
686
|
+
const countResult = await adapter.executeQuery(countSql, queryParams);
|
|
687
|
+
response["totalCount"] = toNum(countResult.rows?.[0]?.["total"]);
|
|
688
|
+
response["truncated"] = true;
|
|
689
|
+
}
|
|
690
|
+
else {
|
|
691
|
+
response["truncated"] = false;
|
|
692
|
+
response["totalCount"] = tables.length;
|
|
693
|
+
}
|
|
694
|
+
return response;
|
|
597
695
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
696
|
+
catch (error) {
|
|
697
|
+
return {
|
|
698
|
+
success: false,
|
|
699
|
+
error: formatPostgresError(error, { tool: "pg_vacuum_stats" }),
|
|
700
|
+
};
|
|
601
701
|
}
|
|
602
|
-
return response;
|
|
603
702
|
},
|
|
604
703
|
};
|
|
605
704
|
}
|
|
606
705
|
export function createQueryPlanStatsTool(adapter) {
|
|
607
706
|
const QueryPlanStatsSchemaBase = z.object({
|
|
608
707
|
limit: z
|
|
609
|
-
.
|
|
708
|
+
.any()
|
|
610
709
|
.optional()
|
|
611
710
|
.describe("Number of queries to return (default: 20, use 0 for all)"),
|
|
612
711
|
truncateQuery: z
|
|
613
|
-
.
|
|
712
|
+
.any()
|
|
614
713
|
.optional()
|
|
615
714
|
.describe("Max query length in chars (default: 100, use 0 for full text)"),
|
|
616
715
|
});
|
|
@@ -624,11 +723,26 @@ export function createQueryPlanStatsTool(adapter) {
|
|
|
624
723
|
annotations: readOnly("Query Plan Stats"),
|
|
625
724
|
icons: getToolIcons("performance", readOnly("Query Plan Stats")),
|
|
626
725
|
handler: async (params, _context) => {
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
726
|
+
try {
|
|
727
|
+
const parsed = QueryPlanStatsSchema.parse(params);
|
|
728
|
+
const rawLimit = Number(parsed.limit);
|
|
729
|
+
const limit = parsed.limit === undefined
|
|
730
|
+
? 20
|
|
731
|
+
: isNaN(rawLimit)
|
|
732
|
+
? 20
|
|
733
|
+
: rawLimit === 0
|
|
734
|
+
? null
|
|
735
|
+
: rawLimit;
|
|
736
|
+
const rawTruncate = Number(parsed.truncateQuery);
|
|
737
|
+
const truncateLen = parsed.truncateQuery === undefined
|
|
738
|
+
? 100
|
|
739
|
+
: isNaN(rawTruncate)
|
|
740
|
+
? 100
|
|
741
|
+
: rawTruncate === 0
|
|
742
|
+
? null
|
|
743
|
+
: rawTruncate;
|
|
744
|
+
// Check if pg_stat_statements is available with planning time columns
|
|
745
|
+
const sql = `SELECT
|
|
632
746
|
query,
|
|
633
747
|
calls,
|
|
634
748
|
total_plan_time,
|
|
@@ -651,42 +765,49 @@ export function createQueryPlanStatsTool(adapter) {
|
|
|
651
765
|
FROM pg_stat_statements
|
|
652
766
|
ORDER BY total_plan_time + total_exec_time DESC
|
|
653
767
|
${limit !== null ? `LIMIT ${String(limit)}` : ""}`;
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
768
|
+
const result = await adapter.executeQuery(sql);
|
|
769
|
+
// Coerce numeric fields to JavaScript numbers and optionally truncate query
|
|
770
|
+
const queryPlanStats = (result.rows ?? []).map((row) => {
|
|
771
|
+
const queryVal = row["query"];
|
|
772
|
+
const query = typeof queryVal === "string" ? queryVal : "";
|
|
773
|
+
const truncatedQuery = truncateLen !== null && query.length > truncateLen
|
|
774
|
+
? query.substring(0, truncateLen) + "..."
|
|
775
|
+
: query;
|
|
776
|
+
return {
|
|
777
|
+
query: truncatedQuery,
|
|
778
|
+
queryTruncated: truncateLen !== null && query.length > truncateLen,
|
|
779
|
+
calls: toNum(row["calls"]),
|
|
780
|
+
total_plan_time: row["total_plan_time"],
|
|
781
|
+
mean_plan_time: row["mean_plan_time"],
|
|
782
|
+
total_exec_time: row["total_exec_time"],
|
|
783
|
+
mean_exec_time: row["mean_exec_time"],
|
|
784
|
+
rows: toNum(row["rows"]),
|
|
785
|
+
plan_pct: toNum(row["plan_pct"]),
|
|
786
|
+
cache_hit_pct: toNum(row["cache_hit_pct"]),
|
|
787
|
+
shared_blks_hit: toNum(row["shared_blks_hit"]),
|
|
788
|
+
shared_blks_read: toNum(row["shared_blks_read"]),
|
|
789
|
+
};
|
|
790
|
+
});
|
|
791
|
+
const response = {
|
|
792
|
+
queryPlanStats,
|
|
793
|
+
count: queryPlanStats.length,
|
|
794
|
+
hint: "High plan_pct indicates queries spending significant time in planning. Consider prepared statements.",
|
|
795
|
+
};
|
|
796
|
+
// Add totalCount if results were limited
|
|
797
|
+
if (limit !== null && queryPlanStats.length === limit) {
|
|
798
|
+
const countSql = `SELECT COUNT(*) as total FROM pg_stat_statements`;
|
|
799
|
+
const countResult = await adapter.executeQuery(countSql);
|
|
800
|
+
response["totalCount"] = toNum(countResult.rows?.[0]?.["total"]);
|
|
801
|
+
response["truncated"] = true;
|
|
802
|
+
}
|
|
803
|
+
return response;
|
|
804
|
+
}
|
|
805
|
+
catch (error) {
|
|
662
806
|
return {
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
calls: toNum(row["calls"]),
|
|
666
|
-
total_plan_time: row["total_plan_time"],
|
|
667
|
-
mean_plan_time: row["mean_plan_time"],
|
|
668
|
-
total_exec_time: row["total_exec_time"],
|
|
669
|
-
mean_exec_time: row["mean_exec_time"],
|
|
670
|
-
rows: toNum(row["rows"]),
|
|
671
|
-
plan_pct: toNum(row["plan_pct"]),
|
|
672
|
-
cache_hit_pct: toNum(row["cache_hit_pct"]),
|
|
673
|
-
shared_blks_hit: toNum(row["shared_blks_hit"]),
|
|
674
|
-
shared_blks_read: toNum(row["shared_blks_read"]),
|
|
807
|
+
success: false,
|
|
808
|
+
error: formatPostgresError(error, { tool: "pg_query_plan_stats" }),
|
|
675
809
|
};
|
|
676
|
-
});
|
|
677
|
-
const response = {
|
|
678
|
-
queryPlanStats,
|
|
679
|
-
count: queryPlanStats.length,
|
|
680
|
-
hint: "High plan_pct indicates queries spending significant time in planning. Consider prepared statements.",
|
|
681
|
-
};
|
|
682
|
-
// Add totalCount if results were limited
|
|
683
|
-
if (limit !== null && queryPlanStats.length === limit) {
|
|
684
|
-
const countSql = `SELECT COUNT(*) as total FROM pg_stat_statements`;
|
|
685
|
-
const countResult = await adapter.executeQuery(countSql);
|
|
686
|
-
response["totalCount"] = toNum(countResult.rows?.[0]?.["total"]);
|
|
687
|
-
response["truncated"] = true;
|
|
688
810
|
}
|
|
689
|
-
return response;
|
|
690
811
|
},
|
|
691
812
|
};
|
|
692
813
|
}
|