diff --git a/plugins/dbgate-plugin-postgres/src/backend/Analyser.js b/plugins/dbgate-plugin-postgres/src/backend/Analyser.js index 01485b0c2..1fd2f0f51 100644 --- a/plugins/dbgate-plugin-postgres/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-postgres/src/backend/Analyser.js @@ -11,21 +11,36 @@ function normalizeTypeName(dataType) { return dataType; } -function getColumnInfo({ - is_nullable, - column_name, - data_type, - char_max_length, - numeric_precision, - numeric_ccale, - default_value, -}) { +function getColumnInfo( + { is_nullable, column_name, data_type, char_max_length, numeric_precision, numeric_ccale, default_value }, + table = undefined, + geometryColumns = undefined, + geographyColumns = undefined +) { const normDataType = normalizeTypeName(data_type); let fullDataType = normDataType; if (char_max_length && isTypeString(normDataType)) fullDataType = `${normDataType}(${char_max_length})`; if (numeric_precision && numeric_ccale && isTypeNumeric(normDataType)) fullDataType = `${normDataType}(${numeric_precision},${numeric_ccale})`; const autoIncrement = !!(default_value && default_value.startsWith('nextval(')); + if ( + table && + geometryColumns && + geometryColumns.rows.find( + x => x.schema_name == table.schemaName && x.pure_name == table.pureName && x.column_name == column_name + ) + ) { + fullDataType = 'geometry'; + } + if ( + table && + geographyColumns && + geographyColumns.rows.find( + x => x.schema_name == table.schemaName && x.pure_name == table.pureName && x.column_name == column_name + ) + ) { + fullDataType = 'geography'; + } return { columnName: column_name, dataType: fullDataType, @@ -145,6 +160,18 @@ class Analyser extends DatabaseAnalyser { : await this.driver.query(this.pool, this.createQuery('indexcols', ['tables'])); this.feedback({ analysingMessage: 'Loading unique names' }); const uniqueNames = await this.driver.query(this.pool, this.createQuery('uniqueNames', ['tables'])); + + let geometryColumns = { rows: [] }; + if (views.rows.find(x => (x.pure_name = 'geometry_columns' && x.schema_name == 'public'))) { + this.feedback({ analysingMessage: 'Loading geometry columns' }); + geometryColumns = await this.driver.query(this.pool, this.createQuery('geometryColumns', ['tables'])); + } + let geographyColumns = { rows: [] }; + if (views.rows.find(x => (x.pure_name = 'geography_columns' && x.schema_name == 'public'))) { + this.feedback({ analysingMessage: 'Loading geography columns' }); + geographyColumns = await this.driver.query(this.pool, this.createQuery('geographyColumns', ['tables'])); + } + this.feedback({ analysingMessage: 'Finalizing DB structure' }); const columnColumnsMapped = fkColumns.rows.map(x => ({ @@ -179,7 +206,7 @@ class Analyser extends DatabaseAnalyser { ...newTable, columns: columns.rows .filter(col => col.pure_name == table.pure_name && col.schema_name == table.schema_name) - .map(getColumnInfo), + .map(col => getColumnInfo(col, newTable, geometryColumns, geographyColumns)), primaryKey: DatabaseAnalyser.extractPrimaryKeys(newTable, pkColumnsMapped), foreignKeys: DatabaseAnalyser.extractForeignKeys(newTable, columnColumnsMapped), indexes: indexes.rows @@ -231,7 +258,7 @@ class Analyser extends DatabaseAnalyser { 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(getColumnInfo), + .map(col => getColumnInfo(col)), })), matviews: matviews ? matviews.rows.map(matview => ({ @@ -242,7 +269,7 @@ class Analyser extends DatabaseAnalyser { 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) - .map(getColumnInfo), + .map(col => getColumnInfo(col)), })) : undefined, procedures: routines.rows diff --git a/plugins/dbgate-plugin-postgres/src/backend/sql/geographyColumns.js b/plugins/dbgate-plugin-postgres/src/backend/sql/geographyColumns.js new file mode 100644 index 000000000..343d9c5d6 --- /dev/null +++ b/plugins/dbgate-plugin-postgres/src/backend/sql/geographyColumns.js @@ -0,0 +1,8 @@ +module.exports = ` +select + f_table_schema as "schema_name", + f_table_name as "pure_name", + f_geography_column as "column_name" +from public.geography_columns +where ('tables:' || f_table_schema || '.' || f_table_name) =OBJECT_ID_CONDITION +`; \ No newline at end of file diff --git a/plugins/dbgate-plugin-postgres/src/backend/sql/geometryColumns.js b/plugins/dbgate-plugin-postgres/src/backend/sql/geometryColumns.js new file mode 100644 index 000000000..94b8d5516 --- /dev/null +++ b/plugins/dbgate-plugin-postgres/src/backend/sql/geometryColumns.js @@ -0,0 +1,8 @@ +module.exports = ` +select + f_table_schema as "schema_name", + f_table_name as "pure_name", + f_geometry_column as "column_name" +from public.geometry_columns +where ('tables:' || f_table_schema || '.' || f_table_name) =OBJECT_ID_CONDITION +`; \ No newline at end of file diff --git a/plugins/dbgate-plugin-postgres/src/backend/sql/index.js b/plugins/dbgate-plugin-postgres/src/backend/sql/index.js index b029fb6f2..4c2f500a4 100644 --- a/plugins/dbgate-plugin-postgres/src/backend/sql/index.js +++ b/plugins/dbgate-plugin-postgres/src/backend/sql/index.js @@ -13,6 +13,8 @@ const matviewColumns = require('./matviewColumns'); const indexes = require('./indexes'); const indexcols = require('./indexcols'); const uniqueNames = require('./uniqueNames'); +const geometryColumns = require('./geometryColumns'); +const geographyColumns = require('./geographyColumns'); const fk_keyColumnUsage = require('./fk_key_column_usage'); const fk_referentialConstraints = require('./fk_referential_constraints'); @@ -37,4 +39,6 @@ module.exports = { indexes, indexcols, uniqueNames, + geometryColumns, + geographyColumns, }; diff --git a/plugins/dbgate-plugin-postgres/src/frontend/drivers.js b/plugins/dbgate-plugin-postgres/src/frontend/drivers.js index d533ea3ea..5d60186ff 100644 --- a/plugins/dbgate-plugin-postgres/src/frontend/drivers.js +++ b/plugins/dbgate-plugin-postgres/src/frontend/drivers.js @@ -2,6 +2,8 @@ const { driverBase } = global.DBGATE_TOOLS; const Dumper = require('./Dumper'); const { postgreSplitterOptions } = require('dbgate-query-splitter/lib/options'); +const spatialTypes = ['GEOGRAPHY']; + /** @type {import('dbgate-types').SqlDialect} */ const dialect = { rangeSelect: true, @@ -78,6 +80,23 @@ const dialect = { 'uuid', 'xml', ], + + createColumnViewExpression(columnName, dataType, source, alias) { + if (dataType && spatialTypes.includes(dataType.toUpperCase())) { + return { + exprType: 'call', + func: 'ST_AsText', + alias: alias || columnName, + args: [ + { + exprType: 'column', + columnName, + source, + }, + ], + }; + } + }, }; const postgresDriverBase = {