Merge pull request #1407 from dbgate/feature/postgres-optimalization
Feature/postgres optimalization
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"private": true,
|
||||
"version": "7.1.6",
|
||||
"version": "7.1.7-premium-beta.1",
|
||||
"name": "dbgate-all",
|
||||
"workspaces": [
|
||||
"packages/*",
|
||||
|
||||
@@ -72,6 +72,8 @@ class Analyser extends DatabaseAnalyser {
|
||||
...replacements,
|
||||
$typeAggFunc: this.driver.dialect.stringAgg ? 'string_agg' : 'max',
|
||||
$typeAggParam: this.driver.dialect.stringAgg ? ", '|'" : '',
|
||||
$hashColumnAggTail: this.driver.dialect.stringAgg ? ", ',' ORDER BY a.attnum" : '',
|
||||
$hashConstraintAggTail: this.driver.dialect.stringAgg ? ", ',' ORDER BY con.conname" : '',
|
||||
$md5Function: this.dialect?.isFipsComplianceOn ? 'LENGTH' : 'MD5',
|
||||
});
|
||||
return query;
|
||||
@@ -83,131 +85,92 @@ class Analyser extends DatabaseAnalyser {
|
||||
}
|
||||
|
||||
async _runAnalysis() {
|
||||
this.feedback({ analysingMessage: 'DBGM-00241 Loading tables' });
|
||||
const tables = await this.analyserQuery('tableList', ['tables']);
|
||||
const useInfoSchema = this.driver.__analyserInternals.useInfoSchemaRoutines;
|
||||
const routinesQueryName = useInfoSchema ? 'routinesInfoSchema' : 'routines';
|
||||
const proceduresParametersQueryName = useInfoSchema ? 'proceduresParametersInfoSchema' : 'proceduresParameters';
|
||||
|
||||
this.feedback({ analysingMessage: 'DBGM-00242 Loading columns' });
|
||||
const columns = await this.analyserQuery('columns', ['tables', 'views']);
|
||||
|
||||
this.feedback({ analysingMessage: 'DBGM-00243 Loading primary keys' });
|
||||
const pkColumns = await this.analyserQuery('primaryKeys', ['tables']);
|
||||
|
||||
let fkColumns = null;
|
||||
|
||||
this.feedback({ analysingMessage: 'DBGM-00244 Loading foreign key constraints' });
|
||||
// const fk_tableConstraints = await this.analyserQuery('fk_tableConstraints', ['tables']);
|
||||
|
||||
this.feedback({ analysingMessage: 'DBGM-00245 Loading foreign key refs' });
|
||||
const foreignKeys = await this.analyserQuery('foreignKeys', ['tables']);
|
||||
|
||||
this.feedback({ analysingMessage: 'DBGM-00246 Loading foreign key columns' });
|
||||
const fk_keyColumnUsage = await this.analyserQuery('fk_keyColumnUsage', ['tables']);
|
||||
|
||||
// const cntKey = x => `${x.constraint_name}|${x.constraint_schema}`;
|
||||
const fkRows = [];
|
||||
// const fkConstraintDct = _.keyBy(fk_tableConstraints.rows, cntKey);
|
||||
for (const fkRef of foreignKeys.rows) {
|
||||
// const cntBase = fkConstraintDct[cntKey(fkRef)];
|
||||
// const cntRef = fkConstraintDct[`${fkRef.unique_constraint_name}|${fkRef.unique_constraint_schema}`];
|
||||
// if (!cntBase || !cntRef) continue;
|
||||
const baseCols = _.sortBy(
|
||||
fk_keyColumnUsage.rows.filter(
|
||||
x =>
|
||||
x.table_name == fkRef.table_name &&
|
||||
x.constraint_name == fkRef.constraint_name &&
|
||||
x.table_schema == fkRef.table_schema
|
||||
),
|
||||
'ordinal_position'
|
||||
);
|
||||
const refCols = _.sortBy(
|
||||
fk_keyColumnUsage.rows.filter(
|
||||
x =>
|
||||
x.table_name == fkRef.ref_table_name &&
|
||||
x.constraint_name == fkRef.unique_constraint_name &&
|
||||
x.table_schema == fkRef.ref_table_schema
|
||||
),
|
||||
'ordinal_position'
|
||||
);
|
||||
if (baseCols.length != refCols.length) continue;
|
||||
|
||||
for (let i = 0; i < baseCols.length; i++) {
|
||||
const baseCol = baseCols[i];
|
||||
const refCol = refCols[i];
|
||||
|
||||
fkRows.push({
|
||||
...fkRef,
|
||||
pure_name: fkRef.table_name,
|
||||
schema_name: fkRef.table_schema,
|
||||
ref_table_name: fkRef.ref_table_name,
|
||||
ref_schema_name: fkRef.ref_table_schema,
|
||||
column_name: baseCol.column_name,
|
||||
ref_column_name: refCol.column_name,
|
||||
update_action: fkRef.update_action,
|
||||
delete_action: fkRef.delete_action,
|
||||
});
|
||||
}
|
||||
}
|
||||
fkColumns = { rows: fkRows };
|
||||
|
||||
this.feedback({ analysingMessage: 'DBGM-00247 Loading views' });
|
||||
const views = await this.analyserQuery('views', ['views']);
|
||||
|
||||
this.feedback({ analysingMessage: 'DBGM-00248 Loading materialized views' });
|
||||
const matviews = this.driver.dialect.materializedViews ? await this.analyserQuery('matviews', ['matviews']) : null;
|
||||
|
||||
this.feedback({ analysingMessage: 'DBGM-00249 Loading materialized view columns' });
|
||||
const matviewColumns = this.driver.dialect.materializedViews
|
||||
? await this.analyserQuery('matviewColumns', ['matviews'])
|
||||
: null;
|
||||
|
||||
this.feedback({ analysingMessage: 'DBGM-00250 Loading routines' });
|
||||
const routines = await this.analyserQuery('routines', ['procedures', 'functions']);
|
||||
|
||||
this.feedback({ analysingMessage: 'DBGM-00251 Loading routine parameters' });
|
||||
const routineParametersRows = await this.analyserQuery('proceduresParameters');
|
||||
|
||||
this.feedback({ analysingMessage: 'DBGM-00252 Loading indexes' });
|
||||
const indexes = this.driver.__analyserInternals.skipIndexes
|
||||
? { rows: [] }
|
||||
: await this.analyserQuery('indexes', ['tables']);
|
||||
|
||||
this.feedback({ analysingMessage: 'DBGM-00253 Loading index columns' });
|
||||
const indexcols = this.driver.__analyserInternals.skipIndexes
|
||||
? { rows: [] }
|
||||
: await this.analyserQuery('indexcols', ['tables']);
|
||||
|
||||
this.feedback({ analysingMessage: 'DBGM-00254 Loading unique names' });
|
||||
const uniqueNames = await this.analyserQuery('uniqueNames', ['tables']);
|
||||
// Run all independent queries in parallel
|
||||
this.feedback({ analysingMessage: 'DBGM-00241 Loading database structure' });
|
||||
const [
|
||||
tables,
|
||||
views,
|
||||
columns,
|
||||
pkColumns,
|
||||
foreignKeys,
|
||||
uniqueNames,
|
||||
routines,
|
||||
routineParametersRows,
|
||||
indexes,
|
||||
indexcols,
|
||||
matviews,
|
||||
matviewColumns,
|
||||
triggers,
|
||||
] = await Promise.all([
|
||||
this.analyserQuery('tableList', ['tables']),
|
||||
this.analyserQuery('views', ['views']),
|
||||
this.analyserQuery('columns', ['tables', 'views']),
|
||||
this.analyserQuery('primaryKeys', ['tables']),
|
||||
this.analyserQuery('foreignKeys', ['tables']),
|
||||
this.analyserQuery('uniqueNames', ['tables']),
|
||||
this.analyserQuery(routinesQueryName, ['procedures', 'functions']),
|
||||
this.analyserQuery(proceduresParametersQueryName),
|
||||
this.driver.__analyserInternals.skipIndexes
|
||||
? Promise.resolve({ rows: [] })
|
||||
: this.analyserQuery('indexes', ['tables']),
|
||||
this.driver.__analyserInternals.skipIndexes
|
||||
? Promise.resolve({ rows: [] })
|
||||
: this.analyserQuery('indexcols', ['tables']),
|
||||
this.driver.dialect.materializedViews
|
||||
? this.analyserQuery('matviews', ['matviews'])
|
||||
: Promise.resolve(null),
|
||||
this.driver.dialect.materializedViews
|
||||
? this.analyserQuery('matviewColumns', ['matviews'])
|
||||
: Promise.resolve(null),
|
||||
this.analyserQuery('triggers'),
|
||||
]);
|
||||
|
||||
// Load geometry/geography columns if the views exist (these are rare, so run after views are loaded)
|
||||
let geometryColumns = { rows: [] };
|
||||
if (views.rows.find(x => x.pure_name == 'geometry_columns' && x.schema_name == 'public')) {
|
||||
this.feedback({ analysingMessage: 'DBGM-00255 Loading geometry columns' });
|
||||
geometryColumns = await this.analyserQuery('geometryColumns', ['tables']);
|
||||
}
|
||||
|
||||
let geographyColumns = { rows: [] };
|
||||
if (views.rows.find(x => x.pure_name == 'geography_columns' && x.schema_name == 'public')) {
|
||||
this.feedback({ analysingMessage: 'DBGM-00256 Loading geography columns' });
|
||||
geographyColumns = await this.analyserQuery('geographyColumns', ['tables']);
|
||||
const hasGeometry = views.rows.find(x => x.pure_name == 'geometry_columns' && x.schema_name == 'public');
|
||||
const hasGeography = views.rows.find(x => x.pure_name == 'geography_columns' && x.schema_name == 'public');
|
||||
if (hasGeometry || hasGeography) {
|
||||
const [geomCols, geogCols] = await Promise.all([
|
||||
hasGeometry
|
||||
? this.analyserQuery('geometryColumns', ['tables'])
|
||||
: Promise.resolve({ rows: [] }),
|
||||
hasGeography
|
||||
? this.analyserQuery('geographyColumns', ['tables'])
|
||||
: Promise.resolve({ rows: [] }),
|
||||
]);
|
||||
geometryColumns = geomCols;
|
||||
geographyColumns = geogCols;
|
||||
}
|
||||
|
||||
this.feedback({ analysingMessage: 'DBGM-00257 Loading triggers' });
|
||||
const triggers = await this.analyserQuery('triggers');
|
||||
|
||||
this.feedback({ analysingMessage: 'DBGM-00258 Finalizing DB structure' });
|
||||
|
||||
const columnColumnsMapped = fkColumns.rows.map(x => ({
|
||||
pureName: x.pure_name,
|
||||
schemaName: x.schema_name,
|
||||
constraintSchema: x.constraint_schema,
|
||||
// Pre-build lookup maps for O(1) access instead of O(n) scanning per table/view
|
||||
const columnsByTable = _.groupBy(columns.rows, x => `${x.schema_name}.${x.pure_name}`);
|
||||
const indexcolsByOidAttnum = _.keyBy(indexcols.rows, x => `${x.oid}_${x.attnum}`);
|
||||
const uniqueNameSet = new Set(uniqueNames.rows.map(x => x.constraint_name));
|
||||
const indexesByTable = _.groupBy(indexes.rows, x => `${x.schema_name}.${x.table_name}`);
|
||||
const matviewColumnsByTable = matviewColumns
|
||||
? _.groupBy(matviewColumns.rows, x => `${x.schema_name}.${x.pure_name}`)
|
||||
: {};
|
||||
|
||||
const columnColumnsMapped = foreignKeys.rows.map(x => ({
|
||||
pureName: x.table_name,
|
||||
schemaName: x.table_schema,
|
||||
constraintName: x.constraint_name,
|
||||
columnName: x.column_name,
|
||||
refColumnName: x.ref_column_name,
|
||||
updateAction: x.update_action,
|
||||
deleteAction: x.delete_action,
|
||||
refTableName: x.ref_table_name,
|
||||
refSchemaName: x.ref_schema_name,
|
||||
refSchemaName: x.ref_table_schema,
|
||||
}));
|
||||
const fkByTable = _.groupBy(columnColumnsMapped, x => `${x.schemaName}.${x.pureName}`);
|
||||
|
||||
const pkColumnsMapped = pkColumns.rows.map(x => ({
|
||||
pureName: x.pure_name,
|
||||
schemaName: x.schema_name,
|
||||
@@ -215,6 +178,7 @@ class Analyser extends DatabaseAnalyser {
|
||||
constraintName: x.constraint_name,
|
||||
columnName: x.column_name,
|
||||
}));
|
||||
const pkByTable = _.groupBy(pkColumnsMapped, x => `${x.schemaName}.${x.pureName}`);
|
||||
|
||||
const procedureParameters = routineParametersRows.rows
|
||||
.filter(i => i.routine_type == 'PROCEDURE')
|
||||
@@ -252,6 +216,7 @@ class Analyser extends DatabaseAnalyser {
|
||||
|
||||
const res = {
|
||||
tables: tables.rows.map(table => {
|
||||
const tableKey = `${table.schema_name}.${table.pure_name}`;
|
||||
const newTable = {
|
||||
pureName: table.pure_name,
|
||||
schemaName: table.schema_name,
|
||||
@@ -259,20 +224,16 @@ class Analyser extends DatabaseAnalyser {
|
||||
objectId: `tables:${table.schema_name}.${table.pure_name}`,
|
||||
contentHash: table.hash_code_columns ? `${table.hash_code_columns}-${table.hash_code_constraints}` : null,
|
||||
};
|
||||
const tableIndexes = indexesByTable[tableKey] || [];
|
||||
return {
|
||||
...newTable,
|
||||
columns: columns.rows
|
||||
.filter(col => col.pure_name == table.pure_name && col.schema_name == table.schema_name)
|
||||
.map(col => getColumnInfo(col, newTable, geometryColumns, geographyColumns)),
|
||||
primaryKey: DatabaseAnalyser.extractPrimaryKeys(newTable, pkColumnsMapped),
|
||||
foreignKeys: DatabaseAnalyser.extractForeignKeys(newTable, columnColumnsMapped),
|
||||
indexes: indexes.rows
|
||||
.filter(
|
||||
x =>
|
||||
x.table_name == table.pure_name &&
|
||||
x.schema_name == table.schema_name &&
|
||||
!uniqueNames.rows.find(y => y.constraint_name == x.index_name)
|
||||
)
|
||||
columns: (columnsByTable[tableKey] || []).map(col =>
|
||||
getColumnInfo(col, newTable, geometryColumns, geographyColumns)
|
||||
),
|
||||
primaryKey: DatabaseAnalyser.extractPrimaryKeys(newTable, pkByTable[tableKey] || []),
|
||||
foreignKeys: DatabaseAnalyser.extractForeignKeys(newTable, fkByTable[tableKey] || []),
|
||||
indexes: tableIndexes
|
||||
.filter(x => !uniqueNameSet.has(x.index_name))
|
||||
.map(idx => {
|
||||
const indOptionSplit = idx.indoption.split(' ');
|
||||
return {
|
||||
@@ -281,7 +242,7 @@ class Analyser extends DatabaseAnalyser {
|
||||
columns: _.compact(
|
||||
idx.indkey
|
||||
.split(' ')
|
||||
.map(colid => indexcols.rows.find(col => col.oid == idx.oid && col.attnum == colid))
|
||||
.map(colid => indexcolsByOidAttnum[`${idx.oid}_${colid}`])
|
||||
.filter(col => col != null)
|
||||
.map((col, colIndex) => ({
|
||||
columnName: col.column_name,
|
||||
@@ -290,19 +251,14 @@ class Analyser extends DatabaseAnalyser {
|
||||
),
|
||||
};
|
||||
}),
|
||||
uniques: indexes.rows
|
||||
.filter(
|
||||
x =>
|
||||
x.table_name == table.pure_name &&
|
||||
x.schema_name == table.schema_name &&
|
||||
uniqueNames.rows.find(y => y.constraint_name == x.index_name)
|
||||
)
|
||||
uniques: tableIndexes
|
||||
.filter(x => uniqueNameSet.has(x.index_name))
|
||||
.map(idx => ({
|
||||
constraintName: idx.index_name,
|
||||
columns: _.compact(
|
||||
idx.indkey
|
||||
.split(' ')
|
||||
.map(colid => indexcols.rows.find(col => col.oid == idx.oid && col.attnum == colid))
|
||||
.map(colid => indexcolsByOidAttnum[`${idx.oid}_${colid}`])
|
||||
.filter(col => col != null)
|
||||
.map(col => ({
|
||||
columnName: col.column_name,
|
||||
@@ -317,9 +273,7 @@ class Analyser extends DatabaseAnalyser {
|
||||
schemaName: view.schema_name,
|
||||
contentHash: view.hash_code,
|
||||
createSql: `CREATE VIEW "${view.schema_name}"."${view.pure_name}"\nAS\n${view.create_sql}`,
|
||||
columns: columns.rows
|
||||
.filter(col => col.pure_name == view.pure_name && col.schema_name == view.schema_name)
|
||||
.map(col => getColumnInfo(col)),
|
||||
columns: (columnsByTable[`${view.schema_name}.${view.pure_name}`] || []).map(col => getColumnInfo(col)),
|
||||
})),
|
||||
matviews: matviews
|
||||
? matviews.rows.map(matview => ({
|
||||
@@ -328,8 +282,7 @@ class Analyser extends DatabaseAnalyser {
|
||||
schemaName: matview.schema_name,
|
||||
contentHash: matview.hash_code,
|
||||
createSql: `CREATE MATERIALIZED VIEW "${matview.schema_name}"."${matview.pure_name}"\nAS\n${matview.definition}`,
|
||||
columns: matviewColumns.rows
|
||||
.filter(col => col.pure_name == matview.pure_name && col.schema_name == matview.schema_name)
|
||||
columns: (matviewColumnsByTable[`${matview.schema_name}.${matview.pure_name}`] || [])
|
||||
.map(col => getColumnInfo(col)),
|
||||
}))
|
||||
: undefined,
|
||||
@@ -396,14 +349,31 @@ class Analyser extends DatabaseAnalyser {
|
||||
}
|
||||
|
||||
async _getFastSnapshot() {
|
||||
const viewModificationsQueryData = await this.analyserQuery('viewModifications');
|
||||
const matviewModificationsQueryData = this.driver.dialect.materializedViews
|
||||
? await this.analyserQuery('matviewModifications')
|
||||
: null;
|
||||
const routineModificationsQueryData = await this.analyserQuery('routineModifications');
|
||||
const useInfoSchema = this.driver.__analyserInternals.useInfoSchemaRoutines;
|
||||
const routineModificationsQueryName = useInfoSchema ? 'routineModificationsInfoSchema' : 'routineModifications';
|
||||
|
||||
// Run all modification queries in parallel
|
||||
const [
|
||||
tableModificationsQueryData,
|
||||
viewModificationsQueryData,
|
||||
matviewModificationsQueryData,
|
||||
routineModificationsQueryData,
|
||||
] = await Promise.all([
|
||||
this.analyserQuery('tableModifications'),
|
||||
this.analyserQuery('viewModifications'),
|
||||
this.driver.dialect.materializedViews
|
||||
? this.analyserQuery('matviewModifications')
|
||||
: Promise.resolve(null),
|
||||
this.analyserQuery(routineModificationsQueryName),
|
||||
]);
|
||||
|
||||
return {
|
||||
tables: null,
|
||||
tables: tableModificationsQueryData.rows.map(x => ({
|
||||
objectId: `tables:${x.schema_name}.${x.pure_name}`,
|
||||
pureName: x.pure_name,
|
||||
schemaName: x.schema_name,
|
||||
contentHash: `${x.hash_code_columns}-${x.hash_code_constraints}`,
|
||||
})),
|
||||
views: viewModificationsQueryData.rows.map(x => ({
|
||||
objectId: `views:${x.schema_name}.${x.pure_name}`,
|
||||
pureName: x.pure_name,
|
||||
|
||||
@@ -1,22 +1,38 @@
|
||||
module.exports = `
|
||||
select
|
||||
table_schema as "schema_name",
|
||||
table_name as "pure_name",
|
||||
column_name as "column_name",
|
||||
is_nullable as "is_nullable",
|
||||
data_type as "data_type",
|
||||
character_maximum_length as "char_max_length",
|
||||
numeric_precision as "numeric_precision",
|
||||
numeric_scale as "numeric_scale",
|
||||
column_default as "default_value"
|
||||
from information_schema.columns
|
||||
where
|
||||
table_schema !~ '^_timescaledb_'
|
||||
and (
|
||||
('tables:' || table_schema || '.' || table_name) =OBJECT_ID_CONDITION
|
||||
or
|
||||
('views:' || table_schema || '.' || table_name) =OBJECT_ID_CONDITION
|
||||
)
|
||||
and table_schema =SCHEMA_NAME_CONDITION
|
||||
order by ordinal_position
|
||||
SELECT
|
||||
n.nspname AS "schema_name",
|
||||
c.relname AS "pure_name",
|
||||
a.attname AS "column_name",
|
||||
CASE WHEN a.attnotnull THEN 'NO' ELSE 'YES' END AS "is_nullable",
|
||||
format_type(a.atttypid, NULL) AS "data_type",
|
||||
CASE
|
||||
WHEN a.atttypmod > 0 AND t.typname IN ('varchar', 'bpchar', 'char') THEN a.atttypmod - 4
|
||||
WHEN a.atttypmod > 0 AND t.typname IN ('bit', 'varbit') THEN a.atttypmod
|
||||
ELSE NULL
|
||||
END AS "char_max_length",
|
||||
CASE
|
||||
WHEN a.atttypmod > 0 AND t.typname = 'numeric' THEN ((a.atttypmod - 4) >> 16) & 65535
|
||||
ELSE NULL
|
||||
END AS "numeric_precision",
|
||||
CASE
|
||||
WHEN a.atttypmod > 0 AND t.typname = 'numeric' THEN (a.atttypmod - 4) & 65535
|
||||
ELSE NULL
|
||||
END AS "numeric_scale",
|
||||
pg_get_expr(d.adbin, d.adrelid) AS "default_value"
|
||||
FROM pg_catalog.pg_attribute a
|
||||
JOIN pg_catalog.pg_class c ON c.oid = a.attrelid
|
||||
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
||||
JOIN pg_catalog.pg_type t ON t.oid = a.atttypid
|
||||
LEFT JOIN pg_catalog.pg_attrdef d ON d.adrelid = a.attrelid AND d.adnum = a.attnum
|
||||
WHERE a.attnum > 0
|
||||
AND NOT a.attisdropped
|
||||
AND c.relkind IN ('r', 'v', 'p', 'f')
|
||||
AND n.nspname !~ '^_timescaledb_'
|
||||
AND (
|
||||
('tables:' || n.nspname || '.' || c.relname) =OBJECT_ID_CONDITION
|
||||
OR
|
||||
('views:' || n.nspname || '.' || c.relname) =OBJECT_ID_CONDITION
|
||||
)
|
||||
AND n.nspname =SCHEMA_NAME_CONDITION
|
||||
ORDER BY a.attnum
|
||||
`;
|
||||
@@ -5,7 +5,8 @@ SELECT
|
||||
con.conname AS constraint_name,
|
||||
nsp2.nspname AS ref_table_schema,
|
||||
rel2.relname AS ref_table_name,
|
||||
conpk.conname AS unique_constraint_name,
|
||||
att.attname AS column_name,
|
||||
att2.attname AS ref_column_name,
|
||||
CASE con.confupdtype
|
||||
WHEN 'a' THEN 'NO ACTION'
|
||||
WHEN 'r' THEN 'RESTRICT'
|
||||
@@ -13,26 +14,26 @@ SELECT
|
||||
WHEN 'n' THEN 'SET NULL'
|
||||
WHEN 'd' THEN 'SET DEFAULT'
|
||||
ELSE con.confupdtype::text
|
||||
END AS update_action,
|
||||
|
||||
CASE con.confdeltype
|
||||
END AS update_action,
|
||||
CASE con.confdeltype
|
||||
WHEN 'a' THEN 'NO ACTION'
|
||||
WHEN 'r' THEN 'RESTRICT'
|
||||
WHEN 'c' THEN 'CASCADE'
|
||||
WHEN 'n' THEN 'SET NULL'
|
||||
WHEN 'd' THEN 'SET DEFAULT'
|
||||
ELSE con.confdeltype::text
|
||||
END AS delete_action
|
||||
|
||||
END AS delete_action
|
||||
FROM pg_constraint con
|
||||
JOIN pg_class rel ON rel.oid = con.conrelid
|
||||
JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace
|
||||
JOIN pg_class rel2 ON rel2.oid = con.confrelid
|
||||
JOIN pg_namespace nsp2 ON nsp2.oid = rel2.relnamespace
|
||||
JOIN pg_constraint conpk
|
||||
ON conpk.conrelid = con.confrelid
|
||||
AND conpk.conkey = con.confkey
|
||||
AND conpk.contype IN ('p','u') -- 'p' = primary key, 'u' = unique constraint
|
||||
WHERE con.contype = 'f' AND ('tables:' || nsp.nspname || '.' || rel.relname) =OBJECT_ID_CONDITION AND nsp.nspname =SCHEMA_NAME_CONDITION
|
||||
JOIN LATERAL unnest(con.conkey, con.confkey) WITH ORDINALITY AS cols(attnum, ref_attnum, ordinal_position) ON TRUE
|
||||
JOIN pg_attribute att ON att.attrelid = con.conrelid AND att.attnum = cols.attnum
|
||||
JOIN pg_attribute att2 ON att2.attrelid = con.confrelid AND att2.attnum = cols.ref_attnum
|
||||
WHERE con.contype = 'f'
|
||||
AND ('tables:' || nsp.nspname || '.' || rel.relname) =OBJECT_ID_CONDITION
|
||||
AND nsp.nspname =SCHEMA_NAME_CONDITION
|
||||
ORDER BY con.conname, cols.ordinal_position
|
||||
;
|
||||
`;
|
||||
|
||||
@@ -19,15 +19,16 @@ const triggers = require('./triggers');
|
||||
const listDatabases = require('./listDatabases');
|
||||
const listVariables = require('./listVariables');
|
||||
const listProcesses = require('./listProcesses');
|
||||
|
||||
const fk_keyColumnUsage = require('./fk_key_column_usage');
|
||||
const routinesInfoSchema = require('./routinesInfoSchema');
|
||||
const proceduresParametersInfoSchema = require('./proceduresParametersInfoSchema');
|
||||
const routineModificationsInfoSchema = require('./routineModificationsInfoSchema');
|
||||
const tableModifications = require('./tableModifications');
|
||||
|
||||
module.exports = {
|
||||
columns,
|
||||
tableList,
|
||||
viewModifications,
|
||||
primaryKeys,
|
||||
fk_keyColumnUsage,
|
||||
foreignKeys,
|
||||
views,
|
||||
routines,
|
||||
@@ -45,4 +46,8 @@ module.exports = {
|
||||
listDatabases,
|
||||
listVariables,
|
||||
listProcesses,
|
||||
routinesInfoSchema,
|
||||
proceduresParametersInfoSchema,
|
||||
routineModificationsInfoSchema,
|
||||
tableModifications,
|
||||
};
|
||||
|
||||
@@ -1,31 +1,34 @@
|
||||
module.exports = `
|
||||
SELECT
|
||||
proc.specific_schema AS schema_name,
|
||||
proc.routine_name AS pure_name,
|
||||
proc.routine_type as routine_type,
|
||||
args.parameter_name AS parameter_name,
|
||||
args.parameter_mode,
|
||||
args.data_type AS data_type,
|
||||
args.ordinal_position AS parameter_index,
|
||||
args.parameter_mode AS parameter_mode
|
||||
FROM
|
||||
information_schema.routines proc
|
||||
LEFT JOIN
|
||||
information_schema.parameters args
|
||||
ON proc.specific_schema = args.specific_schema
|
||||
AND proc.specific_name = args.specific_name
|
||||
WHERE
|
||||
proc.specific_schema NOT IN ('pg_catalog', 'information_schema') -- Exclude system schemas
|
||||
AND args.parameter_name IS NOT NULL
|
||||
AND proc.routine_type IN ('PROCEDURE', 'FUNCTION') -- Filter for procedures
|
||||
AND proc.specific_schema !~ '^_timescaledb_'
|
||||
AND proc.specific_schema =SCHEMA_NAME_CONDITION
|
||||
SELECT
|
||||
n.nspname AS "schema_name",
|
||||
p.proname AS "pure_name",
|
||||
CASE p.prokind WHEN 'p' THEN 'PROCEDURE' ELSE 'FUNCTION' END AS "routine_type",
|
||||
a.parameter_name AS "parameter_name",
|
||||
CASE (p.proargmodes::text[])[a.ordinal_position]
|
||||
WHEN 'o' THEN 'OUT'
|
||||
WHEN 'b' THEN 'INOUT'
|
||||
WHEN 'v' THEN 'VARIADIC'
|
||||
WHEN 't' THEN 'TABLE'
|
||||
ELSE 'IN'
|
||||
END AS "parameter_mode",
|
||||
pg_catalog.format_type(a.parameter_type, NULL) AS "data_type",
|
||||
a.ordinal_position AS "parameter_index"
|
||||
FROM pg_catalog.pg_proc p
|
||||
JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
|
||||
CROSS JOIN LATERAL unnest(
|
||||
COALESCE(p.proallargtypes, p.proargtypes::oid[]),
|
||||
p.proargnames
|
||||
) WITH ORDINALITY AS a(parameter_type, parameter_name, ordinal_position)
|
||||
WHERE p.prokind IN ('f', 'p')
|
||||
AND p.proargnames IS NOT NULL
|
||||
AND a.parameter_name IS NOT NULL
|
||||
AND n.nspname !~ '^_timescaledb_'
|
||||
AND n.nspname NOT IN ('pg_catalog', 'information_schema')
|
||||
AND n.nspname =SCHEMA_NAME_CONDITION
|
||||
AND (
|
||||
(routine_type = 'PROCEDURE' AND ('procedures:' || proc.specific_schema || '.' || routine_name) =OBJECT_ID_CONDITION)
|
||||
OR
|
||||
(routine_type = 'FUNCTION' AND ('functions:' || proc.specific_schema || '.' || routine_name) =OBJECT_ID_CONDITION)
|
||||
(p.prokind = 'p' AND ('procedures:' || n.nspname || '.' || p.proname) =OBJECT_ID_CONDITION)
|
||||
OR
|
||||
(p.prokind != 'p' AND ('functions:' || n.nspname || '.' || p.proname) =OBJECT_ID_CONDITION)
|
||||
)
|
||||
ORDER BY
|
||||
schema_name,
|
||||
args.ordinal_position;
|
||||
ORDER BY n.nspname, a.ordinal_position
|
||||
`;
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
module.exports = `
|
||||
SELECT
|
||||
proc.specific_schema AS schema_name,
|
||||
proc.routine_name AS pure_name,
|
||||
proc.routine_type as routine_type,
|
||||
args.parameter_name AS parameter_name,
|
||||
args.parameter_mode,
|
||||
args.data_type AS data_type,
|
||||
args.ordinal_position AS parameter_index,
|
||||
args.parameter_mode AS parameter_mode
|
||||
FROM
|
||||
information_schema.routines proc
|
||||
LEFT JOIN
|
||||
information_schema.parameters args
|
||||
ON proc.specific_schema = args.specific_schema
|
||||
AND proc.specific_name = args.specific_name
|
||||
WHERE
|
||||
proc.specific_schema NOT IN ('pg_catalog', 'information_schema')
|
||||
AND args.parameter_name IS NOT NULL
|
||||
AND proc.routine_type IN ('PROCEDURE', 'FUNCTION')
|
||||
AND proc.specific_schema !~ '^_timescaledb_'
|
||||
AND proc.specific_schema =SCHEMA_NAME_CONDITION
|
||||
AND (
|
||||
(routine_type = 'PROCEDURE' AND ('procedures:' || proc.specific_schema || '.' || routine_name) =OBJECT_ID_CONDITION)
|
||||
OR
|
||||
(routine_type = 'FUNCTION' AND ('functions:' || proc.specific_schema || '.' || routine_name) =OBJECT_ID_CONDITION)
|
||||
)
|
||||
ORDER BY
|
||||
schema_name,
|
||||
args.ordinal_position;
|
||||
`;
|
||||
@@ -1,10 +1,13 @@
|
||||
module.exports = `
|
||||
select
|
||||
routine_name as "pure_name",
|
||||
routine_schema as "schema_name",
|
||||
$md5Function(routine_definition) as "hash_code",
|
||||
routine_type as "object_type"
|
||||
from
|
||||
information_schema.routines where routine_schema !~ '^_timescaledb_'
|
||||
and routine_type in ('PROCEDURE', 'FUNCTION') and routine_schema =SCHEMA_NAME_CONDITION
|
||||
SELECT
|
||||
p.proname AS "pure_name",
|
||||
n.nspname AS "schema_name",
|
||||
$md5Function(p.prosrc) AS "hash_code",
|
||||
CASE p.prokind WHEN 'p' THEN 'PROCEDURE' ELSE 'FUNCTION' END AS "object_type"
|
||||
FROM pg_catalog.pg_proc p
|
||||
JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
|
||||
WHERE p.prokind IN ('f', 'p')
|
||||
AND n.nspname !~ '^_timescaledb_'
|
||||
AND n.nspname NOT IN ('pg_catalog', 'information_schema')
|
||||
AND n.nspname =SCHEMA_NAME_CONDITION
|
||||
`;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
module.exports = `
|
||||
select
|
||||
routine_name as "pure_name",
|
||||
routine_schema as "schema_name",
|
||||
$md5Function(routine_definition) as "hash_code",
|
||||
routine_type as "object_type"
|
||||
from
|
||||
information_schema.routines where routine_schema !~ '^_timescaledb_'
|
||||
and routine_type in ('PROCEDURE', 'FUNCTION') and routine_schema =SCHEMA_NAME_CONDITION
|
||||
`;
|
||||
@@ -1,19 +1,23 @@
|
||||
module.exports = `
|
||||
select
|
||||
routine_name as "pure_name",
|
||||
routine_schema as "schema_name",
|
||||
max(routine_definition) as "definition",
|
||||
max($md5Function(routine_definition)) as "hash_code",
|
||||
routine_type as "object_type",
|
||||
$typeAggFunc(data_type $typeAggParam) as "data_type",
|
||||
max(external_language) as "language"
|
||||
from
|
||||
information_schema.routines where routine_schema !~ '^_timescaledb_'
|
||||
and routine_schema =SCHEMA_NAME_CONDITION
|
||||
and (
|
||||
(routine_type = 'PROCEDURE' and ('procedures:' || routine_schema || '.' || routine_name) =OBJECT_ID_CONDITION)
|
||||
or
|
||||
(routine_type = 'FUNCTION' and ('functions:' || routine_schema || '.' || routine_name) =OBJECT_ID_CONDITION)
|
||||
)
|
||||
group by routine_name, routine_schema, routine_type
|
||||
SELECT
|
||||
p.proname AS "pure_name",
|
||||
n.nspname AS "schema_name",
|
||||
max(p.prosrc) AS "definition",
|
||||
max($md5Function(p.prosrc)) AS "hash_code",
|
||||
CASE max(p.prokind) WHEN 'p' THEN 'PROCEDURE' ELSE 'FUNCTION' END AS "object_type",
|
||||
$typeAggFunc(pg_catalog.format_type(p.prorettype, NULL) $typeAggParam) AS "data_type",
|
||||
max(l.lanname) AS "language"
|
||||
FROM pg_catalog.pg_proc p
|
||||
JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
|
||||
JOIN pg_catalog.pg_language l ON l.oid = p.prolang
|
||||
WHERE p.prokind IN ('f', 'p')
|
||||
AND n.nspname !~ '^_timescaledb_'
|
||||
AND n.nspname NOT IN ('pg_catalog', 'information_schema')
|
||||
AND n.nspname =SCHEMA_NAME_CONDITION
|
||||
AND (
|
||||
(p.prokind = 'p' AND ('procedures:' || n.nspname || '.' || p.proname) =OBJECT_ID_CONDITION)
|
||||
OR
|
||||
(p.prokind != 'p' AND ('functions:' || n.nspname || '.' || p.proname) =OBJECT_ID_CONDITION)
|
||||
)
|
||||
GROUP BY p.proname, n.nspname, p.prokind
|
||||
`;
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
module.exports = `
|
||||
select
|
||||
routine_name as "pure_name",
|
||||
routine_schema as "schema_name",
|
||||
max(routine_definition) as "definition",
|
||||
max($md5Function(routine_definition)) as "hash_code",
|
||||
routine_type as "object_type",
|
||||
$typeAggFunc(data_type $typeAggParam) as "data_type",
|
||||
max(external_language) as "language"
|
||||
from
|
||||
information_schema.routines where routine_schema !~ '^_timescaledb_'
|
||||
and routine_schema =SCHEMA_NAME_CONDITION
|
||||
and (
|
||||
(routine_type = 'PROCEDURE' and ('procedures:' || routine_schema || '.' || routine_name) =OBJECT_ID_CONDITION)
|
||||
or
|
||||
(routine_type = 'FUNCTION' and ('functions:' || routine_schema || '.' || routine_name) =OBJECT_ID_CONDITION)
|
||||
)
|
||||
group by routine_name, routine_schema, routine_type
|
||||
`;
|
||||
@@ -1,10 +1,35 @@
|
||||
module.exports = `
|
||||
select infoTables.table_schema as "schema_name", infoTables.table_name as "pure_name",
|
||||
pg_relation_size('"'||infoTables.table_schema||'"."'||infoTables.table_name||'"') as "size_bytes"
|
||||
from information_schema.tables infoTables
|
||||
where infoTables.table_type not like '%VIEW%'
|
||||
and ('tables:' || infoTables.table_schema || '.' || infoTables.table_name) =OBJECT_ID_CONDITION
|
||||
and infoTables.table_schema <> 'pg_internal'
|
||||
and infoTables.table_schema !~ '^_timescaledb_'
|
||||
and infoTables.table_schema =SCHEMA_NAME_CONDITION
|
||||
SELECT
|
||||
n.nspname AS "schema_name",
|
||||
c.relname AS "pure_name",
|
||||
pg_relation_size(c.oid) AS "size_bytes",
|
||||
$md5Function(
|
||||
COALESCE(
|
||||
(SELECT $typeAggFunc(
|
||||
a.attname || ':' || pg_catalog.format_type(a.atttypid, a.atttypmod) || ':' || a.attnotnull::text
|
||||
$hashColumnAggTail
|
||||
)
|
||||
FROM pg_catalog.pg_attribute a
|
||||
WHERE a.attrelid = c.oid AND a.attnum > 0 AND NOT a.attisdropped),
|
||||
''
|
||||
)
|
||||
) AS "hash_code_columns",
|
||||
$md5Function(
|
||||
COALESCE(
|
||||
(SELECT $typeAggFunc(
|
||||
con.conname || ':' || con.contype::text
|
||||
$hashConstraintAggTail
|
||||
)
|
||||
FROM pg_catalog.pg_constraint con
|
||||
WHERE con.conrelid = c.oid),
|
||||
''
|
||||
)
|
||||
) AS "hash_code_constraints"
|
||||
FROM pg_catalog.pg_class c
|
||||
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE c.relkind IN ('r', 'p', 'f')
|
||||
AND ('tables:' || n.nspname || '.' || c.relname) =OBJECT_ID_CONDITION
|
||||
AND n.nspname <> 'pg_internal'
|
||||
AND n.nspname !~ '^_timescaledb_'
|
||||
AND n.nspname =SCHEMA_NAME_CONDITION
|
||||
`;
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
module.exports = `
|
||||
SELECT
|
||||
n.nspname AS "schema_name",
|
||||
c.relname AS "pure_name",
|
||||
$md5Function(
|
||||
COALESCE(
|
||||
(SELECT $typeAggFunc(
|
||||
a.attname || ':' || pg_catalog.format_type(a.atttypid, a.atttypmod) || ':' || a.attnotnull::text
|
||||
$hashColumnAggTail
|
||||
)
|
||||
FROM pg_catalog.pg_attribute a
|
||||
WHERE a.attrelid = c.oid AND a.attnum > 0 AND NOT a.attisdropped),
|
||||
''
|
||||
)
|
||||
) AS "hash_code_columns",
|
||||
$md5Function(
|
||||
COALESCE(
|
||||
(SELECT $typeAggFunc(
|
||||
con.conname || ':' || con.contype::text
|
||||
$hashConstraintAggTail
|
||||
)
|
||||
FROM pg_catalog.pg_constraint con
|
||||
WHERE con.conrelid = c.oid),
|
||||
''
|
||||
)
|
||||
) AS "hash_code_constraints"
|
||||
FROM pg_catalog.pg_class c
|
||||
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE c.relkind IN ('r', 'p', 'f')
|
||||
AND n.nspname <> 'pg_internal'
|
||||
AND n.nspname !~ '^_timescaledb_'
|
||||
AND n.nspname NOT IN ('pg_catalog', 'information_schema')
|
||||
AND n.nspname =SCHEMA_NAME_CONDITION
|
||||
`;
|
||||
@@ -1,8 +1,13 @@
|
||||
module.exports = `
|
||||
select
|
||||
table_name as "pure_name",
|
||||
table_schema as "schema_name",
|
||||
$md5Function(view_definition) as "hash_code"
|
||||
from
|
||||
information_schema.views where table_schema != 'information_schema' and table_schema != 'pg_catalog' and table_schema !~ '^_timescaledb_' and table_schema =SCHEMA_NAME_CONDITION
|
||||
SELECT
|
||||
c.relname AS "pure_name",
|
||||
n.nspname AS "schema_name",
|
||||
$md5Function(pg_get_viewdef(c.oid, true)) AS "hash_code"
|
||||
FROM pg_catalog.pg_class c
|
||||
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE c.relkind = 'v'
|
||||
AND n.nspname != 'information_schema'
|
||||
AND n.nspname != 'pg_catalog'
|
||||
AND n.nspname !~ '^_timescaledb_'
|
||||
AND n.nspname =SCHEMA_NAME_CONDITION
|
||||
`;
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
module.exports = `
|
||||
select
|
||||
table_name as "pure_name",
|
||||
table_schema as "schema_name",
|
||||
view_definition as "create_sql",
|
||||
$md5Function(view_definition) as "hash_code"
|
||||
from
|
||||
information_schema.views
|
||||
where table_schema !~ '^_timescaledb_' and table_schema =SCHEMA_NAME_CONDITION
|
||||
and ('views:' || table_schema || '.' || table_name) =OBJECT_ID_CONDITION
|
||||
WITH view_defs AS (
|
||||
SELECT
|
||||
c.relname AS pure_name,
|
||||
n.nspname AS schema_name,
|
||||
pg_get_viewdef(c.oid, true) AS viewdef
|
||||
FROM pg_catalog.pg_class c
|
||||
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE c.relkind = 'v'
|
||||
AND n.nspname !~ '^_timescaledb_'
|
||||
AND n.nspname =SCHEMA_NAME_CONDITION
|
||||
AND ('views:' || n.nspname || '.' || c.relname) =OBJECT_ID_CONDITION
|
||||
)
|
||||
SELECT
|
||||
pure_name AS "pure_name",
|
||||
schema_name AS "schema_name",
|
||||
viewdef AS "create_sql",
|
||||
$md5Function(viewdef) AS "hash_code"
|
||||
FROM view_defs
|
||||
`;
|
||||
|
||||
@@ -418,6 +418,7 @@ const redshiftDriver = {
|
||||
},
|
||||
__analyserInternals: {
|
||||
skipIndexes: true,
|
||||
useInfoSchemaRoutines: true,
|
||||
},
|
||||
engine: 'redshift@dbgate-plugin-postgres',
|
||||
title: 'Amazon Redshift',
|
||||
|
||||
Reference in New Issue
Block a user