From 295ab7a11a49f9b13b51f6ded623227fae433183 Mon Sep 17 00:00:00 2001 From: mertalev <101130780+mertalev@users.noreply.github.com> Date: Thu, 12 Feb 2026 20:30:18 -0500 Subject: [PATCH] sql-tools changes --- .../sql-tools/comparers/parameter.comparer.ts | 1 + .../configuration-parameter.processor.ts | 15 +++++++-- .../src/sql-tools/readers/parameter.reader.ts | 32 +++++++++++++++++++ .../transformers/parameter.transformer.ts | 19 +++++++++-- server/src/sql-tools/types.ts | 8 +++-- 5 files changed, 69 insertions(+), 6 deletions(-) diff --git a/server/src/sql-tools/comparers/parameter.comparer.ts b/server/src/sql-tools/comparers/parameter.comparer.ts index 41d0508d70..8d78580b36 100644 --- a/server/src/sql-tools/comparers/parameter.comparer.ts +++ b/server/src/sql-tools/comparers/parameter.comparer.ts @@ -12,6 +12,7 @@ export const compareParameters = (): Comparer => ({ { type: 'ParameterReset', databaseName: target.databaseName, + tableName: target.tableName, parameterName: target.name, reason: Reason.MissingInSource, }, diff --git a/server/src/sql-tools/processors/configuration-parameter.processor.ts b/server/src/sql-tools/processors/configuration-parameter.processor.ts index dbb5cd4636..ede46e4cdd 100644 --- a/server/src/sql-tools/processors/configuration-parameter.processor.ts +++ b/server/src/sql-tools/processors/configuration-parameter.processor.ts @@ -3,11 +3,22 @@ import { Processor } from 'src/sql-tools/types'; export const processConfigurationParameters: Processor = (ctx, items) => { for (const { - item: { options }, + item: { object, options }, } of items.filter((item) => item.type === 'configurationParameter')) { + let tableName: string | undefined; + if (options.scope === 'table') { + const table = ctx.getTableByObject(object); + if (!table) { + ctx.warn('@ConfigurationParameter', `Unable to find table for table-scoped parameter "${options.name}"`); + continue; + } + tableName = table.name; + } + ctx.parameters.push({ databaseName: ctx.databaseName, - name: options.name, + tableName, + name: tableName ? `${tableName}.${options.name}` : options.name, value: fromColumnValue(options.value), scope: options.scope, synchronize: options.synchronize ?? true, diff --git a/server/src/sql-tools/readers/parameter.reader.ts b/server/src/sql-tools/readers/parameter.reader.ts index c5f36591a3..6a84c7fe6f 100644 --- a/server/src/sql-tools/readers/parameter.reader.ts +++ b/server/src/sql-tools/readers/parameter.reader.ts @@ -17,4 +17,36 @@ export const readParameters: Reader = async (ctx, db) => { synchronize: true, }); } + + // Read table-scoped storage parameters from pg_class.reloptions + const tableParams = await db + .selectFrom('pg_class') + .innerJoin('pg_namespace', 'pg_namespace.oid', 'pg_class.relnamespace') + .where('pg_namespace.nspname', '=', ctx.schemaName) + .where('pg_class.relkind', '=', sql.lit('r')) + .where('pg_class.reloptions', 'is not', null) + .select(['pg_class.relname as table_name', 'pg_class.reloptions']) + .execute(); + + for (const row of tableParams) { + if (!row.reloptions) { + continue; + } + for (const option of row.reloptions) { + const eqIdx = option.indexOf('='); + if (eqIdx === -1) { + continue; + } + const name = option.slice(0, eqIdx); + const value = option.slice(eqIdx + 1); + ctx.parameters.push({ + name: `${row.table_name}.${name}`, + tableName: row.table_name, + value, + databaseName: ctx.databaseName, + scope: 'table', + synchronize: true, + }); + } + } }; diff --git a/server/src/sql-tools/transformers/parameter.transformer.ts b/server/src/sql-tools/transformers/parameter.transformer.ts index d23472f991..425a6a8757 100644 --- a/server/src/sql-tools/transformers/parameter.transformer.ts +++ b/server/src/sql-tools/transformers/parameter.transformer.ts @@ -8,7 +8,7 @@ export const transformParameters: SqlTransformer = (ctx, item) => { } case 'ParameterReset': { - return asParameterReset(item.databaseName, item.parameterName); + return asParameterReset(item.databaseName, item.parameterName, item.tableName); } default: { @@ -17,7 +17,19 @@ export const transformParameters: SqlTransformer = (ctx, item) => { } }; +const getParameterName = (parameter: DatabaseParameter): string => { + if (parameter.scope === 'table' && parameter.tableName && parameter.name.startsWith(`${parameter.tableName}.`)) { + return parameter.name.slice(parameter.tableName.length + 1); + } + return parameter.name; +}; + const asParameterSet = (parameter: DatabaseParameter): string => { + if (parameter.scope === 'table' && parameter.tableName) { + const paramName = getParameterName(parameter); + return `ALTER TABLE "${parameter.tableName}" SET (${paramName} = ${parameter.value})`; + } + let sql = ''; if (parameter.scope === 'database') { sql += `ALTER DATABASE "${parameter.databaseName}" `; @@ -28,6 +40,9 @@ const asParameterSet = (parameter: DatabaseParameter): string => { return sql; }; -const asParameterReset = (databaseName: string, parameterName: string): string => { +const asParameterReset = (databaseName: string, parameterName: string, tableName?: string): string => { + if (tableName) { + return `ALTER TABLE "${tableName}" RESET (${parameterName})`; + } return `ALTER DATABASE "${databaseName}" RESET "${parameterName}"`; }; diff --git a/server/src/sql-tools/types.ts b/server/src/sql-tools/types.ts index 9d93a79ff1..a02f17846d 100644 --- a/server/src/sql-tools/types.ts +++ b/server/src/sql-tools/types.ts @@ -86,6 +86,7 @@ export type PostgresDB = { relhasindex: PostgresYesOrNo; relisshared: PostgresYesOrNo; relpersistence: string; + reloptions: string[] | null; }; pg_constraint: { @@ -306,6 +307,7 @@ export enum ActionType { export type ColumnStorage = 'default' | 'external' | 'extended' | 'main'; export type ColumnType = + | '"char"' | 'bigint' | 'boolean' | 'bytea' @@ -316,6 +318,7 @@ export type ColumnType = | 'integer' | 'jsonb' | 'polygon' + | 'smallint' | 'text' | 'time' | 'time with time zone' @@ -344,12 +347,13 @@ export type DatabaseSchema = { export type DatabaseParameter = { name: string; databaseName: string; + tableName?: string; value: string | number | null | undefined; scope: ParameterScope; synchronize: boolean; }; -export type ParameterScope = 'database' | 'user'; +export type ParameterScope = 'database' | 'table' | 'user'; export type DatabaseOverride = { name: string; @@ -506,7 +510,7 @@ export type SchemaDiff = { reason: string } & ( | { type: 'TriggerCreate'; trigger: DatabaseTrigger } | { type: 'TriggerDrop'; tableName: string; triggerName: string } | { type: 'ParameterSet'; parameter: DatabaseParameter } - | { type: 'ParameterReset'; databaseName: string; parameterName: string } + | { type: 'ParameterReset'; databaseName: string; tableName?: string; parameterName: string } | { type: 'EnumCreate'; enum: DatabaseEnum } | { type: 'EnumDrop'; enumName: string } | { type: 'OverrideCreate'; override: DatabaseOverride }