diff --git a/packages/api/src/proc/databaseConnectionProcess.js b/packages/api/src/proc/databaseConnectionProcess.js index f5994b83f..bed349355 100644 --- a/packages/api/src/proc/databaseConnectionProcess.js +++ b/packages/api/src/proc/databaseConnectionProcess.js @@ -366,8 +366,6 @@ async function handleSaveTableData({ msgid, changeSet }) { errorMessage: extractErrorMessage(err, 'Error executing SQL script'), }); } - - } async function handleSqlPreview({ msgid, objects, options }) { diff --git a/packages/datalib/src/GridDisplay.ts b/packages/datalib/src/GridDisplay.ts index 3a2d24d4a..d4e3b40e9 100644 --- a/packages/datalib/src/GridDisplay.ts +++ b/packages/datalib/src/GridDisplay.ts @@ -13,7 +13,7 @@ import type { FilterBehaviour, } from 'dbgate-types'; import { parseFilter } from 'dbgate-filterparser'; -import { filterName } from 'dbgate-tools'; +import { filterName, shortenIdentifier } from 'dbgate-tools'; import { ChangeSetFieldDefinition, ChangeSetRowDefinition } from './ChangeSet'; import { Expression, Select, treeToSql, dumpSqlSelect, Condition, CompoudCondition } from 'dbgate-sqltree'; import { isTypeLogical, standardFilterBehaviours, detectSqlFilterBehaviour, stringFilterBehaviour } from 'dbgate-tools'; @@ -606,7 +606,9 @@ export abstract class GridDisplay { } return { exprType: 'column', - ...(!this.dialect.omitTableAliases && { alias: alias || col.columnName }), + ...(!this.dialect.omitTableAliases && { + alias: alias ? shortenIdentifier(alias, this.driver.dialect.maxIdentifierLength) : col.columnName, + }), source, ...col, }; diff --git a/packages/datalib/src/TableGridDisplay.ts b/packages/datalib/src/TableGridDisplay.ts index dc4f3588d..9cd49098d 100644 --- a/packages/datalib/src/TableGridDisplay.ts +++ b/packages/datalib/src/TableGridDisplay.ts @@ -1,5 +1,5 @@ import _ from 'lodash'; -import { filterName, isTableColumnUnique } from 'dbgate-tools'; +import { filterName, isTableColumnUnique, shortenIdentifier } from 'dbgate-tools'; import { GridDisplay, ChangeCacheFunc, DisplayColumn, DisplayedColumnInfo, ChangeConfigFunc } from './GridDisplay'; import type { TableInfo, @@ -101,8 +101,8 @@ export class TableGridDisplay extends GridDisplay { ...col, isChecked: this.isColumnChecked(col), hintColumnNames: - this.getFkDictionaryDescription(col.isForeignKeyUnique ? col.foreignKey : null)?.columns?.map( - columnName => `hint_${col.uniqueName}_${columnName}` + this.getFkDictionaryDescription(col.isForeignKeyUnique ? col.foreignKey : null)?.columns?.map(columnName => + shortenIdentifier(`hint_${col.uniqueName}_${columnName}`, this.driver.dialect.maxIdentifierLength) ) || null, hintColumnDelimiter: this.getFkDictionaryDescription(col.isForeignKeyUnique ? col.foreignKey : null) ?.delimiter, @@ -116,7 +116,7 @@ export class TableGridDisplay extends GridDisplay { if (this.isExpandedColumn(column.uniqueName)) { const table = this.getFkTarget(column); if (table) { - const childAlias = `${column.uniqueName}_ref`; + const childAlias = shortenIdentifier(`${column.uniqueName}_ref`, this.driver.dialect.maxIdentifierLength); const subcolumns = this.getDisplayColumns(table, column.uniquePath); this.addReferenceToSelect(select, parentAlias, column); @@ -129,7 +129,7 @@ export class TableGridDisplay extends GridDisplay { } addReferenceToSelect(select: Select, parentAlias: string, column: DisplayColumn) { - const childAlias = `${column.uniqueName}_ref`; + const childAlias = shortenIdentifier(`${column.uniqueName}_ref`, this.driver.dialect.maxIdentifierLength); if ((select.from.relations || []).find(x => x.alias == childAlias)) return; const table = this.getFkTarget(column); if (table && table.primaryKey) { @@ -191,15 +191,24 @@ export class TableGridDisplay extends GridDisplay { const hintDescription = this.getDictionaryDescription(table); if (hintDescription) { const parentUniqueName = column.uniquePath.slice(0, -1).join('.'); - this.addReferenceToSelect(select, parentUniqueName ? `${parentUniqueName}_ref` : 'basetbl', column); - const childAlias = `${column.uniqueName}_ref`; + this.addReferenceToSelect( + select, + parentUniqueName + ? shortenIdentifier(`${parentUniqueName}_ref`, this.driver.dialect.maxIdentifierLength) + : 'basetbl', + column + ); + const childAlias = shortenIdentifier(`${column.uniqueName}_ref`, this.driver.dialect.maxIdentifierLength); select.columns.push( ...hintDescription.columns.map( columnName => ({ exprType: 'column', columnName, - alias: `hint_${column.uniqueName}_${columnName}`, + alias: shortenIdentifier( + `hint_${column.uniqueName}_${columnName}`, + this.driver.dialect.maxIdentifierLength + ), source: { alias: childAlias }, } as ColumnRefExpression) ) @@ -230,7 +239,7 @@ export class TableGridDisplay extends GridDisplay { } getFkTarget(column: DisplayColumn) { - const { uniqueName, foreignKey, isForeignKeyUnique } = column; + const { foreignKey, isForeignKeyUnique } = column; if (!isForeignKeyUnique) return null; const pureName = foreignKey.refTableName; const schemaName = foreignKey.refSchemaName; diff --git a/packages/tools/package.json b/packages/tools/package.json index 40bc17396..26aaf9eda 100644 --- a/packages/tools/package.json +++ b/packages/tools/package.json @@ -32,6 +32,7 @@ "typescript": "^4.4.3" }, "dependencies": { + "blueimp-md5": "^2.19.0", "dbgate-query-splitter": "^4.11.7", "dbgate-sqltree": "^6.0.0-alpha.1", "debug": "^4.3.4", diff --git a/packages/tools/src/stringTools.ts b/packages/tools/src/stringTools.ts index 88eb39e69..1abd2a50b 100644 --- a/packages/tools/src/stringTools.ts +++ b/packages/tools/src/stringTools.ts @@ -9,6 +9,7 @@ import _isEmpty from 'lodash/isEmpty'; import _omitBy from 'lodash/omitBy'; import { DataEditorTypesBehaviour } from 'dbgate-types'; import isPlainObject from 'lodash/isPlainObject'; +import md5 from 'blueimp-md5'; export const MAX_GRID_TEXT_LENGTH = 1000; // maximum length of text in grid cell, longer text is truncated @@ -737,3 +738,12 @@ export function setSqlFrontMatter(text: string, data: { [key: string]: any }, ya const frontMatterContent = `-- >>>\n${yamlContentMapped}\n-- <<<\n`; return frontMatterContent + (textClean || ''); } + +export function shortenIdentifier(s: string, maxLength?: number) { + if (!maxLength || maxLength < 10) return s; + if (s.length <= maxLength) return s; + const hash = md5(s).substring(0, 8); + const partLength = Math.floor((maxLength - 9) / 2); + const restLength = maxLength - 10 - partLength; + return s.substring(0, partLength) + '_' + hash + '_' + s.substring(s.length - restLength); +} diff --git a/packages/types/dialect.d.ts b/packages/types/dialect.d.ts index b06a30071..9f6099290 100644 --- a/packages/types/dialect.d.ts +++ b/packages/types/dialect.d.ts @@ -22,6 +22,7 @@ export interface SqlDialect { requireStandaloneSelectForScopeIdentity?: boolean; allowMultipleValuesInsert?: boolean; useServerDatabaseFile?: boolean; + maxIdentifierLength?: number; dropColumnDependencies?: string[]; changeColumnDependencies?: string[]; diff --git a/plugins/dbgate-plugin-firebird/src/frontend/driver.js b/plugins/dbgate-plugin-firebird/src/frontend/driver.js index b7ddcb2cb..633433c4e 100644 --- a/plugins/dbgate-plugin-firebird/src/frontend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/frontend/driver.js @@ -18,6 +18,7 @@ const dialect = { renameColumnDependencies: ['dependencies', 'foreignKeys', 'uniques'], defaultValueBeforeNullability: true, useServerDatabaseFile: true, + maxIdentifierLength: 31, quoteIdentifier(s) { return `"${s}"`;