From bac8bd0006179f2e82a1103ec1df439d9c541b6f Mon Sep 17 00:00:00 2001 From: Nybkox Date: Tue, 6 May 2025 15:51:49 +0200 Subject: [PATCH 01/65] feat: add firebird to to tests compose --- integration-tests/docker-compose.yaml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/integration-tests/docker-compose.yaml b/integration-tests/docker-compose.yaml index 6ea85877c..61d90766e 100644 --- a/integration-tests/docker-compose.yaml +++ b/integration-tests/docker-compose.yaml @@ -89,3 +89,28 @@ services: # - '5002:5001' # volumes: # - ./data/libsql:/var/lib/sqld + + firebird: + image: firebirdsql/firebird:latest + container_name: firebird-db + environment: + - FIREBIRD_DATABASE=mydatabase.fdb + - FIREBIRD_USER=dbuser + - FIREBIRD_PASSWORD=dbpassword + - ISC_PASSWORD=masterkey + - FIREBIRD_TRACE=false + - FIREBIRD_USE_LEGACY_AUTH=true + ports: + - '3050:3050' + volumes: + - firebird-data:/firebird/data + - ./firebird.conf:/firebird/firebird.conf # Mount custom config file + healthcheck: + test: ['CMD', 'nc', '-z', 'localhost', '3050'] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + +volumes: + firebird-data: From 839ec9a456a94098f618a3b006d21ecc5832935d Mon Sep 17 00:00:00 2001 From: Nybkox Date: Tue, 6 May 2025 15:52:15 +0200 Subject: [PATCH 02/65] feat: basic firebird analyser --- integration-tests/firebird.conf | 45 ++++++ plugins/dbgate-plugin-firebird/package.json | 46 ++++++ .../dbgate-plugin-firebird/prettier.config.js | 9 ++ .../src/backend/Analyser.js | 51 ++++++ .../src/backend/driver.js | 146 ++++++++++++++++++ .../src/backend/helpers.js | 54 +++++++ .../src/backend/index.js | 7 + .../src/backend/sql/columns.js | 43 ++++++ .../src/backend/sql/index.js | 9 ++ .../src/backend/sql/tables.js | 9 ++ .../src/backend/sql/version.js | 1 + .../src/frontend/Dumper.js | 5 + .../src/frontend/driver.js | 85 ++++++++++ .../src/frontend/index.js | 6 + .../webpack-backend.config.js | 46 ++++++ .../webpack-frontend.config.js | 30 ++++ yarn.lock | 18 +++ 17 files changed, 610 insertions(+) create mode 100644 integration-tests/firebird.conf create mode 100644 plugins/dbgate-plugin-firebird/package.json create mode 100644 plugins/dbgate-plugin-firebird/prettier.config.js create mode 100644 plugins/dbgate-plugin-firebird/src/backend/Analyser.js create mode 100644 plugins/dbgate-plugin-firebird/src/backend/driver.js create mode 100644 plugins/dbgate-plugin-firebird/src/backend/helpers.js create mode 100644 plugins/dbgate-plugin-firebird/src/backend/index.js create mode 100644 plugins/dbgate-plugin-firebird/src/backend/sql/columns.js create mode 100644 plugins/dbgate-plugin-firebird/src/backend/sql/index.js create mode 100644 plugins/dbgate-plugin-firebird/src/backend/sql/tables.js create mode 100644 plugins/dbgate-plugin-firebird/src/backend/sql/version.js create mode 100644 plugins/dbgate-plugin-firebird/src/frontend/Dumper.js create mode 100644 plugins/dbgate-plugin-firebird/src/frontend/driver.js create mode 100644 plugins/dbgate-plugin-firebird/src/frontend/index.js create mode 100644 plugins/dbgate-plugin-firebird/webpack-backend.config.js create mode 100644 plugins/dbgate-plugin-firebird/webpack-frontend.config.js diff --git a/integration-tests/firebird.conf b/integration-tests/firebird.conf new file mode 100644 index 000000000..4ebebf759 --- /dev/null +++ b/integration-tests/firebird.conf @@ -0,0 +1,45 @@ +# Custom Firebird Configuration + +# Wire encryption settings +# Options: Enabled, Required, Disabled +WireCrypt = Disabled + +# Authentication settings +# Add Legacy_Auth to support older clients +AuthServer = Legacy_Auth + +# User manager plugin +UserManager = Legacy_UserManager + +# Default character set +DefaultCharSet = UTF8 + +# Buffer settings for better performance +DefaultDbCachePages = 2048 +TempCacheLimit = 512M + +# Connection settings +ConnectionTimeout = 180 +DatabaseGrowthIncrement = 128M + +# TCP Protocol settings +TcpRemoteBufferSize = 8192 +TcpNoNagle = 1 + +# Security settings +RemoteServiceName = gds_db +RemoteServicePort = 3050 +RemoteAuxPort = 0 +RemotePipeName = firebird + +# Lock settings +LockMemSize = 1M +LockHashSlots = 8191 +LockAcquireSpins = 0 + +# Log settings +FileSystemCacheThreshold = 65536 +FileSystemCacheSize = 0 + +# Compatibility settings for older clients +CompatiblityDialect = 3 diff --git a/plugins/dbgate-plugin-firebird/package.json b/plugins/dbgate-plugin-firebird/package.json new file mode 100644 index 000000000..5af25c58e --- /dev/null +++ b/plugins/dbgate-plugin-firebird/package.json @@ -0,0 +1,46 @@ +{ + "name": "dbgate-plugin-firebird", + "main": "dist/backend.js", + "version": "6.0.0-alpha.1", + "license": "GPL-3.0", + "description": "firebirdQL connector plugin for DbGate", + "homepage": "https://dbgate.org", + "repository": { + "type": "git", + "url": "https://github.com/dbgate/dbgate" + }, + "author": "Jan Prochazka", + "keywords": [ + "dbgate", + "firebird", + "dbgatebuiltin" + ], + "files": [ + "dist", + "icon.svg" + ], + "scripts": { + "build:frontend": "webpack --config webpack-frontend.config", + "build:frontend:watch": "webpack --watch --config webpack-frontend.config", + "build:backend": "webpack --config webpack-backend.config.js", + "build": "yarn build:frontend && yarn build:backend", + "plugin": "yarn build && yarn pack && dbgate-plugin dbgate-plugin-firebird", + "copydist": "yarn build && yarn pack && dbgate-copydist ../dist/dbgate-plugin-firebird", + "plugout": "dbgate-plugout dbgate-plugin-firebird", + "prepublishOnly": "yarn build" + }, + "devDependencies": { + "dbgate-plugin-tools": "^1.0.7", + "webpack": "^5.91.0", + "webpack-cli": "^5.1.4" + }, + "dependencies": { + "wkx": "^0.5.0", + "pg-copy-streams": "^6.0.6", + "node-firebird": "^1.1.9", + "dbgate-query-splitter": "^4.11.3", + "dbgate-tools": "^6.0.0-alpha.1", + "lodash": "^4.17.21", + "pg": "^8.11.5" + } +} diff --git a/plugins/dbgate-plugin-firebird/prettier.config.js b/plugins/dbgate-plugin-firebird/prettier.config.js new file mode 100644 index 000000000..c05d71875 --- /dev/null +++ b/plugins/dbgate-plugin-firebird/prettier.config.js @@ -0,0 +1,9 @@ +module.exports = { + trailingComma: 'es5', + tabWidth: 2, + semi: true, + singleQuote: true, + arrowParen: 'avoid', + arrowParens: 'avoid', + printWidth: 120, +}; diff --git a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js new file mode 100644 index 000000000..a88fe4f76 --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js @@ -0,0 +1,51 @@ +const _ = require('lodash'); +const sql = require('./sql'); +const { getDataTypeString } = require('./helpers'); + +const { DatabaseAnalyser } = require('dbgate-tools'); + +class Analyser extends DatabaseAnalyser { + constructor(dbhan, driver, version) { + super(dbhan, driver, version); + } + + async _runAnalysis() { + const tablesResult = await this.driver.query(this.dbhan, sql.tables); + const columnsResult = await this.driver.query(this.dbhan, sql.columns); + + const columns = columnsResult.rows.map(i => ({ + tableName: i.TABLENAME, + columnName: i.COLUMNNAME, + notNull: i.NOTNULL, + isPrimaryKey: i.ISPRIMARYKEY, + dataType: getDataTypeString(i), + precision: i.NUMBERPRECISION, + scale: i.SCALE, + length: i.LENGTH, + defaultValue: i.DEFAULTVALUE, + columnComment: i.COLUMNCOMMENT, + isUnsigned: i.ISUNSIGNED, + pureName: i.PURENAME, + schemaName: i.SCHEMANAME, + })); + const tables = tablesResult.rows.map(i => ({ + pureName: i.PURENAME, + objectId: i.OBJECTID, + schemaName: i.SCHEMANAME, + objectComment: i.OBJECTCOMMENT, + })); + + return { + tables: tables.map(table => ({ + ...table, + columns: columns.filter(column => column.tableName === table.pureName), + })), + }; + } + + async _getFastSnapshot() { + return this._runAnalysis(); + } +} + +module.exports = Analyser; diff --git a/plugins/dbgate-plugin-firebird/src/backend/driver.js b/plugins/dbgate-plugin-firebird/src/backend/driver.js new file mode 100644 index 000000000..5c04830b0 --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/driver.js @@ -0,0 +1,146 @@ +const _ = require('lodash'); +const driverBase = require('../frontend/driver'); +const Analyser = require('./Analyser'); +const Firebird = require('node-firebird'); +const { getLogger, extractErrorLogData, createBulkInsertStreamBase } = require('dbgate-tools'); +const sql = require('./sql'); + +const logger = getLogger('firebird'); + +/** @type {import('dbgate-types').EngineDriver} */ +const driver = { + ...driverBase, + analyserClass: Analyser, + async connect({ port, user, password, server, databaseFile }) { + const options = { + host: server, + port, + database: databaseFile, + user, + password, + }; + + /**@type {Firebird.Database} */ + const db = await new Promise((resolve, reject) => { + Firebird.attach(options, (err, db) => { + if (err) { + reject(err); + return; + } + resolve(db); + }); + }); + + return { + client: db, + }; + }, + + async query(dbhan, sql) { + const res = await new Promise((resolve, reject) => { + dbhan.client.query(sql, (err, result) => { + if (err) { + reject(err); + return; + } + + resolve(result); + }); + }); + const columns = res[0] ? Object.keys(res[0]).map(i => ({ columnName: i })) : []; + + return { + rows: res, + columns, + }; + }, + + async script(dbhan, sql) { + throw new Error('Not implemented'); + }, + + async stream(dbhan, sql, options) { + try { + await new Promise((resolve, reject) => { + let hasSentColumns = false; + dbhan.client.sequentially( + sql, + [], + (row, index) => { + if (!hasSentColumns) { + hasSentColumns = true; + const columns = Object.keys(row).map(i => ({ columnName: i })); + options.recordset(columns); + } + + options.row(row); + }, + err => { + if (err) { + reject(err); + return; + } + + resolve(); + } + ); + }); + + options.done(); + } catch (err) { + logger.error(extractErrorLogData(err), 'Stream error'); + options.info({ + message: err.message, + line: err.line, + // procedure: procName, + time: new Date(), + severity: 'error', + }); + options.done(); + } + }, + + async readQuery(dbhan, sql, structure) { + throw new Error('Not implemented'); + }, + + async writeTable(dbhan, name, options) { + return createBulkInsertStream(this, stream, dbhan, name, options); + }, + + async getVersion(dbhan) { + const res = await this.query(dbhan, sql.version); + const version = res.rows?.[0]?.VERSION; + + return { + version, + versionText: `Firebird ${version}`, + }; + }, + + async listDatabases(dbhan) { + return [ + { + name: 'default', + }, + ]; + }, + + async createDatabase(dbhan, name) {}, + + async dropDatabase(dbhan, name) {}, + + async close(dbhan) { + return new Promise((resolve, reject) => { + dbhan.client.detach(err => { + if (err) { + reject(err); + return; + } + resolve(); + }); + }); + }, +}; + +module.exports = driver; diff --git a/plugins/dbgate-plugin-firebird/src/backend/helpers.js b/plugins/dbgate-plugin-firebird/src/backend/helpers.js new file mode 100644 index 000000000..a86d7f2b1 --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/helpers.js @@ -0,0 +1,54 @@ +function getDataTypeString(column) { + if (!column) { + return null; + } + const { DATATYPECODE, SCALE, LENGTH, NUMBERPRECISION } = column; + + switch (DATATYPECODE) { + case 7: + return 'SMALLINT'; + + case 8: + return 'INTEGER'; + + case 9: + return 'BIGINT'; + + case 10: + return 'FLOAT'; + + case 11: + return 'DOUBLE PRECISION'; + + case 12: + return 'DATE'; + + case 13: + return 'TIME'; + + case 14: + return `CHAR(${LENGTH})`; + + case 16: + return `DECIMAL(${NUMBERPRECISION}, ${SCALE})`; + + case 27: + return 'DOUBLE PRECISION'; + + case 35: + return 'BLOB'; + + case 37: + return `VARCHAR(${LENGTH})`; + + case 261: + return 'CSTRING'; + + default: + return `UNKNOWN (${DATATYPECODE})`; + } +} + +module.exports = { + getDataTypeString, +}; diff --git a/plugins/dbgate-plugin-firebird/src/backend/index.js b/plugins/dbgate-plugin-firebird/src/backend/index.js new file mode 100644 index 000000000..bee3b7706 --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/index.js @@ -0,0 +1,7 @@ +const driver = require('./driver'); + +module.exports = { + packageName: 'dbgate-plugin-firebird', + drivers: [driver], + initialize(dbgateEnv) {}, +}; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js new file mode 100644 index 000000000..8096ad9b8 --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js @@ -0,0 +1,43 @@ +module.exports = ` +SELECT DISTINCT + CAST(TRIM(rf.rdb$relation_name) AS VARCHAR(255)) AS tableName, + CAST(TRIM(rf.rdb$field_name) AS VARCHAR(255)) AS columnName, + CASE rf.rdb$null_flag WHEN 1 THEN FALSE ELSE TRUE END AS notNull, + CASE + WHEN EXISTS ( + SELECT 1 + FROM rdb$relation_constraints rc + JOIN rdb$index_segments idx ON rc.rdb$index_name = idx.rdb$index_name + WHERE rc.rdb$relation_name = rf.rdb$relation_name + AND idx.rdb$field_name = rf.rdb$field_name + AND rc.rdb$constraint_type = 'PRIMARY KEY' + ) THEN TRUE + ELSE FALSE + END AS isPrimaryKey, + f.rdb$field_type AS dataTypeCode, + f.rdb$field_precision AS numberprecision, + f.rdb$field_scale AS scale, + f.rdb$field_length AS length, + CAST(TRIM(rf.rdb$default_value) AS VARCHAR(255)) AS defaultValue, + CAST(TRIM(rf.rdb$description) AS VARCHAR(255)) AS columnComment, + CASE + WHEN f.rdb$field_type IN (8, 9, 16) AND f.rdb$field_scale < 0 THEN TRUE + ELSE FALSE + END AS isUnsigned, + CAST(TRIM(rf.rdb$field_name) AS VARCHAR(255)) AS pureName, + CAST(TRIM(r.rdb$owner_name) AS VARCHAR(255)) AS schemaName +FROM + rdb$relation_fields rf +JOIN + rdb$relations r ON rf.rdb$relation_name = r.rdb$relation_name +LEFT JOIN + rdb$fields f ON rf.rdb$field_source = f.rdb$field_name +LEFT JOIN + rdb$character_sets cs ON f.rdb$character_set_id = cs.rdb$character_set_id +LEFT JOIN + rdb$collations co ON f.rdb$collation_id = co.rdb$collation_id +WHERE + r.rdb$system_flag = 0 +ORDER BY + tableName, rf.rdb$field_position; +`; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/index.js b/plugins/dbgate-plugin-firebird/src/backend/sql/index.js new file mode 100644 index 000000000..5b56564ce --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/index.js @@ -0,0 +1,9 @@ +const version = require('./version'); +const tables = require('./tables'); +const columns = require('./columns'); + +module.exports = { + version, + columns, + tables, +}; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js b/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js new file mode 100644 index 000000000..2cd18e888 --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js @@ -0,0 +1,9 @@ +module.exports = ` +SELECT + TRIM(RDB$RELATION_NAME) AS pureName, + RDB$DESCRIPTION AS objectComment, + RDB$FORMAT AS objectTypeField +FROM RDB$RELATIONS +WHERE RDB$SYSTEM_FLAG = 0 -- only user-defined tables +ORDER BY pureName; +`; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/version.js b/plugins/dbgate-plugin-firebird/src/backend/sql/version.js new file mode 100644 index 000000000..ef95fb89a --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/version.js @@ -0,0 +1 @@ +module.exports = `SELECT rdb$get_context('SYSTEM', 'ENGINE_VERSION') as version from rdb$database;`; diff --git a/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js b/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js new file mode 100644 index 000000000..f0df62e8f --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js @@ -0,0 +1,5 @@ +const { SqlDumper } = global.DBGATE_PACKAGES['dbgate-tools']; + +class Dumper extends SqlDumper {} + +module.exports = Dumper; diff --git a/plugins/dbgate-plugin-firebird/src/frontend/driver.js b/plugins/dbgate-plugin-firebird/src/frontend/driver.js new file mode 100644 index 000000000..fa0ef8d1f --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/frontend/driver.js @@ -0,0 +1,85 @@ +const { driverBase } = global.DBGATE_PACKAGES['dbgate-tools']; +const Dumper = require('./Dumper'); + +/** @type {import('dbgate-types').SqlDialect} */ +const dialect = { + rangeSelect: true, + ilike: true, + defaultSchemaName: 'public', + multipleSchema: true, + stringEscapeChar: "'", + fallbackDataType: 'varchar', + anonymousPrimaryKey: false, + enableConstraintsPerTable: true, + stringAgg: true, + + createColumn: true, + dropColumn: true, + changeColumn: true, + createIndex: true, + dropIndex: true, + createForeignKey: true, + dropForeignKey: true, + createPrimaryKey: true, + dropPrimaryKey: true, + createUnique: true, + dropUnique: true, + createCheck: true, + dropCheck: true, + allowMultipleValuesInsert: true, + renameSqlObject: true, + filteredIndexes: true, +}; + +const firebirdSplitterOptions = { + stringsBegins: ["'", '"'], + stringsEnds: { + "'": "'", + '"': '"', + }, + stringEscapes: { + "'": "'", // Single quote is escaped by another single quote + '"': '"', // Double quote is escaped by another double quote + }, + allowSemicolon: true, + allowCustomDelimiter: false, + allowCustomSqlTerminator: false, + allowGoDelimiter: false, + allowSlashDelimiter: false, + allowDollarDollarString: false, + noSplit: false, + doubleDashComments: true, + multilineComments: true, + javaScriptComments: false, + skipSeparatorBeginEnd: false, + ignoreComments: false, + preventSingleLineSplit: false, + adaptiveGoSplit: false, + returnRichInfo: false, + splitByLines: false, + splitByEmptyLine: false, + copyFromStdin: false, + queryParameterStyle: ':', // Firebird uses colon-prefixed parameters (:param_name) +}; + +/** @type {import('dbgate-types').EngineDriver} */ +const firebirdDriverBase = { + ...driverBase, + defaultPort: 3050, + showConnectionField: field => ['port', 'user', 'password', 'server', 'databaseFile'].includes(field), + getQuerySplitterOptions: () => firebirdSplitterOptions, + // beforeConnectionSave: connection => { + // const { databaseFile } = connection; + // return { + // singleDatabase: true, + // defaultDatabase: databaseFile, + // }; + // }, + engine: 'firebird@dbgate-plugin-firebird', + title: 'Firebird', + supportsTransactions: true, + dumperClass: Dumper, + dialect, +}; + +module.exports = firebirdDriverBase; diff --git a/plugins/dbgate-plugin-firebird/src/frontend/index.js b/plugins/dbgate-plugin-firebird/src/frontend/index.js new file mode 100644 index 000000000..43f80c143 --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/frontend/index.js @@ -0,0 +1,6 @@ +import driver from './driver'; + +export default { + packageName: 'dbgate-plugin-firebird', + drivers: [driver], +}; diff --git a/plugins/dbgate-plugin-firebird/webpack-backend.config.js b/plugins/dbgate-plugin-firebird/webpack-backend.config.js new file mode 100644 index 000000000..06d31f8c4 --- /dev/null +++ b/plugins/dbgate-plugin-firebird/webpack-backend.config.js @@ -0,0 +1,46 @@ +var webpack = require('webpack'); +var path = require('path'); + +const packageJson = require('./package.json'); +const buildPluginExternals = require('../../common/buildPluginExternals'); +const externals = buildPluginExternals(packageJson); + +var config = { + context: __dirname + '/src/backend', + + entry: { + app: './index.js', + }, + target: 'node', + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'backend.js', + libraryTarget: 'commonjs2', + }, + + // uncomment for disable minimalization + // optimization: { + // minimize: false, + // }, + + plugins: [ + new webpack.IgnorePlugin({ + checkResource(resource) { + const lazyImports = ['pg-native', 'uws']; + if (!lazyImports.includes(resource)) { + return false; + } + try { + require.resolve(resource); + } catch (err) { + return true; + } + return false; + }, + }), + ], + + externals, +}; + +module.exports = config; diff --git a/plugins/dbgate-plugin-firebird/webpack-frontend.config.js b/plugins/dbgate-plugin-firebird/webpack-frontend.config.js new file mode 100644 index 000000000..cbc4a0a5a --- /dev/null +++ b/plugins/dbgate-plugin-firebird/webpack-frontend.config.js @@ -0,0 +1,30 @@ +var webpack = require('webpack'); +var path = require('path'); + +var config = { + context: __dirname + '/src/frontend', + + entry: { + app: './index.js', + }, + target: 'web', + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'frontend.js', + libraryTarget: 'var', + library: 'plugin', + }, + + plugins: [ + new webpack.DefinePlugin({ + 'global.DBGATE_PACKAGES': 'window.DBGATE_PACKAGES', + }), + ], + + // uncomment for disable minimalization + // optimization: { + // minimize: false, + // }, +}; + +module.exports = config; diff --git a/yarn.lock b/yarn.lock index 92632a452..b7614b904 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3310,6 +3310,11 @@ better-sqlite3@11.8.1: bindings "^1.5.0" prebuild-install "^7.1.1" +big-integer@^1.6.51: + version "1.6.52" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85" + integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg== + big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -7873,6 +7878,11 @@ long@*, long@^5.2.1, long@~5.2.3: resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== +long@^5.2.3: + version "5.3.2" + resolved "https://registry.yarnpkg.com/long/-/long-5.3.2.tgz#1d84463095999262d7d7b7f8bfd4a8cc55167f83" + integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA== + lru-cache@^10.2.0: version "10.4.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" @@ -8437,6 +8447,14 @@ node-cron@^2.0.3: opencollective-postinstall "^2.0.0" tz-offset "0.0.1" +node-firebird@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/node-firebird/-/node-firebird-1.1.9.tgz#0e6815b4e209812a4c85b71227e40e268bedeb8b" + integrity sha512-6Ol+Koide1WbfUp4BJ1dSA4wm091jAgCwwSoihxO/RRdcfR+dMVDE9jd2Z2ixjk7q/vSNJUYORXv7jmRfvwdrw== + dependencies: + big-integer "^1.6.51" + long "^5.2.3" + node-gyp@^7.1.0: version "7.1.2" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" From 3e2840ca15036b66fcb072c2966bed2725783e31 Mon Sep 17 00:00:00 2001 From: Nybkox Date: Wed, 7 May 2025 00:13:40 +0200 Subject: [PATCH 03/65] fix: add schema to tables --- plugins/dbgate-plugin-firebird/src/backend/Analyser.js | 4 +++- plugins/dbgate-plugin-firebird/src/backend/sql/tables.js | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js index a88fe4f76..99ff48fd5 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js @@ -38,7 +38,9 @@ class Analyser extends DatabaseAnalyser { return { tables: tables.map(table => ({ ...table, - columns: columns.filter(column => column.tableName === table.pureName), + columns: columns.filter( + column => column.tableName === table.pureName && column.schemaName === table.schemaName + ), })), }; } diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js b/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js index 2cd18e888..ac9f2d533 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js @@ -2,7 +2,8 @@ module.exports = ` SELECT TRIM(RDB$RELATION_NAME) AS pureName, RDB$DESCRIPTION AS objectComment, - RDB$FORMAT AS objectTypeField + RDB$FORMAT AS objectTypeField, + RDB$OWNER_NAME AS schemaName FROM RDB$RELATIONS WHERE RDB$SYSTEM_FLAG = 0 -- only user-defined tables ORDER BY pureName; From 3fd3de1828da4f1be45eaa98fec3dede17c43ed5 Mon Sep 17 00:00:00 2001 From: Nybkox Date: Wed, 7 May 2025 00:29:42 +0200 Subject: [PATCH 04/65] feat: add firebird triggers --- .../src/backend/Analyser.js | 13 +++++++- .../src/backend/helpers.js | 32 +++++++++++++++++++ .../src/backend/sql/index.js | 2 ++ .../src/backend/sql/triggers.js | 12 +++++++ 4 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 plugins/dbgate-plugin-firebird/src/backend/sql/triggers.js diff --git a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js index 99ff48fd5..5b3fdac48 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js @@ -1,6 +1,6 @@ const _ = require('lodash'); const sql = require('./sql'); -const { getDataTypeString } = require('./helpers'); +const { getDataTypeString, getTriggerTiming, getTriggerEventType } = require('./helpers'); const { DatabaseAnalyser } = require('dbgate-tools'); @@ -12,6 +12,7 @@ class Analyser extends DatabaseAnalyser { async _runAnalysis() { const tablesResult = await this.driver.query(this.dbhan, sql.tables); const columnsResult = await this.driver.query(this.dbhan, sql.columns); + const triggersResult = await this.driver.query(this.dbhan, sql.triggers); const columns = columnsResult.rows.map(i => ({ tableName: i.TABLENAME, @@ -28,6 +29,7 @@ class Analyser extends DatabaseAnalyser { pureName: i.PURENAME, schemaName: i.SCHEMANAME, })); + const tables = tablesResult.rows.map(i => ({ pureName: i.PURENAME, objectId: i.OBJECTID, @@ -35,6 +37,14 @@ class Analyser extends DatabaseAnalyser { objectComment: i.OBJECTCOMMENT, })); + const triggers = triggersResult.rows.map(i => ({ + pureName: i.PURENAME, + tableName: i.TABLENAME, + shcemaName: i.SCHEMANAME, + eventType: getTriggerEventType(i.TRIGGERTYPE), + triggerTiming: getTriggerTiming(i.TRIGGERTYPE), + })); + return { tables: tables.map(table => ({ ...table, @@ -42,6 +52,7 @@ class Analyser extends DatabaseAnalyser { column => column.tableName === table.pureName && column.schemaName === table.schemaName ), })), + triggers, }; } diff --git a/plugins/dbgate-plugin-firebird/src/backend/helpers.js b/plugins/dbgate-plugin-firebird/src/backend/helpers.js index a86d7f2b1..868296713 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/helpers.js +++ b/plugins/dbgate-plugin-firebird/src/backend/helpers.js @@ -49,6 +49,38 @@ function getDataTypeString(column) { } } +const eventMap = { + 1: { triggerTiming: 'BEFORE', eventType: 'INSERT' }, + 2: { triggerTiming: 'AFTER', eventType: 'INSERT' }, + 3: { triggerTiming: 'BEFORE', eventType: 'UPDATE' }, + 4: { triggerTiming: 'AFTER', eventType: 'UPDATE' }, + 5: { triggerTiming: 'BEFORE', eventType: 'DELETE' }, + 6: { triggerTiming: 'AFTER', eventType: 'DELETE' }, + 17: { triggerTiming: 'BEFORE', eventType: 'INSERT' }, // OR UPDATE + 18: { triggerTiming: 'AFTER', eventType: 'INSERT' }, // OR UPDATE + 25: { triggerTiming: 'BEFORE', eventType: 'INSERT' }, // OR DELETE + 26: { triggerTiming: 'AFTER', eventType: 'INSERT' }, // OR DELETE + 27: { triggerTiming: 'BEFORE', eventType: 'UPDATE' }, // OR DELETE + 28: { triggerTiming: 'AFTER', eventType: 'UPDATE' }, // OR DELETE + 113: { triggerTiming: 'BEFORE', eventType: 'INSERT' }, // OR UPDATE OR DELETE + 114: { triggerTiming: 'AFTER', eventType: 'INSERT' }, // OR UPDATE OR DELETE + 8192: { triggerTiming: 'BEFORE EVENT', eventType: null }, // ON CONNECT + 8193: { triggerTiming: 'AFTER EVENT', eventType: null }, // ON DISCONNECT + 8194: { triggerTiming: 'BEFORE STATEMENT', eventType: null }, // ON TRANSACTION START + 8195: { triggerTiming: 'AFTER STATEMENT', eventType: null }, // ON TRANSACTION COMMIT + 8196: { triggerTiming: 'AFTER STATEMENT', eventType: null }, // ON TRANSACTION ROLLBACK +}; + +function getTriggerEventType(triggerType) { + return eventMap[triggerType]?.eventType || null; +} + +function getTriggerTiming(triggerType) { + return eventMap[triggerType]?.triggerTiming || null; +} + module.exports = { getDataTypeString, + getTriggerEventType, + getTriggerTiming, }; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/index.js b/plugins/dbgate-plugin-firebird/src/backend/sql/index.js index 5b56564ce..f31c83640 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/index.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/index.js @@ -1,9 +1,11 @@ const version = require('./version'); const tables = require('./tables'); const columns = require('./columns'); +const triggers = require('./triggers'); module.exports = { version, columns, tables, + triggers, }; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/triggers.js b/plugins/dbgate-plugin-firebird/src/backend/sql/triggers.js new file mode 100644 index 000000000..2f49b62d9 --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/triggers.js @@ -0,0 +1,12 @@ +module.exports = ` +SELECT + TRIM(rtr.RDB$TRIGGER_NAME) as PURENAME, + TRIM(rtr.RDB$RELATION_NAME) as TABLENAME, + rtr.RDB$TRIGGER_TYPE as TRIGGERTYPE, + TRIM(rel.RDB$OWNER_NAME) AS SCHEMANAME +FROM + RDB$TRIGGERS rtr +JOIN RDB$RELATIONS rel ON rtr.RDB$RELATION_NAME = rel.RDB$RELATION_NAME +WHERE rtr.RDB$SYSTEM_FLAG = 0 +ORDER BY rtr.RDB$TRIGGER_NAME +`; From 85f7011e0332db98b1f0e56cad617844d9e933c2 Mon Sep 17 00:00:00 2001 From: Nybkox Date: Tue, 13 May 2025 17:18:17 +0200 Subject: [PATCH 05/65] fix: remove empty getFastSnapshot --- plugins/dbgate-plugin-firebird/src/backend/Analyser.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js index 5b3fdac48..a6f9172c1 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js @@ -55,10 +55,6 @@ class Analyser extends DatabaseAnalyser { triggers, }; } - - async _getFastSnapshot() { - return this._runAnalysis(); - } } module.exports = Analyser; From 3e0f834796d6991a387291b1c8d851f58229c814 Mon Sep 17 00:00:00 2001 From: Nybkox Date: Tue, 13 May 2025 19:40:51 +0200 Subject: [PATCH 06/65] feat: firebird FKs, PKs, procedures, funcs --- .../src/backend/Analyser.js | 72 ++++++++++++------- .../src/backend/helpers.js | 18 ++--- .../src/backend/sql/columns.js | 28 ++++---- .../src/backend/sql/foreignKeys.js | 35 +++++++++ .../src/backend/sql/functionParameters.js | 31 ++++++++ .../src/backend/sql/functions.js | 16 +++++ .../src/backend/sql/index.js | 12 ++++ .../src/backend/sql/primaryKeys.js | 29 ++++++++ .../src/backend/sql/procedureParameters.js | 32 +++++++++ .../src/backend/sql/procedures.js | 17 +++++ .../src/backend/sql/tables.js | 10 +-- 11 files changed, 245 insertions(+), 55 deletions(-) create mode 100644 plugins/dbgate-plugin-firebird/src/backend/sql/foreignKeys.js create mode 100644 plugins/dbgate-plugin-firebird/src/backend/sql/functionParameters.js create mode 100644 plugins/dbgate-plugin-firebird/src/backend/sql/functions.js create mode 100644 plugins/dbgate-plugin-firebird/src/backend/sql/primaryKeys.js create mode 100644 plugins/dbgate-plugin-firebird/src/backend/sql/procedureParameters.js create mode 100644 plugins/dbgate-plugin-firebird/src/backend/sql/procedures.js diff --git a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js index a6f9172c1..915af42a6 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js @@ -13,31 +13,19 @@ class Analyser extends DatabaseAnalyser { const tablesResult = await this.driver.query(this.dbhan, sql.tables); const columnsResult = await this.driver.query(this.dbhan, sql.columns); const triggersResult = await this.driver.query(this.dbhan, sql.triggers); + const primaryKeysResult = await this.driver.query(this.dbhan, sql.primaryKeys); + const foreignKeysResult = await this.driver.query(this.dbhan, sql.foreignKeys); + const functionsResults = await this.driver.query(this.dbhan, sql.functions); + const functionParametersResults = await this.driver.query(this.dbhan, sql.functionParameters); + const proceduresResults = await this.driver.query(this.dbhan, sql.procedures); + const procedureParametersResults = await this.driver.query(this.dbhan, sql.procedureParameters); - const columns = columnsResult.rows.map(i => ({ - tableName: i.TABLENAME, - columnName: i.COLUMNNAME, - notNull: i.NOTNULL, - isPrimaryKey: i.ISPRIMARYKEY, - dataType: getDataTypeString(i), - precision: i.NUMBERPRECISION, - scale: i.SCALE, - length: i.LENGTH, - defaultValue: i.DEFAULTVALUE, - columnComment: i.COLUMNCOMMENT, - isUnsigned: i.ISUNSIGNED, - pureName: i.PURENAME, - schemaName: i.SCHEMANAME, + const columns = columnsResult.rows?.map(column => ({ + ...column, + dataType: getDataTypeString(column), })); - const tables = tablesResult.rows.map(i => ({ - pureName: i.PURENAME, - objectId: i.OBJECTID, - schemaName: i.SCHEMANAME, - objectComment: i.OBJECTCOMMENT, - })); - - const triggers = triggersResult.rows.map(i => ({ + const triggers = triggersResult.rows?.map(i => ({ pureName: i.PURENAME, tableName: i.TABLENAME, shcemaName: i.SCHEMANAME, @@ -45,14 +33,48 @@ class Analyser extends DatabaseAnalyser { triggerTiming: getTriggerTiming(i.TRIGGERTYPE), })); - return { - tables: tables.map(table => ({ + const primaryKeys = primaryKeysResult.rows ?? []; + + const foreignKeys = foreignKeysResult.rows ?? []; + + const functions = functionsResults.rows?.map(func => ({ + ...func, + returnType: functionParametersResults.rows?.filter( + param => param.owningObjectName === func.pureName && param.parameterMode === 'RETURN' + )?.dataType, + parameters: functionParametersResults.rows + ?.filter(param => param.owningObjectName === func.pureName) + .map(param => ({ + ...param, + dataType: getDataTypeString(param), + })), + })); + + const procedures = proceduresResults.rows.map(proc => ({ + ...proc, + parameters: procedureParametersResults.rows + ?.filter(param => param.owningObjectName === proc.pureName) + .map(param => ({ + ...param, + dataType: getDataTypeString(param), + })), + })); + + const tables = + tablesResult.rows?.map(table => ({ ...table, columns: columns.filter( column => column.tableName === table.pureName && column.schemaName === table.schemaName ), - })), + primaryKey: DatabaseAnalyser.extractPrimaryKeys(table, primaryKeys), + foreignKeys: DatabaseAnalyser.extractForeignKeys(table, foreignKeys), + })) ?? []; + + return { + tables, triggers, + functions, + procedures, }; } } diff --git a/plugins/dbgate-plugin-firebird/src/backend/helpers.js b/plugins/dbgate-plugin-firebird/src/backend/helpers.js index 868296713..2eecf501d 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/helpers.js +++ b/plugins/dbgate-plugin-firebird/src/backend/helpers.js @@ -1,10 +1,5 @@ -function getDataTypeString(column) { - if (!column) { - return null; - } - const { DATATYPECODE, SCALE, LENGTH, NUMBERPRECISION } = column; - - switch (DATATYPECODE) { +function getDataTypeString({ dataTypeCode, scale, length, precision }) { + switch (dataTypeCode) { case 7: return 'SMALLINT'; @@ -27,10 +22,10 @@ function getDataTypeString(column) { return 'TIME'; case 14: - return `CHAR(${LENGTH})`; + return `CHAR(${length})`; case 16: - return `DECIMAL(${NUMBERPRECISION}, ${SCALE})`; + return `DECIMAL(${precision}, ${scale})`; case 27: return 'DOUBLE PRECISION'; @@ -39,13 +34,14 @@ function getDataTypeString(column) { return 'BLOB'; case 37: - return `VARCHAR(${LENGTH})`; + return `VARCHAR(${length})`; case 261: return 'CSTRING'; default: - return `UNKNOWN (${DATATYPECODE})`; + if (dataTypeCode === null || dataTypeCode === undefined) return 'UNKNOWN'; + return `UNKNOWN (${dataTypeCode})`; } } diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js index 8096ad9b8..ea8804134 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js @@ -1,8 +1,8 @@ module.exports = ` SELECT DISTINCT - CAST(TRIM(rf.rdb$relation_name) AS VARCHAR(255)) AS tableName, - CAST(TRIM(rf.rdb$field_name) AS VARCHAR(255)) AS columnName, - CASE rf.rdb$null_flag WHEN 1 THEN FALSE ELSE TRUE END AS notNull, + CAST(TRIM(rf.rdb$relation_name) AS VARCHAR(255)) AS "tableName", + CAST(TRIM(rf.rdb$field_name) AS VARCHAR(255)) AS "columnName", + CASE rf.rdb$null_flag WHEN 1 THEN FALSE ELSE TRUE END AS "notNull", CASE WHEN EXISTS ( SELECT 1 @@ -13,19 +13,19 @@ SELECT DISTINCT AND rc.rdb$constraint_type = 'PRIMARY KEY' ) THEN TRUE ELSE FALSE - END AS isPrimaryKey, - f.rdb$field_type AS dataTypeCode, - f.rdb$field_precision AS numberprecision, - f.rdb$field_scale AS scale, - f.rdb$field_length AS length, - CAST(TRIM(rf.rdb$default_value) AS VARCHAR(255)) AS defaultValue, - CAST(TRIM(rf.rdb$description) AS VARCHAR(255)) AS columnComment, + END AS "isPrimaryKey", + f.rdb$field_type AS "dataTypeCode", + f.rdb$field_precision AS "precision", + f.rdb$field_scale AS "scale", + f.rdb$field_length AS "length", + CAST(TRIM(rf.rdb$default_value) AS VARCHAR(255)) AS "defaultValue", + CAST(TRIM(rf.rdb$description) AS VARCHAR(255)) AS "columnComment", CASE WHEN f.rdb$field_type IN (8, 9, 16) AND f.rdb$field_scale < 0 THEN TRUE ELSE FALSE - END AS isUnsigned, - CAST(TRIM(rf.rdb$field_name) AS VARCHAR(255)) AS pureName, - CAST(TRIM(r.rdb$owner_name) AS VARCHAR(255)) AS schemaName + END AS "isUnsigned", + CAST(TRIM(rf.rdb$field_name) AS VARCHAR(255)) AS "pureName", + CAST(TRIM(r.rdb$owner_name) AS VARCHAR(255)) AS "schemaName" FROM rdb$relation_fields rf JOIN @@ -39,5 +39,5 @@ LEFT JOIN WHERE r.rdb$system_flag = 0 ORDER BY - tableName, rf.rdb$field_position; + "tableName", rf.rdb$field_position; `; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/foreignKeys.js b/plugins/dbgate-plugin-firebird/src/backend/sql/foreignKeys.js new file mode 100644 index 000000000..b11af75b3 --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/foreignKeys.js @@ -0,0 +1,35 @@ +module.exports = ` +SELECT + TRIM(rel.RDB$OWNER_NAME) AS "schemaName", + TRIM(rc_fk.RDB$RELATION_NAME) AS "pureName", + TRIM(rc_fk.RDB$CONSTRAINT_NAME) AS "constraintName", + TRIM(iseg_fk.RDB$FIELD_NAME) AS "columnName", + TRIM(iseg_pk.RDB$FIELD_NAME) AS "refColumnName", + TRIM(rc_pk.RDB$RELATION_NAME) AS "refTableName", + FALSE AS "isIncludedColumn", + CASE COALESCE(idx_fk.RDB$INDEX_TYPE, 0) + WHEN 1 THEN TRUE -- For the FK's own index, 1 = Descending (modern Firebird) + ELSE FALSE -- 0 or NULL = Ascending for the FK's own index + END AS "isDescending" -- Refers to the sort order of the index on the FK column(s) +FROM + RDB$RELATION_CONSTRAINTS rc_fk +JOIN + RDB$RELATIONS rel ON rc_fk.RDB$RELATION_NAME = rel.RDB$RELATION_NAME +JOIN + RDB$INDEX_SEGMENTS iseg_fk ON rc_fk.RDB$INDEX_NAME = iseg_fk.RDB$INDEX_NAME +JOIN + RDB$INDICES idx_fk ON rc_fk.RDB$INDEX_NAME = idx_fk.RDB$INDEX_NAME +JOIN + RDB$REF_CONSTRAINTS refc ON rc_fk.RDB$CONSTRAINT_NAME = refc.RDB$CONSTRAINT_NAME +JOIN + RDB$RELATION_CONSTRAINTS rc_pk ON refc.RDB$CONST_NAME_UQ = rc_pk.RDB$CONSTRAINT_NAME +JOIN + RDB$INDEX_SEGMENTS iseg_pk ON rc_pk.RDB$INDEX_NAME = iseg_pk.RDB$INDEX_NAME + AND iseg_fk.RDB$FIELD_POSITION = iseg_pk.RDB$FIELD_POSITION -- Critical for matching columns in composite keys +WHERE + rc_fk.RDB$CONSTRAINT_TYPE = 'FOREIGN KEY' +ORDER BY + "pureName", + "constraintName", + iseg_fk.RDB$FIELD_POSITION; +`; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/functionParameters.js b/plugins/dbgate-plugin-firebird/src/backend/sql/functionParameters.js new file mode 100644 index 000000000..efde85aef --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/functionParameters.js @@ -0,0 +1,31 @@ +module.exports = ` +SELECT + TRIM(F.RDB$OWNER_NAME) AS "owningObjectSchemaName", -- Schema of the function this parameter belongs to + TRIM(FA.RDB$FUNCTION_NAME) AS "owningObjectName", -- Name of the function this parameter belongs to + TRIM(FA.RDB$ARGUMENT_NAME) AS "parameterName", + FFLDS.RDB$FIELD_TYPE AS "dataTypeCode", -- SQL data type code from RDB$FIELDS + FFLDS.rdb$field_precision AS "precision", + FFLDS.rdb$field_scale AS "scale", + FFLDS.rdb$field_length AS "length", + + TRIM(CASE + WHEN FA.RDB$ARGUMENT_POSITION = F.RDB$RETURN_ARGUMENT THEN 'RETURN' + ELSE 'IN' -- For PSQL functions, non-return arguments are IN. + END) AS "parameterMode", + FA.RDB$ARGUMENT_POSITION AS "position", -- 0-based index for arguments + + -- Fields for ParameterInfo.NamedObjectInfo + TRIM(FA.RDB$FUNCTION_NAME) AS "pureName", -- NamedObjectInfo.pureName for the parameter + TRIM(F.RDB$OWNER_NAME) AS "schemaName" -- NamedObjectInfo.schemaName (owner of the function) + +FROM + RDB$FUNCTION_ARGUMENTS FA +JOIN + RDB$FUNCTIONS F ON FA.RDB$FUNCTION_NAME = F.RDB$FUNCTION_NAME +JOIN + RDB$FIELDS FFLDS ON FA.RDB$FIELD_SOURCE = FFLDS.RDB$FIELD_NAME -- Crucial join to get RDB$FIELDS.RDB$TYPE +WHERE + COALESCE(F.RDB$SYSTEM_FLAG, 0) = 0 -- Filter for user-defined functions +ORDER BY + "owningObjectSchemaName", "owningObjectName", "position"; +`; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/functions.js b/plugins/dbgate-plugin-firebird/src/backend/sql/functions.js new file mode 100644 index 000000000..4603dd8cb --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/functions.js @@ -0,0 +1,16 @@ +module.exports = ` +SELECT + TRIM(F.RDB$FUNCTION_NAME) AS "pureName", + TRIM(F.RDB$OWNER_NAME) AS "schemaName", + TRIM(F.RDB$FUNCTION_NAME) AS "objectId", + TRIM('FUNCTION') AS "objectTypeField", + TRIM(F.RDB$DESCRIPTION) AS "objectComment", + F.RDB$FUNCTION_SOURCE AS "createSql", -- This is the PSQL body or definition for UDRs + FALSE AS "requiresFormat" -- Assuming PSQL source is generally readable +FROM + RDB$FUNCTIONS F +WHERE + COALESCE(F.RDB$SYSTEM_FLAG, 0) = 0 -- User-defined functions +ORDER BY + "schemaName", "pureName"; +`; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/index.js b/plugins/dbgate-plugin-firebird/src/backend/sql/index.js index f31c83640..a253c99a2 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/index.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/index.js @@ -2,10 +2,22 @@ const version = require('./version'); const tables = require('./tables'); const columns = require('./columns'); const triggers = require('./triggers'); +const primaryKeys = require('./primaryKeys'); +const foreignKeys = require('./foreignKeys'); +const functions = require('./functions'); +const functionParameters = require('./functionParameters'); +const procedures = require('./procedures'); +const procedureParameters = require('./procedureParameters'); module.exports = { version, columns, tables, triggers, + primaryKeys, + foreignKeys, + functions, + functionParameters, + procedures, + procedureParameters, }; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/primaryKeys.js b/plugins/dbgate-plugin-firebird/src/backend/sql/primaryKeys.js new file mode 100644 index 000000000..c73cad3d3 --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/primaryKeys.js @@ -0,0 +1,29 @@ +module.exports = ` +SELECT + TRIM(rel.RDB$OWNER_NAME) AS "schemaName", + TRIM(rc.RDB$RELATION_NAME) AS "pureName", + TRIM(rc.RDB$CONSTRAINT_NAME) AS "constraintName", + TRIM(iseg.RDB$FIELD_NAME) AS "columnName", + CAST(NULL AS VARCHAR(63)) AS "refColumnName", + FALSE AS "isIncludedColumn", + CASE COALESCE(idx.RDB$INDEX_TYPE, 0) -- Treat NULL as 0 (ascending) + WHEN 1 THEN TRUE -- Assuming 1 means DESCENDING for regular (non-expression) indexes + ELSE FALSE -- Assuming 0 (or NULL) means ASCENDING for regular indexes + END AS "isDescending" +FROM + RDB$RELATION_CONSTRAINTS rc +JOIN + RDB$RELATIONS rel ON rc.RDB$RELATION_NAME = rel.RDB$RELATION_NAME +JOIN + RDB$INDICES idx ON rc.RDB$INDEX_NAME = idx.RDB$INDEX_NAME +JOIN + RDB$INDEX_SEGMENTS iseg ON idx.RDB$INDEX_NAME = iseg.RDB$INDEX_NAME +WHERE + rc.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' + AND COALESCE(rel.RDB$SYSTEM_FLAG, 0) = 0 -- Typically, you only want user-defined tables +ORDER BY + "schemaName", + "pureName", + "constraintName", + iseg.RDB$FIELD_POSITION; +`; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/procedureParameters.js b/plugins/dbgate-plugin-firebird/src/backend/sql/procedureParameters.js new file mode 100644 index 000000000..de7a3e95b --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/procedureParameters.js @@ -0,0 +1,32 @@ +module.exports = ` +SELECT + TRIM(P.RDB$OWNER_NAME) AS "owningObjectSchemaName", -- Schema of the procedure this parameter belongs to + TRIM(PP.RDB$PROCEDURE_NAME) AS "owningObjectName", -- Name of the procedure this parameter belongs to + TRIM(PP.RDB$PARAMETER_NAME) AS "parameterName", -- ParameterInfo.parameterName + FFLDS.RDB$FIELD_TYPE AS "dataTypeCode", -- SQL data type code from RDB$FIELDS + FFLDS.rdb$field_precision AS "precision", + FFLDS.rdb$field_scale AS "scale", + FFLDS.rdb$field_length AS "length", + + CASE PP.RDB$PARAMETER_TYPE + WHEN 0 THEN 'IN' + WHEN 1 THEN 'OUT' + ELSE CAST(PP.RDB$PARAMETER_TYPE AS VARCHAR(10)) -- Should ideally not happen for valid params + END AS "parameterMode", + PP.RDB$PARAMETER_NUMBER AS "position", -- 0-based for IN params, then 0-based for OUT params + + -- Fields for ParameterInfo.NamedObjectInfo + TRIM(PP.RDB$PARAMETER_NAME) AS "pureName", -- NamedObjectInfo.pureName for the parameter + TRIM(P.RDB$OWNER_NAME) AS "schemaName" -- NamedObjectInfo.schemaName (owner of the procedure) + +FROM + RDB$PROCEDURE_PARAMETERS PP +JOIN + RDB$PROCEDURES P ON PP.RDB$PROCEDURE_NAME = P.RDB$PROCEDURE_NAME +JOIN + RDB$FIELDS FFLDS ON PP.RDB$FIELD_SOURCE = FFLDS.RDB$FIELD_NAME -- Links parameter to its base field type +WHERE + COALESCE(P.RDB$SYSTEM_FLAG, 0) = 0 -- Filter for user-defined procedures +ORDER BY + "owningObjectSchemaName", "owningObjectName", PP.RDB$PARAMETER_TYPE, "position"; -- Order by IN(0)/OUT(1) then by position +`; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/procedures.js b/plugins/dbgate-plugin-firebird/src/backend/sql/procedures.js new file mode 100644 index 000000000..16da59b34 --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/procedures.js @@ -0,0 +1,17 @@ +module.exports = ` +SELECT + TRIM(P.RDB$PROCEDURE_NAME) AS "pureName", + TRIM(P.RDB$OWNER_NAME) AS "schemaName", + TRIM(P.RDB$PROCEDURE_NAME) AS "objectId", -- Using procedure name as a practical objectId + TRIM('PROCEDURE') AS "objectTypeField", + TRIM(P.RDB$DESCRIPTION) AS "objectComment", + P.RDB$PROCEDURE_SOURCE AS "createSql", -- Contains the PSQL body + FALSE AS "requiresFormat" +FROM + RDB$PROCEDURES P +WHERE + COALESCE(P.RDB$SYSTEM_FLAG, 0) = 0 -- Filter for user-defined procedures + AND P.RDB$PROCEDURE_TYPE IS NOT NULL -- Ensure it's a valid procedure type (0, 1, or 2) +ORDER BY + "schemaName", "pureName"; +`; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js b/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js index ac9f2d533..25876ca33 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js @@ -1,10 +1,10 @@ module.exports = ` SELECT - TRIM(RDB$RELATION_NAME) AS pureName, - RDB$DESCRIPTION AS objectComment, - RDB$FORMAT AS objectTypeField, - RDB$OWNER_NAME AS schemaName + TRIM(RDB$RELATION_NAME) AS "pureName", + RDB$DESCRIPTION AS "objectComment", + RDB$FORMAT AS "objectTypeField", + TRIM(RDB$OWNER_NAME) AS "schemaName" FROM RDB$RELATIONS WHERE RDB$SYSTEM_FLAG = 0 -- only user-defined tables -ORDER BY pureName; +ORDER BY "pureName"; `; From 06055a7c4ca54552d94d6e01e6deec216977ec02 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 15 May 2025 13:22:01 +0200 Subject: [PATCH 07/65] fix: remove schema from firebird --- plugins/dbgate-plugin-firebird/src/backend/Analyser.js | 8 ++------ .../dbgate-plugin-firebird/src/backend/sql/foreignKeys.js | 1 - .../src/backend/sql/functionParameters.js | 6 ++---- .../dbgate-plugin-firebird/src/backend/sql/functions.js | 3 +-- .../dbgate-plugin-firebird/src/backend/sql/primaryKeys.js | 2 -- .../src/backend/sql/procedureParameters.js | 6 ++---- .../dbgate-plugin-firebird/src/backend/sql/procedures.js | 3 +-- plugins/dbgate-plugin-firebird/src/backend/sql/tables.js | 3 +-- .../dbgate-plugin-firebird/src/backend/sql/triggers.js | 7 +++---- plugins/dbgate-plugin-firebird/src/frontend/driver.js | 6 ++++-- 10 files changed, 16 insertions(+), 29 deletions(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js index 915af42a6..ebfd8ffb7 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js @@ -26,9 +26,7 @@ class Analyser extends DatabaseAnalyser { })); const triggers = triggersResult.rows?.map(i => ({ - pureName: i.PURENAME, - tableName: i.TABLENAME, - shcemaName: i.SCHEMANAME, + ...i, eventType: getTriggerEventType(i.TRIGGERTYPE), triggerTiming: getTriggerTiming(i.TRIGGERTYPE), })); @@ -63,9 +61,7 @@ class Analyser extends DatabaseAnalyser { const tables = tablesResult.rows?.map(table => ({ ...table, - columns: columns.filter( - column => column.tableName === table.pureName && column.schemaName === table.schemaName - ), + columns: columns.filter(column => column.tableName === table.pureName), primaryKey: DatabaseAnalyser.extractPrimaryKeys(table, primaryKeys), foreignKeys: DatabaseAnalyser.extractForeignKeys(table, foreignKeys), })) ?? []; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/foreignKeys.js b/plugins/dbgate-plugin-firebird/src/backend/sql/foreignKeys.js index b11af75b3..b8fd22d3e 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/foreignKeys.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/foreignKeys.js @@ -1,6 +1,5 @@ module.exports = ` SELECT - TRIM(rel.RDB$OWNER_NAME) AS "schemaName", TRIM(rc_fk.RDB$RELATION_NAME) AS "pureName", TRIM(rc_fk.RDB$CONSTRAINT_NAME) AS "constraintName", TRIM(iseg_fk.RDB$FIELD_NAME) AS "columnName", diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/functionParameters.js b/plugins/dbgate-plugin-firebird/src/backend/sql/functionParameters.js index efde85aef..75f5a7243 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/functionParameters.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/functionParameters.js @@ -1,6 +1,5 @@ module.exports = ` SELECT - TRIM(F.RDB$OWNER_NAME) AS "owningObjectSchemaName", -- Schema of the function this parameter belongs to TRIM(FA.RDB$FUNCTION_NAME) AS "owningObjectName", -- Name of the function this parameter belongs to TRIM(FA.RDB$ARGUMENT_NAME) AS "parameterName", FFLDS.RDB$FIELD_TYPE AS "dataTypeCode", -- SQL data type code from RDB$FIELDS @@ -15,8 +14,7 @@ SELECT FA.RDB$ARGUMENT_POSITION AS "position", -- 0-based index for arguments -- Fields for ParameterInfo.NamedObjectInfo - TRIM(FA.RDB$FUNCTION_NAME) AS "pureName", -- NamedObjectInfo.pureName for the parameter - TRIM(F.RDB$OWNER_NAME) AS "schemaName" -- NamedObjectInfo.schemaName (owner of the function) + TRIM(FA.RDB$FUNCTION_NAME) AS "pureName" -- NamedObjectInfo.pureName for the parameter FROM RDB$FUNCTION_ARGUMENTS FA @@ -27,5 +25,5 @@ JOIN WHERE COALESCE(F.RDB$SYSTEM_FLAG, 0) = 0 -- Filter for user-defined functions ORDER BY - "owningObjectSchemaName", "owningObjectName", "position"; + "owningObjectName", "position"; `; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/functions.js b/plugins/dbgate-plugin-firebird/src/backend/sql/functions.js index 4603dd8cb..694200960 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/functions.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/functions.js @@ -1,7 +1,6 @@ module.exports = ` SELECT TRIM(F.RDB$FUNCTION_NAME) AS "pureName", - TRIM(F.RDB$OWNER_NAME) AS "schemaName", TRIM(F.RDB$FUNCTION_NAME) AS "objectId", TRIM('FUNCTION') AS "objectTypeField", TRIM(F.RDB$DESCRIPTION) AS "objectComment", @@ -12,5 +11,5 @@ FROM WHERE COALESCE(F.RDB$SYSTEM_FLAG, 0) = 0 -- User-defined functions ORDER BY - "schemaName", "pureName"; + "pureName"; `; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/primaryKeys.js b/plugins/dbgate-plugin-firebird/src/backend/sql/primaryKeys.js index c73cad3d3..50a5abe09 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/primaryKeys.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/primaryKeys.js @@ -1,6 +1,5 @@ module.exports = ` SELECT - TRIM(rel.RDB$OWNER_NAME) AS "schemaName", TRIM(rc.RDB$RELATION_NAME) AS "pureName", TRIM(rc.RDB$CONSTRAINT_NAME) AS "constraintName", TRIM(iseg.RDB$FIELD_NAME) AS "columnName", @@ -22,7 +21,6 @@ WHERE rc.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' AND COALESCE(rel.RDB$SYSTEM_FLAG, 0) = 0 -- Typically, you only want user-defined tables ORDER BY - "schemaName", "pureName", "constraintName", iseg.RDB$FIELD_POSITION; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/procedureParameters.js b/plugins/dbgate-plugin-firebird/src/backend/sql/procedureParameters.js index de7a3e95b..33b0e63b9 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/procedureParameters.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/procedureParameters.js @@ -1,6 +1,5 @@ module.exports = ` SELECT - TRIM(P.RDB$OWNER_NAME) AS "owningObjectSchemaName", -- Schema of the procedure this parameter belongs to TRIM(PP.RDB$PROCEDURE_NAME) AS "owningObjectName", -- Name of the procedure this parameter belongs to TRIM(PP.RDB$PARAMETER_NAME) AS "parameterName", -- ParameterInfo.parameterName FFLDS.RDB$FIELD_TYPE AS "dataTypeCode", -- SQL data type code from RDB$FIELDS @@ -16,8 +15,7 @@ SELECT PP.RDB$PARAMETER_NUMBER AS "position", -- 0-based for IN params, then 0-based for OUT params -- Fields for ParameterInfo.NamedObjectInfo - TRIM(PP.RDB$PARAMETER_NAME) AS "pureName", -- NamedObjectInfo.pureName for the parameter - TRIM(P.RDB$OWNER_NAME) AS "schemaName" -- NamedObjectInfo.schemaName (owner of the procedure) + TRIM(PP.RDB$PARAMETER_NAME) AS "pureName" -- NamedObjectInfo.pureName for the parameter FROM RDB$PROCEDURE_PARAMETERS PP @@ -28,5 +26,5 @@ JOIN WHERE COALESCE(P.RDB$SYSTEM_FLAG, 0) = 0 -- Filter for user-defined procedures ORDER BY - "owningObjectSchemaName", "owningObjectName", PP.RDB$PARAMETER_TYPE, "position"; -- Order by IN(0)/OUT(1) then by position + "owningObjectName", PP.RDB$PARAMETER_TYPE, "position"; -- Order by IN(0)/OUT(1) then by position `; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/procedures.js b/plugins/dbgate-plugin-firebird/src/backend/sql/procedures.js index 16da59b34..7816d50d7 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/procedures.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/procedures.js @@ -1,7 +1,6 @@ module.exports = ` SELECT TRIM(P.RDB$PROCEDURE_NAME) AS "pureName", - TRIM(P.RDB$OWNER_NAME) AS "schemaName", TRIM(P.RDB$PROCEDURE_NAME) AS "objectId", -- Using procedure name as a practical objectId TRIM('PROCEDURE') AS "objectTypeField", TRIM(P.RDB$DESCRIPTION) AS "objectComment", @@ -13,5 +12,5 @@ WHERE COALESCE(P.RDB$SYSTEM_FLAG, 0) = 0 -- Filter for user-defined procedures AND P.RDB$PROCEDURE_TYPE IS NOT NULL -- Ensure it's a valid procedure type (0, 1, or 2) ORDER BY - "schemaName", "pureName"; + "pureName"; `; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js b/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js index 25876ca33..0f4d20538 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js @@ -2,8 +2,7 @@ module.exports = ` SELECT TRIM(RDB$RELATION_NAME) AS "pureName", RDB$DESCRIPTION AS "objectComment", - RDB$FORMAT AS "objectTypeField", - TRIM(RDB$OWNER_NAME) AS "schemaName" + RDB$FORMAT AS "objectTypeField" FROM RDB$RELATIONS WHERE RDB$SYSTEM_FLAG = 0 -- only user-defined tables ORDER BY "pureName"; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/triggers.js b/plugins/dbgate-plugin-firebird/src/backend/sql/triggers.js index 2f49b62d9..6e1a622b2 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/triggers.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/triggers.js @@ -1,9 +1,8 @@ module.exports = ` SELECT - TRIM(rtr.RDB$TRIGGER_NAME) as PURENAME, - TRIM(rtr.RDB$RELATION_NAME) as TABLENAME, - rtr.RDB$TRIGGER_TYPE as TRIGGERTYPE, - TRIM(rel.RDB$OWNER_NAME) AS SCHEMANAME + TRIM(rtr.RDB$TRIGGER_NAME) as "pureName", + TRIM(rtr.RDB$RELATION_NAME) as "tableName", + rtr.RDB$TRIGGER_TYPE as TRIGGERTYPE FROM RDB$TRIGGERS rtr JOIN RDB$RELATIONS rel ON rtr.RDB$RELATION_NAME = rel.RDB$RELATION_NAME diff --git a/plugins/dbgate-plugin-firebird/src/frontend/driver.js b/plugins/dbgate-plugin-firebird/src/frontend/driver.js index fa0ef8d1f..c4118e175 100644 --- a/plugins/dbgate-plugin-firebird/src/frontend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/frontend/driver.js @@ -5,13 +5,15 @@ const Dumper = require('./Dumper'); const dialect = { rangeSelect: true, ilike: true, - defaultSchemaName: 'public', - multipleSchema: true, + multipleSchema: false, stringEscapeChar: "'", fallbackDataType: 'varchar', anonymousPrimaryKey: false, enableConstraintsPerTable: true, stringAgg: true, + quoteIdentifier(s) { + return `"${s}"`; + }, createColumn: true, dropColumn: true, From 7ac6cfcf2503d8f027ee3dfd0db01b1ffdd81d1a Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 15 May 2025 13:32:07 +0200 Subject: [PATCH 08/65] feat: offsetFirstSkipRangeSyntax support --- packages/sqltree/src/dumpSqlCommand.ts | 5 +++++ packages/types/dialect.d.ts | 1 + plugins/dbgate-plugin-firebird/src/frontend/driver.js | 2 ++ 3 files changed, 8 insertions(+) diff --git a/packages/sqltree/src/dumpSqlCommand.ts b/packages/sqltree/src/dumpSqlCommand.ts index 4122ea3f8..e8286bafb 100644 --- a/packages/sqltree/src/dumpSqlCommand.ts +++ b/packages/sqltree/src/dumpSqlCommand.ts @@ -12,6 +12,9 @@ export function dumpSqlSelect(dmp: SqlDumper, cmd: Select) { if (cmd.topRecords) { if (!dmp.dialect.rangeSelect || dmp.dialect.offsetFetchRangeSyntax) dmp.put('^top %s ', cmd.topRecords); } + if (cmd.range && dmp.dialect.offsetFirstSkipSyntax) { + dmp.put('^first %s ^skip %s ', cmd.range.limit, cmd.range.offset); + } if (cmd.selectAll) { dmp.put('* '); } @@ -52,6 +55,8 @@ export function dumpSqlSelect(dmp: SqlDumper, cmd: Select) { if (cmd.range) { if (dmp.dialect.offsetFetchRangeSyntax) { dmp.put('^offset %s ^rows ^fetch ^next %s ^rows ^only', cmd.range.offset, cmd.range.limit); + } else if (dmp.dialect.offsetFirstSkipSyntax) { + // } else if (dmp.dialect.offsetNotSupported) { dmp.put('^limit %s', cmd.range.limit + cmd.range.offset); } else { diff --git a/packages/types/dialect.d.ts b/packages/types/dialect.d.ts index 4e772be8e..53baf4a0b 100644 --- a/packages/types/dialect.d.ts +++ b/packages/types/dialect.d.ts @@ -8,6 +8,7 @@ export interface SqlDialect { topRecords?: boolean; stringEscapeChar: string; offsetFetchRangeSyntax?: boolean; + offsetFirstSkipSyntax?: boolean; offsetNotSupported?: boolean; quoteIdentifier(s: string): string; fallbackDataType?: string; diff --git a/plugins/dbgate-plugin-firebird/src/frontend/driver.js b/plugins/dbgate-plugin-firebird/src/frontend/driver.js index c4118e175..69d729dae 100644 --- a/plugins/dbgate-plugin-firebird/src/frontend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/frontend/driver.js @@ -11,6 +11,8 @@ const dialect = { anonymousPrimaryKey: false, enableConstraintsPerTable: true, stringAgg: true, + offsetFirstSkipSyntax: true, + quoteIdentifier(s) { return `"${s}"`; }, From 951bfa23f3f0e336cafe1f45cf8bfef47334e8fc Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 15 May 2025 15:04:54 +0200 Subject: [PATCH 09/65] feat: firebird use attachOrCreate on connect, add dbFileExtension and locaiton on server to tests --- integration-tests/tools.js | 9 +++- packages/tools/src/SqlDumper.ts | 4 +- packages/types/dialect.d.ts | 2 + packages/types/test-engines.d.ts | 2 + .../src/backend/driver.js | 46 ++++++++++++++----- .../src/frontend/Dumper.js | 6 ++- .../src/frontend/driver.js | 2 + 7 files changed, 54 insertions(+), 17 deletions(-) diff --git a/integration-tests/tools.js b/integration-tests/tools.js index 7b13a2657..0a8b3e2b2 100644 --- a/integration-tests/tools.js +++ b/integration-tests/tools.js @@ -5,7 +5,12 @@ const crypto = require('crypto'); function randomDbName(dialect) { const generatedKey = crypto.randomBytes(6); const newKey = generatedKey.toString('hex'); - const res = `db${newKey}`; + let res = `db${newKey}`; + + if (dialect.dbFileExtension) { + res += dialect.dbFileExtension; + } + if (dialect.upperCaseAllDbObjectNames) return res.toUpperCase(); return res; } @@ -17,7 +22,7 @@ async function connect(engine, database) { if (engine.generateDbFile) { const conn = await driver.connect({ ...connection, - databaseFile: `dbtemp/${database}`, + databaseFile: (engine.databaseFileLocationOnServer ?? 'dbtemp/') + database, }); return conn; } else { diff --git a/packages/tools/src/SqlDumper.ts b/packages/tools/src/SqlDumper.ts index 371fb75fe..ce8c36a9f 100644 --- a/packages/tools/src/SqlDumper.ts +++ b/packages/tools/src/SqlDumper.ts @@ -265,11 +265,11 @@ export class SqlDumper implements AlterProcessor { this.columnDefault(column); } if (includeNullable && !this.dialect?.specificNullabilityImplementation) { - this.put(column.notNull ? '^not ^null' : '^null'); + this.put(column.notNull ? '^not ^null' : this.dialect.implicitNullDeclaration ? '^null' : ''); } } else { if (includeNullable && !this.dialect?.specificNullabilityImplementation) { - this.put(column.notNull ? '^not ^null' : '^null'); + this.put(column.notNull ? '^not ^null' : this.dialect.implicitNullDeclaration ? '^null' : ''); } if (includeDefault && column.defaultValue?.toString()?.trim()) { this.columnDefault(column); diff --git a/packages/types/dialect.d.ts b/packages/types/dialect.d.ts index 53baf4a0b..19a25a02f 100644 --- a/packages/types/dialect.d.ts +++ b/packages/types/dialect.d.ts @@ -48,6 +48,7 @@ export interface SqlDialect { namedDefaultConstraint?: boolean; specificNullabilityImplementation?: boolean; + implicitNullDeclaration?: boolean; omitForeignKeys?: boolean; omitUniqueConstraints?: boolean; omitIndexes?: boolean; @@ -67,6 +68,7 @@ export interface SqlDialect { requireFromDual?: boolean; userDatabaseNamePrefix?: string; // c## in Oracle upperCaseAllDbObjectNames?: boolean; + dbFileExtension?: string; defaultValueBeforeNullability?: boolean; predefinedDataTypes: string[]; diff --git a/packages/types/test-engines.d.ts b/packages/types/test-engines.d.ts index 9cea205c4..271c38bb6 100644 --- a/packages/types/test-engines.d.ts +++ b/packages/types/test-engines.d.ts @@ -60,6 +60,8 @@ export type TestEngineInfo = { defaultSchemaName?: string; generateDbFile?: boolean; + generateDbFileOnServer?: boolean; + databaseFileLocationOnServer?: string; dbSnapshotBySeconds?: boolean; dumpFile?: string; dumpChecks?: Array<{ sql: string; res: string }>; diff --git a/plugins/dbgate-plugin-firebird/src/backend/driver.js b/plugins/dbgate-plugin-firebird/src/backend/driver.js index 5c04830b0..be411482c 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/backend/driver.js @@ -1,4 +1,5 @@ const _ = require('lodash'); +const stream = require('stream'); const driverBase = require('../frontend/driver'); const Analyser = require('./Analyser'); const Firebird = require('node-firebird'); @@ -22,7 +23,7 @@ const driver = { /**@type {Firebird.Database} */ const db = await new Promise((resolve, reject) => { - Firebird.attach(options, (err, db) => { + Firebird.attachOrCreate(options, (err, db) => { if (err) { reject(err); return; @@ -47,18 +48,14 @@ const driver = { resolve(result); }); }); - const columns = res[0] ? Object.keys(res[0]).map(i => ({ columnName: i })) : []; + const columns = res?.[0] ? Object.keys(res[0]).map(i => ({ columnName: i })) : []; return { - rows: res, + rows: res ?? [], columns, }; }, - async script(dbhan, sql) { - throw new Error('Not implemented'); - }, - async stream(dbhan, sql, options) { try { await new Promise((resolve, reject) => { @@ -101,7 +98,36 @@ const driver = { }, async readQuery(dbhan, sql, structure) { - throw new Error('Not implemented'); + console.log('readQuery from SQL:', sql); + const pass = new stream.PassThrough({ + objectMode: true, + highWaterMark: 100, + }); + let hasSentColumns = false; + + dbhan.client.sequentially( + sql, + [], + (row, index) => { + if (!hasSentColumns) { + hasSentColumns = true; + + const columns = Object.keys(row).map(i => ({ columnName: i })); + + pass.write({ + __isStreamHeader: true, + ...(structure || { columns }), + }); + } + + pass.write(row); + }, + err => { + pass.end(); + } + ); + + return pass; }, async writeTable(dbhan, name, options) { @@ -126,10 +152,6 @@ const driver = { ]; }, - async createDatabase(dbhan, name) {}, - - async dropDatabase(dbhan, name) {}, - async close(dbhan) { return new Promise((resolve, reject) => { dbhan.client.detach(err => { diff --git a/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js b/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js index f0df62e8f..154361d0a 100644 --- a/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js +++ b/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js @@ -1,5 +1,9 @@ const { SqlDumper } = global.DBGATE_PACKAGES['dbgate-tools']; -class Dumper extends SqlDumper {} +class Dumper extends SqlDumper { + autoIncrement() { + this.put(' ^generated ^by ^default ^as ^identity'); + } +} module.exports = Dumper; diff --git a/plugins/dbgate-plugin-firebird/src/frontend/driver.js b/plugins/dbgate-plugin-firebird/src/frontend/driver.js index 69d729dae..0212e4f04 100644 --- a/plugins/dbgate-plugin-firebird/src/frontend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/frontend/driver.js @@ -17,6 +17,8 @@ const dialect = { return `"${s}"`; }, + dbFileExtension: '.fdb', + createColumn: true, dropColumn: true, changeColumn: true, From 05aaf0de9f93975b744e18623dcb789d203509e9 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 15 May 2025 15:05:44 +0200 Subject: [PATCH 10/65] feat: add firebird to test engines --- integration-tests/engines.js | 37 +++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/integration-tests/engines.js b/integration-tests/engines.js index 51ba9705e..ab8a603a1 100644 --- a/integration-tests/engines.js +++ b/integration-tests/engines.js @@ -680,6 +680,38 @@ const duckdbEngine = { skipDropReferences: true, }; +/** @type {import('dbgate-types').TestEngineInfo} */ +const firebirdEngine = { + label: 'Firebird', + generateDbFile: true, + databaseFileLocationOnServer: '/var/lib/firebird/data/', + defaultSchemaName: 'main', + connection: { + engine: 'firebird@dbgate-plugin-firebird', + server: 'localhost', + port: 3050, + // databaseUrl: '/var/lib/firebird/data/mydatabase.fdb', + // databaseFile: '/var/lib/firebird/data/mydatabase.fdb', + user: 'SYSDBA', + password: 'masterkey', + }, + skipOnCI: false, + // skipChangeColumn: true, + // skipIndexes: true, + // skipStringLength: true, + // skipTriggers: true, + skipDataReplicator: true, + // skipAutoIncrement: true, + // skipDropColumn: true, + // skipRenameColumn: true, + // skipChangeNullability: true, + // skipDeploy: true, + // supportRenameSqlObject: true, + // skipIncrementalAnalysis: true, + // skipDefaultValue: true, + // skipDropReferences: true, +}; + const enginesOnCi = [ // all engines, which would be run on GitHub actions mysqlEngine, @@ -694,6 +726,7 @@ const enginesOnCi = [ oracleEngine, cassandraEngine, duckdbEngine, + firebirdEngine, ]; const enginesOnLocal = [ @@ -709,7 +742,8 @@ const enginesOnLocal = [ // libsqlFileEngine, // libsqlWsEngine, // oracleEngine, - duckdbEngine, + // duckdbEngine, + firebirdEngine, ]; /** @type {import('dbgate-types').TestEngineInfo[] & Record} */ @@ -727,3 +761,4 @@ module.exports.cassandraEngine = cassandraEngine; module.exports.libsqlFileEngine = libsqlFileEngine; module.exports.libsqlWsEngine = libsqlWsEngine; module.exports.duckdbEngine = duckdbEngine; +module.exports.firebirdEngine = firebirdEngine; From 2f6427af32672a4b500f8a37979819fb504911ce Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 15 May 2025 17:00:02 +0200 Subject: [PATCH 11/65] feat: set implicitNullDeclaration to true for firebird --- plugins/dbgate-plugin-firebird/src/frontend/driver.js | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/dbgate-plugin-firebird/src/frontend/driver.js b/plugins/dbgate-plugin-firebird/src/frontend/driver.js index 0212e4f04..598b9bb7b 100644 --- a/plugins/dbgate-plugin-firebird/src/frontend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/frontend/driver.js @@ -19,6 +19,7 @@ const dialect = { dbFileExtension: '.fdb', + implicitNullDeclaration: true, createColumn: true, dropColumn: true, changeColumn: true, From 2e00daf63c76af875dd42154d7a8c3c791ecae95 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 22 May 2025 15:39:46 +0200 Subject: [PATCH 12/65] fix: correct implicitNullDeclaration usage in dumper --- packages/tools/src/SqlDumper.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/tools/src/SqlDumper.ts b/packages/tools/src/SqlDumper.ts index ce8c36a9f..02080e2a6 100644 --- a/packages/tools/src/SqlDumper.ts +++ b/packages/tools/src/SqlDumper.ts @@ -265,11 +265,11 @@ export class SqlDumper implements AlterProcessor { this.columnDefault(column); } if (includeNullable && !this.dialect?.specificNullabilityImplementation) { - this.put(column.notNull ? '^not ^null' : this.dialect.implicitNullDeclaration ? '^null' : ''); + this.put(column.notNull ? '^not ^null' : this.dialect.implicitNullDeclaration ? '' : '^null'); } } else { if (includeNullable && !this.dialect?.specificNullabilityImplementation) { - this.put(column.notNull ? '^not ^null' : this.dialect.implicitNullDeclaration ? '^null' : ''); + this.put(column.notNull ? '^not ^null' : this.dialect.implicitNullDeclaration ? '' : '^null'); } if (includeDefault && column.defaultValue?.toString()?.trim()) { this.columnDefault(column); From 3a3a261d9cb2defc07d4135e0351aaa3c0a1857c Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 22 May 2025 15:40:02 +0200 Subject: [PATCH 13/65] fix: correct firedb columns notNull query --- plugins/dbgate-plugin-firebird/src/backend/sql/columns.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js index ea8804134..0f854a8ed 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js @@ -2,7 +2,7 @@ module.exports = ` SELECT DISTINCT CAST(TRIM(rf.rdb$relation_name) AS VARCHAR(255)) AS "tableName", CAST(TRIM(rf.rdb$field_name) AS VARCHAR(255)) AS "columnName", - CASE rf.rdb$null_flag WHEN 1 THEN FALSE ELSE TRUE END AS "notNull", + CASE rf.rdb$null_flag WHEN 1 THEN TRUE ELSE FALSE END AS "notNull", CASE WHEN EXISTS ( SELECT 1 From 0d8d87857c6c4a54865816e77343dc4c2e25def0 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 22 May 2025 15:40:23 +0200 Subject: [PATCH 14/65] fix: skip autoIncrement for firedb tests --- integration-tests/engines.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/engines.js b/integration-tests/engines.js index ab8a603a1..c1eaaf9bb 100644 --- a/integration-tests/engines.js +++ b/integration-tests/engines.js @@ -701,7 +701,7 @@ const firebirdEngine = { // skipStringLength: true, // skipTriggers: true, skipDataReplicator: true, - // skipAutoIncrement: true, + skipAutoIncrement: true, // skipDropColumn: true, // skipRenameColumn: true, // skipChangeNullability: true, From 8ea3f80b97f4047c74c2fb2405cd04a802ee424b Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 22 May 2025 15:40:43 +0200 Subject: [PATCH 15/65] feat: add firebird to github workflows --- .github/workflows/build-app-beta.yaml | 34 +++++++-------- .github/workflows/build-app-pro-beta.yaml | 36 ++++++++-------- .github/workflows/build-app-pro.yaml | 36 ++++++++-------- .github/workflows/build-app.yaml | 34 +++++++-------- .github/workflows/build-cloud-pro.yaml | 44 ++++++++++---------- .github/workflows/build-docker-pro.yaml | 20 ++++----- .github/workflows/build-docker.yaml | 22 +++++----- .github/workflows/build-npm-pro.yaml | 14 +++---- .github/workflows/build-npm.yaml | 12 +++--- .github/workflows/build-test-containers.yaml | 4 +- .github/workflows/diflow.yaml | 2 +- .github/workflows/e2e-pro.yaml | 16 +++---- .github/workflows/process-templates.yaml | 4 +- .github/workflows/run-tests.yaml | 28 +++++++++---- workflow-templates/run-tests.yaml | 21 ++++++++-- 15 files changed, 176 insertions(+), 151 deletions(-) diff --git a/.github/workflows/build-app-beta.yaml b/.github/workflows/build-app-beta.yaml index b238d00c0..9d10bdeda 100644 --- a/.github/workflows/build-app-beta.yaml +++ b/.github/workflows/build-app-beta.yaml @@ -5,10 +5,10 @@ name: Electron app BETA 'on': push: tags: - - v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+ + - 'v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+' jobs: build: - runs-on: ${{ matrix.os }} + runs-on: '${{ matrix.os }}' strategy: fail-fast: false matrix: @@ -24,7 +24,7 @@ jobs: echo "PYTHON=/opt/homebrew/bin/python3.11" >> $GITHUB_ENV - name: Context env: - GITHUB_CONTEXT: ${{ toJson(github) }} + GITHUB_CONTEXT: '${{ toJson(github) }}' run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -58,7 +58,7 @@ jobs: yarn printSecrets env: - GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} + GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' - name: fillPackagedPlugins run: | @@ -71,16 +71,16 @@ jobs: yarn run build:app env: - GH_TOKEN: ${{ secrets.GH_TOKEN }} - WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }} - WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }} - CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }} - CSC_KEY_PASSWORD: ${{ secrets.APPLECERT_PASSWORD }} - APPLE_ID: ${{ secrets.APPLE_ID }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} - SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} - APPLE_APP_SPECIFIC_PASSWORD: ${{secrets.APPLE_APP_SPECIFIC_PASSWORD}} + GH_TOKEN: '${{ secrets.GH_TOKEN }}' + WIN_CSC_LINK: '${{ secrets.WINCERT_2025 }}' + WIN_CSC_KEY_PASSWORD: '${{ secrets.WINCERT_2025_PASSWORD }}' + CSC_LINK: '${{ secrets.APPLECERT_CERTIFICATE }}' + CSC_KEY_PASSWORD: '${{ secrets.APPLECERT_PASSWORD }}' + APPLE_ID: '${{ secrets.APPLE_ID }}' + APPLE_TEAM_ID: '${{ secrets.APPLE_TEAM_ID }}' + APPLE_ID_PASSWORD: '${{ secrets.APPLE_ID_PASSWORD }}' + SNAPCRAFT_STORE_CREDENTIALS: '${{secrets.SNAPCRAFT_LOGIN}}' + APPLE_APP_SPECIFIC_PASSWORD: '${{secrets.APPLE_APP_SPECIFIC_PASSWORD}}' - name: Copy artifacts run: | mkdir artifacts @@ -111,16 +111,16 @@ jobs: - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: ${{ matrix.os }} + name: '${{ matrix.os }}' path: artifacts - name: Release uses: softprops/action-gh-release@v1 - if: startsWith(github.ref, 'refs/tags/') + if: 'startsWith(github.ref, ''refs/tags/'')' with: files: artifacts/** prerelease: true env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' - name: Print content of notarization-error.log if: failure() && matrix.os == 'macos-14' run: | diff --git a/.github/workflows/build-app-pro-beta.yaml b/.github/workflows/build-app-pro-beta.yaml index 219b97675..4ae4d59c1 100644 --- a/.github/workflows/build-app-pro-beta.yaml +++ b/.github/workflows/build-app-pro-beta.yaml @@ -5,10 +5,10 @@ name: Electron app PREMIUM BETA 'on': push: tags: - - v[0-9]+.[0-9]+.[0-9]+-premium-beta.[0-9]+ + - 'v[0-9]+.[0-9]+.[0-9]+-premium-beta.[0-9]+' jobs: build: - runs-on: ${{ matrix.os }} + runs-on: '${{ matrix.os }}' strategy: fail-fast: false matrix: @@ -24,7 +24,7 @@ jobs: echo "PYTHON=/opt/homebrew/bin/python3.11" >> $GITHUB_ENV - name: Context env: - GITHUB_CONTEXT: ${{ toJson(github) }} + GITHUB_CONTEXT: '${{ toJson(github) }}' run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -37,7 +37,7 @@ jobs: uses: actions/checkout@v2 with: repository: dbgate/dbgate-pro - token: ${{ secrets.GH_TOKEN }} + token: '${{ secrets.GH_TOKEN }}' path: dbgate-pro ref: 55cf42d58b843c4f1ffd6ab9b808f5f971bc3c8b - name: Merge dbgate/dbgate-pro @@ -88,7 +88,7 @@ jobs: yarn printSecrets env: - GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} + GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' - name: fillPackagedPlugins run: | cd .. @@ -102,16 +102,16 @@ jobs: yarn run build:app env: - GH_TOKEN: ${{ secrets.GH_TOKEN }} - WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }} - WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }} - CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }} - CSC_KEY_PASSWORD: ${{ secrets.APPLECERT_PASSWORD }} - APPLE_ID: ${{ secrets.APPLE_ID }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} - SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} - APPLE_APP_SPECIFIC_PASSWORD: ${{secrets.APPLE_APP_SPECIFIC_PASSWORD}} + GH_TOKEN: '${{ secrets.GH_TOKEN }}' + WIN_CSC_LINK: '${{ secrets.WINCERT_2025 }}' + WIN_CSC_KEY_PASSWORD: '${{ secrets.WINCERT_2025_PASSWORD }}' + CSC_LINK: '${{ secrets.APPLECERT_CERTIFICATE }}' + CSC_KEY_PASSWORD: '${{ secrets.APPLECERT_PASSWORD }}' + APPLE_ID: '${{ secrets.APPLE_ID }}' + APPLE_TEAM_ID: '${{ secrets.APPLE_TEAM_ID }}' + APPLE_ID_PASSWORD: '${{ secrets.APPLE_ID_PASSWORD }}' + SNAPCRAFT_STORE_CREDENTIALS: '${{secrets.SNAPCRAFT_LOGIN}}' + APPLE_APP_SPECIFIC_PASSWORD: '${{secrets.APPLE_APP_SPECIFIC_PASSWORD}}' - name: Copy artifacts run: | mkdir artifacts @@ -142,16 +142,16 @@ jobs: - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: ${{ matrix.os }} + name: '${{ matrix.os }}' path: artifacts - name: Release uses: softprops/action-gh-release@v1 - if: startsWith(github.ref, 'refs/tags/') + if: 'startsWith(github.ref, ''refs/tags/'')' with: files: artifacts/** prerelease: true env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' - name: Print content of notarization-error.log if: failure() && matrix.os == 'macos-14' run: | diff --git a/.github/workflows/build-app-pro.yaml b/.github/workflows/build-app-pro.yaml index dfeac852d..aa41c0652 100644 --- a/.github/workflows/build-app-pro.yaml +++ b/.github/workflows/build-app-pro.yaml @@ -5,10 +5,10 @@ name: Electron app PREMIUM 'on': push: tags: - - v[0-9]+.[0-9]+.[0-9]+ + - 'v[0-9]+.[0-9]+.[0-9]+' jobs: build: - runs-on: ${{ matrix.os }} + runs-on: '${{ matrix.os }}' strategy: fail-fast: false matrix: @@ -24,7 +24,7 @@ jobs: echo "PYTHON=/opt/homebrew/bin/python3.11" >> $GITHUB_ENV - name: Context env: - GITHUB_CONTEXT: ${{ toJson(github) }} + GITHUB_CONTEXT: '${{ toJson(github) }}' run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -37,7 +37,7 @@ jobs: uses: actions/checkout@v2 with: repository: dbgate/dbgate-pro - token: ${{ secrets.GH_TOKEN }} + token: '${{ secrets.GH_TOKEN }}' path: dbgate-pro ref: 55cf42d58b843c4f1ffd6ab9b808f5f971bc3c8b - name: Merge dbgate/dbgate-pro @@ -88,7 +88,7 @@ jobs: yarn printSecrets env: - GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} + GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' - name: fillPackagedPlugins run: | cd .. @@ -102,16 +102,16 @@ jobs: yarn run build:app env: - GH_TOKEN: ${{ secrets.GH_TOKEN }} - WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }} - WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }} - CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }} - CSC_KEY_PASSWORD: ${{ secrets.APPLECERT_PASSWORD }} - APPLE_ID: ${{ secrets.APPLE_ID }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} - SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} - APPLE_APP_SPECIFIC_PASSWORD: ${{secrets.APPLE_APP_SPECIFIC_PASSWORD}} + GH_TOKEN: '${{ secrets.GH_TOKEN }}' + WIN_CSC_LINK: '${{ secrets.WINCERT_2025 }}' + WIN_CSC_KEY_PASSWORD: '${{ secrets.WINCERT_2025_PASSWORD }}' + CSC_LINK: '${{ secrets.APPLECERT_CERTIFICATE }}' + CSC_KEY_PASSWORD: '${{ secrets.APPLECERT_PASSWORD }}' + APPLE_ID: '${{ secrets.APPLE_ID }}' + APPLE_TEAM_ID: '${{ secrets.APPLE_TEAM_ID }}' + APPLE_ID_PASSWORD: '${{ secrets.APPLE_ID_PASSWORD }}' + SNAPCRAFT_STORE_CREDENTIALS: '${{secrets.SNAPCRAFT_LOGIN}}' + APPLE_APP_SPECIFIC_PASSWORD: '${{secrets.APPLE_APP_SPECIFIC_PASSWORD}}' - name: Copy artifacts run: | mkdir artifacts @@ -142,16 +142,16 @@ jobs: - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: ${{ matrix.os }} + name: '${{ matrix.os }}' path: artifacts - name: Release uses: softprops/action-gh-release@v1 - if: startsWith(github.ref, 'refs/tags/') + if: 'startsWith(github.ref, ''refs/tags/'')' with: files: artifacts/** prerelease: false env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' - name: Print content of notarization-error.log if: failure() && matrix.os == 'macos-14' run: | diff --git a/.github/workflows/build-app.yaml b/.github/workflows/build-app.yaml index db0785eac..bc4ae305b 100644 --- a/.github/workflows/build-app.yaml +++ b/.github/workflows/build-app.yaml @@ -5,10 +5,10 @@ name: Electron app 'on': push: tags: - - v[0-9]+.[0-9]+.[0-9]+ + - 'v[0-9]+.[0-9]+.[0-9]+' jobs: build: - runs-on: ${{ matrix.os }} + runs-on: '${{ matrix.os }}' strategy: fail-fast: false matrix: @@ -24,7 +24,7 @@ jobs: echo "PYTHON=/opt/homebrew/bin/python3.11" >> $GITHUB_ENV - name: Context env: - GITHUB_CONTEXT: ${{ toJson(github) }} + GITHUB_CONTEXT: '${{ toJson(github) }}' run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -54,7 +54,7 @@ jobs: yarn printSecrets env: - GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} + GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' - name: fillPackagedPlugins run: | @@ -67,16 +67,16 @@ jobs: yarn run build:app env: - GH_TOKEN: ${{ secrets.GH_TOKEN }} - WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }} - WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }} - CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }} - CSC_KEY_PASSWORD: ${{ secrets.APPLECERT_PASSWORD }} - APPLE_ID: ${{ secrets.APPLE_ID }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} - SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} - APPLE_APP_SPECIFIC_PASSWORD: ${{secrets.APPLE_APP_SPECIFIC_PASSWORD}} + GH_TOKEN: '${{ secrets.GH_TOKEN }}' + WIN_CSC_LINK: '${{ secrets.WINCERT_2025 }}' + WIN_CSC_KEY_PASSWORD: '${{ secrets.WINCERT_2025_PASSWORD }}' + CSC_LINK: '${{ secrets.APPLECERT_CERTIFICATE }}' + CSC_KEY_PASSWORD: '${{ secrets.APPLECERT_PASSWORD }}' + APPLE_ID: '${{ secrets.APPLE_ID }}' + APPLE_TEAM_ID: '${{ secrets.APPLE_TEAM_ID }}' + APPLE_ID_PASSWORD: '${{ secrets.APPLE_ID_PASSWORD }}' + SNAPCRAFT_STORE_CREDENTIALS: '${{secrets.SNAPCRAFT_LOGIN}}' + APPLE_APP_SPECIFIC_PASSWORD: '${{secrets.APPLE_APP_SPECIFIC_PASSWORD}}' - name: generatePadFile run: | yarn generatePadFile @@ -114,16 +114,16 @@ jobs: - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: ${{ matrix.os }} + name: '${{ matrix.os }}' path: artifacts - name: Release uses: softprops/action-gh-release@v1 - if: startsWith(github.ref, 'refs/tags/') + if: 'startsWith(github.ref, ''refs/tags/'')' with: files: artifacts/** prerelease: false env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' - name: Print content of notarization-error.log if: failure() && matrix.os == 'macos-14' run: | diff --git a/.github/workflows/build-cloud-pro.yaml b/.github/workflows/build-cloud-pro.yaml index 56f37a0f1..1908742a7 100644 --- a/.github/workflows/build-cloud-pro.yaml +++ b/.github/workflows/build-cloud-pro.yaml @@ -5,11 +5,11 @@ name: Cloud images PREMIUM 'on': push: tags: - - v[0-9]+.[0-9]+.[0-9]+ - - v[0-9]+.[0-9]+.[0-9]+-packer-beta.[0-9]+ + - 'v[0-9]+.[0-9]+.[0-9]+' + - 'v[0-9]+.[0-9]+.[0-9]+-packer-beta.[0-9]+' jobs: build: - runs-on: ${{ matrix.os }} + runs-on: '${{ matrix.os }}' strategy: matrix: os: @@ -17,7 +17,7 @@ jobs: steps: - name: Context env: - GITHUB_CONTEXT: ${{ toJson(github) }} + GITHUB_CONTEXT: '${{ toJson(github) }}' run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -37,7 +37,7 @@ jobs: uses: actions/checkout@v2 with: repository: dbgate/dbgate-pro - token: ${{ secrets.GH_TOKEN }} + token: '${{ secrets.GH_TOKEN }}' path: dbgate-pro ref: 55cf42d58b843c4f1ffd6ab9b808f5f971bc3c8b - name: Merge dbgate/dbgate-pro @@ -72,7 +72,7 @@ jobs: cd dbgate-merged yarn printSecrets env: - GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} + GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' - name: Prepare packer build run: | cd .. @@ -87,16 +87,16 @@ jobs: - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: ${{ matrix.os }} + name: '${{ matrix.os }}' path: artifacts - name: Release uses: softprops/action-gh-release@v1 - if: startsWith(github.ref, 'refs/tags/') + if: 'startsWith(github.ref, ''refs/tags/'')' with: files: artifacts/** prerelease: true env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' - name: Run `packer init` for Azure run: | cd ../dbgate-merged/packer @@ -110,33 +110,33 @@ jobs: cd ../dbgate-merged/packer packer init ./aws-ubuntu.pkr.hcl env: - AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}} - AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}} - AWS_DEFAULT_REGION: ${{secrets.AWS_DEFAULT_REGION}} + AWS_ACCESS_KEY_ID: '${{secrets.AWS_ACCESS_KEY_ID}}' + AWS_SECRET_ACCESS_KEY: '${{secrets.AWS_SECRET_ACCESS_KEY}}' + AWS_DEFAULT_REGION: '${{secrets.AWS_DEFAULT_REGION}}' - name: Run `packer build` for AWS run: | cd ../dbgate-merged/packer packer build ./aws-ubuntu.pkr.hcl env: - AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}} - AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}} - AWS_DEFAULT_REGION: ${{secrets.AWS_DEFAULT_REGION}} + AWS_ACCESS_KEY_ID: '${{secrets.AWS_ACCESS_KEY_ID}}' + AWS_SECRET_ACCESS_KEY: '${{secrets.AWS_SECRET_ACCESS_KEY}}' + AWS_DEFAULT_REGION: '${{secrets.AWS_DEFAULT_REGION}}' - name: Delete old Azure VMs run: | cd ../dbgate-merged/packer chmod +x delete-old-azure-images.sh ./delete-old-azure-images.sh env: - AZURE_CLIENT_ID: ${{secrets.AZURE_CLIENT_ID}} - AZURE_CLIENT_SECRET: ${{secrets.AZURE_CLIENT_SECRET}} - AZURE_TENANT_ID: ${{secrets.AZURE_TENANT_ID}} - AZURE_SUBSCRIPTION_ID: ${{secrets.AZURE_SUBSCRIPTION_ID}} + AZURE_CLIENT_ID: '${{secrets.AZURE_CLIENT_ID}}' + AZURE_CLIENT_SECRET: '${{secrets.AZURE_CLIENT_SECRET}}' + AZURE_TENANT_ID: '${{secrets.AZURE_TENANT_ID}}' + AZURE_SUBSCRIPTION_ID: '${{secrets.AZURE_SUBSCRIPTION_ID}}' - name: Delete old AMIs (AWS) run: | cd ../dbgate-merged/packer chmod +x delete-old-amis.sh ./delete-old-amis.sh env: - AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}} - AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}} - AWS_DEFAULT_REGION: ${{secrets.AWS_DEFAULT_REGION}} + AWS_ACCESS_KEY_ID: '${{secrets.AWS_ACCESS_KEY_ID}}' + AWS_SECRET_ACCESS_KEY: '${{secrets.AWS_SECRET_ACCESS_KEY}}' + AWS_DEFAULT_REGION: '${{secrets.AWS_DEFAULT_REGION}}' diff --git a/.github/workflows/build-docker-pro.yaml b/.github/workflows/build-docker-pro.yaml index 029dde3d4..be8442201 100644 --- a/.github/workflows/build-docker-pro.yaml +++ b/.github/workflows/build-docker-pro.yaml @@ -5,11 +5,11 @@ name: Docker image PREMIUM 'on': push: tags: - - v[0-9]+.[0-9]+.[0-9]+ - - v[0-9]+.[0-9]+.[0-9]+-premium-beta.[0-9]+ + - 'v[0-9]+.[0-9]+.[0-9]+' + - 'v[0-9]+.[0-9]+.[0-9]+-premium-beta.[0-9]+' jobs: build: - runs-on: ${{ matrix.os }} + runs-on: '${{ matrix.os }}' strategy: matrix: os: @@ -17,7 +17,7 @@ jobs: steps: - name: Context env: - GITHUB_CONTEXT: ${{ toJson(github) }} + GITHUB_CONTEXT: '${{ toJson(github) }}' run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -42,7 +42,7 @@ jobs: uses: actions/checkout@v2 with: repository: dbgate/dbgate-pro - token: ${{ secrets.GH_TOKEN }} + token: '${{ secrets.GH_TOKEN }}' path: dbgate-pro ref: 55cf42d58b843c4f1ffd6ab9b808f5f971bc3c8b - name: Merge dbgate/dbgate-pro @@ -83,7 +83,7 @@ jobs: yarn printSecrets env: - GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} + GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' - name: Prepare docker image run: | cd .. @@ -97,12 +97,12 @@ jobs: - name: Login to DockerHub uses: docker/login-action@v2 with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} + username: '${{ secrets.DOCKER_USERNAME }}' + password: '${{ secrets.DOCKER_PASSWORD }}' - name: Build and push uses: docker/build-push-action@v3 with: push: true context: ../dbgate-merged/docker - tags: ${{ steps.meta.outputs.tags }} - platforms: linux/amd64,linux/arm64 + tags: '${{ steps.meta.outputs.tags }}' + platforms: 'linux/amd64,linux/arm64' diff --git a/.github/workflows/build-docker.yaml b/.github/workflows/build-docker.yaml index 644335b1d..09c38abdf 100644 --- a/.github/workflows/build-docker.yaml +++ b/.github/workflows/build-docker.yaml @@ -5,11 +5,11 @@ name: Docker image Community 'on': push: tags: - - v[0-9]+.[0-9]+.[0-9]+ - - v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+ + - 'v[0-9]+.[0-9]+.[0-9]+' + - 'v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+' jobs: build: - runs-on: ${{ matrix.os }} + runs-on: '${{ matrix.os }}' strategy: matrix: os: @@ -17,7 +17,7 @@ jobs: steps: - name: Context env: - GITHUB_CONTEXT: ${{ toJson(github) }} + GITHUB_CONTEXT: '${{ toJson(github) }}' run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -70,7 +70,7 @@ jobs: yarn printSecrets env: - GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} + GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' - name: Prepare docker image run: | @@ -82,20 +82,20 @@ jobs: - name: Login to DockerHub uses: docker/login-action@v2 with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} + username: '${{ secrets.DOCKER_USERNAME }}' + password: '${{ secrets.DOCKER_PASSWORD }}' - name: Build and push uses: docker/build-push-action@v3 with: push: true context: ./docker - tags: ${{ steps.meta.outputs.tags }} - platforms: linux/amd64,linux/arm64,linux/arm/v7 + tags: '${{ steps.meta.outputs.tags }}' + platforms: 'linux/amd64,linux/arm64,linux/arm/v7' - name: Build and push alpine uses: docker/build-push-action@v3 with: push: true context: ./docker file: ./docker/Dockerfile-alpine - tags: ${{ steps.alpmeta.outputs.tags }} - platforms: linux/amd64,linux/arm64,linux/arm/v7 + tags: '${{ steps.alpmeta.outputs.tags }}' + platforms: 'linux/amd64,linux/arm64,linux/arm/v7' diff --git a/.github/workflows/build-npm-pro.yaml b/.github/workflows/build-npm-pro.yaml index c6c83f7f3..b97ab4d19 100644 --- a/.github/workflows/build-npm-pro.yaml +++ b/.github/workflows/build-npm-pro.yaml @@ -5,11 +5,11 @@ name: NPM packages PREMIUM 'on': push: tags: - - v[0-9]+.[0-9]+.[0-9]+ - - v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+ + - 'v[0-9]+.[0-9]+.[0-9]+' + - 'v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+' jobs: build: - runs-on: ${{ matrix.os }} + runs-on: '${{ matrix.os }}' strategy: matrix: os: @@ -17,7 +17,7 @@ jobs: steps: - name: Context env: - GITHUB_CONTEXT: ${{ toJson(github) }} + GITHUB_CONTEXT: '${{ toJson(github) }}' run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -30,7 +30,7 @@ jobs: uses: actions/checkout@v2 with: repository: dbgate/dbgate-pro - token: ${{ secrets.GH_TOKEN }} + token: '${{ secrets.GH_TOKEN }}' path: dbgate-pro ref: 55cf42d58b843c4f1ffd6ab9b808f5f971bc3c8b - name: Merge dbgate/dbgate-pro @@ -51,7 +51,7 @@ jobs: node adjustNpmPackageJsonPremium - name: Configure NPM token env: - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + NPM_TOKEN: '${{ secrets.NPM_TOKEN }}' run: | cd .. cd dbgate-merged @@ -77,7 +77,7 @@ jobs: cd dbgate-merged yarn printSecrets env: - GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} + GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' - name: Publish dbgate-api-premium run: | cd .. diff --git a/.github/workflows/build-npm.yaml b/.github/workflows/build-npm.yaml index 0c79e5097..f204115dd 100644 --- a/.github/workflows/build-npm.yaml +++ b/.github/workflows/build-npm.yaml @@ -5,11 +5,11 @@ name: NPM packages 'on': push: tags: - - v[0-9]+.[0-9]+.[0-9]+ - - v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+ + - 'v[0-9]+.[0-9]+.[0-9]+' + - 'v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+' jobs: build: - runs-on: ${{ matrix.os }} + runs-on: '${{ matrix.os }}' strategy: matrix: os: @@ -17,7 +17,7 @@ jobs: steps: - name: Context env: - GITHUB_CONTEXT: ${{ toJson(github) }} + GITHUB_CONTEXT: '${{ toJson(github) }}' run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -28,7 +28,7 @@ jobs: node-version: 18.x - name: Configure NPM token env: - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + NPM_TOKEN: '${{ secrets.NPM_TOKEN }}' run: | npm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN}" - name: yarn install @@ -41,7 +41,7 @@ jobs: run: | yarn printSecrets env: - GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} + GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' - name: Publish types working-directory: packages/types run: | diff --git a/.github/workflows/build-test-containers.yaml b/.github/workflows/build-test-containers.yaml index 90346f8f1..af2c5bc81 100644 --- a/.github/workflows/build-test-containers.yaml +++ b/.github/workflows/build-test-containers.yaml @@ -30,8 +30,8 @@ jobs: uses: docker/login-action@v2 with: registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + username: '${{ github.actor }}' + password: '${{ secrets.GITHUB_TOKEN }}' - name: Push mysql-ssh-login to GHCR run: | docker tag dbgate/mysql-ssh-login:latest ghcr.io/dbgate/mysql-ssh-login:latest diff --git a/.github/workflows/diflow.yaml b/.github/workflows/diflow.yaml index 064fd8be8..a9b8fbd91 100644 --- a/.github/workflows/diflow.yaml +++ b/.github/workflows/diflow.yaml @@ -33,4 +33,4 @@ jobs: cd diflow node dist/diflow.js sync -r https://DIFLOW_GIT_SECRET@github.com/dbgate/dbgate-diflow-config.git -b master env: - DIFLOW_GIT_SECRET: ${{ secrets.DIFLOW_GIT_SECRET }} + DIFLOW_GIT_SECRET: '${{ secrets.DIFLOW_GIT_SECRET }}' diff --git a/.github/workflows/e2e-pro.yaml b/.github/workflows/e2e-pro.yaml index 3b3d87b7e..1477fb71a 100644 --- a/.github/workflows/e2e-pro.yaml +++ b/.github/workflows/e2e-pro.yaml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v2 with: repository: dbgate/dbgate-pro - token: ${{ secrets.GH_TOKEN }} + token: '${{ secrets.GH_TOKEN }}' path: dbgate-pro ref: 55cf42d58b843c4f1ffd6ab9b808f5f971bc3c8b - name: Merge dbgate/dbgate-pro @@ -70,7 +70,7 @@ jobs: name: screenshots path: screenshots - name: Push E2E screenshots - if: ${{ github.ref_name == 'master' }} + if: '${{ github.ref_name == ''master'' }}' run: | git config --global user.email "info@dbgate.info" git config --global user.name "GitHub Actions" @@ -89,25 +89,25 @@ jobs: ports: - '16000:5432' mysql-cypress: - image: mysql:8.0.18 + image: 'mysql:8.0.18' ports: - '16004:3306' env: MYSQL_ROOT_PASSWORD: Pwd2020Db mysql-ssh-login: - image: ghcr.io/dbgate/mysql-ssh-login:latest + image: 'ghcr.io/dbgate/mysql-ssh-login:latest' ports: - '16012:22' mysql-ssh-keyfile: - image: ghcr.io/dbgate/mysql-ssh-keyfile:latest + image: 'ghcr.io/dbgate/mysql-ssh-keyfile:latest' ports: - '16008:22' dex: - image: ghcr.io/dbgate/dex:latest + image: 'ghcr.io/dbgate/dex:latest' ports: - '16009:5556' mongo: - image: mongo:4.0.12 + image: 'mongo:4.0.12' env: MONGO_INITDB_ROOT_USERNAME: root MONGO_INITDB_ROOT_PASSWORD: Pwd2020Db @@ -126,7 +126,7 @@ jobs: SA_PASSWORD: Pwd2020Db MSSQL_PID: Express oracle: - image: gvenzl/oracle-xe:21-slim + image: 'gvenzl/oracle-xe:21-slim' env: ORACLE_PASSWORD: Pwd2020Db ports: diff --git a/.github/workflows/process-templates.yaml b/.github/workflows/process-templates.yaml index 5baa3490e..0e12a4be3 100644 --- a/.github/workflows/process-templates.yaml +++ b/.github/workflows/process-templates.yaml @@ -15,7 +15,7 @@ jobs: - name: Check out repository uses: actions/checkout@v3 with: - token: ${{ secrets.WORKFLOW_CHANGE_ACCESS_TOKEN }} + token: '${{ secrets.WORKFLOW_CHANGE_ACCESS_TOKEN }}' - name: git pull run: | git pull @@ -47,5 +47,5 @@ jobs: - name: Push changes uses: ad-m/github-push-action@v0.6.0 with: - github_token: ${{ secrets.WORKFLOW_CHANGE_ACCESS_TOKEN }} + github_token: '${{ secrets.WORKFLOW_CHANGE_ACCESS_TOKEN }}' branch: master diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 6010cdb05..650b443bf 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -45,19 +45,19 @@ jobs: - uses: tanmen/jest-reporter@v1 if: always() with: - github-token: ${{ secrets.GITHUB_TOKEN }} + github-token: '${{ secrets.GITHUB_TOKEN }}' result-file: integration-tests/result.json action-name: Integration tests - uses: tanmen/jest-reporter@v1 if: always() with: - github-token: ${{ secrets.GITHUB_TOKEN }} + github-token: '${{ secrets.GITHUB_TOKEN }}' result-file: packages/filterparser/result.json action-name: Filter parser test results - uses: tanmen/jest-reporter@v1 if: always() with: - github-token: ${{ secrets.GITHUB_TOKEN }} + github-token: '${{ secrets.GITHUB_TOKEN }}' result-file: packages/datalib/result.json action-name: Datalib (perspectives) test results services: @@ -69,7 +69,7 @@ jobs: ports: - '15000:5432' mysql-integr: - image: mysql:8.0.18 + image: 'mysql:8.0.18' env: MYSQL_ROOT_PASSWORD: Pwd2020Db ports: @@ -83,22 +83,34 @@ jobs: ports: - '15002:1433' clickhouse-integr: - image: bitnami/clickhouse:24.8.4 + image: 'bitnami/clickhouse:24.8.4' env: CLICKHOUSE_ADMIN_PASSWORD: Pwd2020Db ports: - '15005:8123' oracle-integr: - image: gvenzl/oracle-xe:21-slim + image: 'gvenzl/oracle-xe:21-slim' env: ORACLE_PASSWORD: Pwd2020Db ports: - '15006:1521' cassandradb: - image: cassandra:5.0.2 + image: 'cassandra:5.0.2' ports: - '15942:9042' libsql: - image: ghcr.io/tursodatabase/libsql-server:latest + image: 'ghcr.io/tursodatabase/libsql-server:latest' ports: - '8080:8080' + firebird: + image: 'firebirdsql/firebird:latest' + container_name: firebird-db + env: + - FIREBIRD_DATABASE=mydatabase.fdb + - FIREBIRD_USER=dbuser + - FIREBIRD_PASSWORD=dbpassword + - ISC_PASSWORD=masterkey + - FIREBIRD_TRACE=false + - FIREBIRD_USE_LEGACY_AUTH=true + ports: + - '3050:3050' diff --git a/workflow-templates/run-tests.yaml b/workflow-templates/run-tests.yaml index a8eac8a2f..5dc7c9f88 100644 --- a/workflow-templates/run-tests.yaml +++ b/workflow-templates/run-tests.yaml @@ -81,13 +81,13 @@ jobs: --health-timeout 5s --health-retries 5 ports: - - 15000:5432 + - 15000:5432 mysql-integr: image: mysql:8.0.18 env: MYSQL_ROOT_PASSWORD: Pwd2020Db - ports: + ports: - 15001:3306 mssql-integr: @@ -96,14 +96,14 @@ jobs: ACCEPT_EULA: Y SA_PASSWORD: Pwd2020Db MSSQL_PID: Express - ports: + ports: - 15002:1433 clickhouse-integr: image: bitnami/clickhouse:24.8.4 env: CLICKHOUSE_ADMIN_PASSWORD: Pwd2020Db - ports: + ports: - 15005:8123 oracle-integr: @@ -122,3 +122,16 @@ jobs: image: ghcr.io/tursodatabase/libsql-server:latest ports: - '8080:8080' + + firebird: + image: firebirdsql/firebird:latest + container_name: firebird-db + env: + - FIREBIRD_DATABASE=mydatabase.fdb + - FIREBIRD_USER=dbuser + - FIREBIRD_PASSWORD=dbpassword + - ISC_PASSWORD=masterkey + - FIREBIRD_TRACE=false + - FIREBIRD_USE_LEGACY_AUTH=true + ports: + - '3050:3050' From 78521ffdb4ec3365b18f24b70403f0271bd73905 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 22 May 2025 15:44:15 +0200 Subject: [PATCH 16/65] fix: remove schemaName from firebird columns query --- plugins/dbgate-plugin-firebird/src/backend/sql/columns.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js index 0f854a8ed..be4b24680 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js @@ -24,8 +24,7 @@ SELECT DISTINCT WHEN f.rdb$field_type IN (8, 9, 16) AND f.rdb$field_scale < 0 THEN TRUE ELSE FALSE END AS "isUnsigned", - CAST(TRIM(rf.rdb$field_name) AS VARCHAR(255)) AS "pureName", - CAST(TRIM(r.rdb$owner_name) AS VARCHAR(255)) AS "schemaName" + CAST(TRIM(rf.rdb$field_name) AS VARCHAR(255)) AS "pureName" FROM rdb$relation_fields rf JOIN From d4931890ae5d7761e900e9356f32962cd8cdc295 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 22 May 2025 15:50:40 +0200 Subject: [PATCH 17/65] fix: use table name as pureName for firebird column --- plugins/dbgate-plugin-firebird/src/backend/sql/columns.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js index be4b24680..eafcbc342 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js @@ -24,7 +24,7 @@ SELECT DISTINCT WHEN f.rdb$field_type IN (8, 9, 16) AND f.rdb$field_scale < 0 THEN TRUE ELSE FALSE END AS "isUnsigned", - CAST(TRIM(rf.rdb$field_name) AS VARCHAR(255)) AS "pureName" + CAST(TRIM(rf.rdb$relation_name) AS VARCHAR(255)) AS "pureName" FROM rdb$relation_fields rf JOIN From 8ea7d3d5e8b84cfda3930dd678d03aa51ef365a8 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 22 May 2025 16:48:11 +0200 Subject: [PATCH 18/65] fix: correctly show default value for firebird --- plugins/dbgate-plugin-firebird/src/backend/Analyser.js | 3 ++- plugins/dbgate-plugin-firebird/src/backend/helpers.js | 7 +++++++ plugins/dbgate-plugin-firebird/src/backend/sql/columns.js | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js index ebfd8ffb7..4e73578fc 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js @@ -1,6 +1,6 @@ const _ = require('lodash'); const sql = require('./sql'); -const { getDataTypeString, getTriggerTiming, getTriggerEventType } = require('./helpers'); +const { getDataTypeString, getTriggerTiming, getTriggerEventType, getFormattedDefaultValue } = require('./helpers'); const { DatabaseAnalyser } = require('dbgate-tools'); @@ -23,6 +23,7 @@ class Analyser extends DatabaseAnalyser { const columns = columnsResult.rows?.map(column => ({ ...column, dataType: getDataTypeString(column), + defaultValue: getFormattedDefaultValue(column.defaultValue), })); const triggers = triggersResult.rows?.map(i => ({ diff --git a/plugins/dbgate-plugin-firebird/src/backend/helpers.js b/plugins/dbgate-plugin-firebird/src/backend/helpers.js index 2eecf501d..0c2d9589c 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/helpers.js +++ b/plugins/dbgate-plugin-firebird/src/backend/helpers.js @@ -75,8 +75,15 @@ function getTriggerTiming(triggerType) { return eventMap[triggerType]?.triggerTiming || null; } +function getFormattedDefaultValue(defaultValue) { + if (defaultValue === null) return null; + + return defaultValue.replace(/^default\s*/i, ''); +} + module.exports = { getDataTypeString, getTriggerEventType, getTriggerTiming, + getFormattedDefaultValue, }; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js index eafcbc342..521151460 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js @@ -18,7 +18,7 @@ SELECT DISTINCT f.rdb$field_precision AS "precision", f.rdb$field_scale AS "scale", f.rdb$field_length AS "length", - CAST(TRIM(rf.rdb$default_value) AS VARCHAR(255)) AS "defaultValue", + CAST(TRIM(rf.RDB$DEFAULT_SOURCE) AS VARCHAR(255)) AS "defaultValue", CAST(TRIM(rf.rdb$description) AS VARCHAR(255)) AS "columnComment", CASE WHEN f.rdb$field_type IN (8, 9, 16) AND f.rdb$field_scale < 0 THEN TRUE From 808f7504c3984c3f873b61c5fc90d04da8cb3f06 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 22 May 2025 16:49:29 +0200 Subject: [PATCH 19/65] feat: add changeColumn, renameColumn, dropColumn to firebird dumper --- .../src/frontend/Dumper.js | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js b/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js index 154361d0a..6478f2e85 100644 --- a/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js +++ b/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js @@ -4,6 +4,41 @@ class Dumper extends SqlDumper { autoIncrement() { this.put(' ^generated ^by ^default ^as ^identity'); } + + dropColumn(column) { + this.putCmd('^alter ^table %f ^drop %i', column, column.columnName); + } + + renameColumn(column, newName) { + this.putCmd('^alter ^table %f ^alter ^column %i ^to %i', column, column.columnName, newName); + } + + changeColumn(oldcol, newcol, constraints) { + if (oldcol.columnName != newcol.columnName) { + this.putCmd('^alter ^table %f ^alter ^column %i ^to %i', oldcol, oldcol.columnName, newcol.columnName); + } + + if (oldcol.notNull != newcol.notNull) { + if (newcol.notNull) { + this.putCmd('^alter ^table %f ^alter ^column %i ^set ^not ^null', newcol, newcol.columnName); + } else { + this.putCmd('^alter ^table %f ^alter ^column %i ^drop ^not ^null', newcol, newcol.columnName); + } + } + + if (oldcol.defaultValue != newcol.defaultValue) { + if (newcol.defaultValue) { + this.putCmd( + '^alter ^table %f ^alter ^column %i ^set ^default %s', + newcol, + newcol.columnName, + newcol.defaultValue + ); + } else { + this.putCmd('^alter ^table %f ^alter ^column %i ^drop ^default', newcol, newcol.columnName); + } + } + } } module.exports = Dumper; From f94901c3b273b0f0db9404ec8ad3e37350ef14d2 Mon Sep 17 00:00:00 2001 From: Pavel Date: Fri, 23 May 2025 00:28:27 +0200 Subject: [PATCH 20/65] feat: handle implicit null declation in alter-table --- integration-tests/__tests__/alter-table.spec.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/integration-tests/__tests__/alter-table.spec.js b/integration-tests/__tests__/alter-table.spec.js index bcbe583ef..c6883543b 100644 --- a/integration-tests/__tests__/alter-table.spec.js +++ b/integration-tests/__tests__/alter-table.spec.js @@ -60,7 +60,9 @@ async function testTableDiff(engine, conn, driver, mangle) { if (!engine.skipReferences) { const query = formatQueryWithoutParams( driver, - `create table ~t2 (~id int not null primary key, ~fkval int null references ~t1(~col_ref))` + `create table ~t2 (~id int not null primary key, ~fkval int ${ + driver.dialect.implicitNullDeclaration ? '' : 'null' + } references ~t1(~col_ref))` ); await driver.query(conn, transformSqlForEngine(engine, query)); From c767dfb22e00b67161b3ff3633a5ca3ffbfc7ebc Mon Sep 17 00:00:00 2001 From: Pavel Date: Fri, 23 May 2025 00:59:34 +0200 Subject: [PATCH 21/65] fix: add createSql to firebird triggers --- plugins/dbgate-plugin-firebird/src/backend/Analyser.js | 9 ++++++++- plugins/dbgate-plugin-firebird/src/backend/helpers.js | 10 ++++++++++ .../dbgate-plugin-firebird/src/backend/sql/triggers.js | 3 ++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js index 4e73578fc..38f9ab6ee 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js @@ -1,6 +1,12 @@ const _ = require('lodash'); const sql = require('./sql'); -const { getDataTypeString, getTriggerTiming, getTriggerEventType, getFormattedDefaultValue } = require('./helpers'); +const { + getDataTypeString, + getTriggerTiming, + getTriggerEventType, + getFormattedDefaultValue, + getTriggerCreateSql, +} = require('./helpers'); const { DatabaseAnalyser } = require('dbgate-tools'); @@ -30,6 +36,7 @@ class Analyser extends DatabaseAnalyser { ...i, eventType: getTriggerEventType(i.TRIGGERTYPE), triggerTiming: getTriggerTiming(i.TRIGGERTYPE), + createSql: getTriggerCreateSql(i), })); const primaryKeys = primaryKeysResult.rows ?? []; diff --git a/plugins/dbgate-plugin-firebird/src/backend/helpers.js b/plugins/dbgate-plugin-firebird/src/backend/helpers.js index 0c2d9589c..0b5f4cddf 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/helpers.js +++ b/plugins/dbgate-plugin-firebird/src/backend/helpers.js @@ -71,6 +71,15 @@ function getTriggerEventType(triggerType) { return eventMap[triggerType]?.eventType || null; } +function getTriggerCreateSql(triggerResult) { + const eventType = getTriggerEventType(triggerResult.TRIGGERTYPE); + const triggerTiming = getTriggerTiming(triggerResult.TRIGGERTYPE); + const body = triggerResult.TRIGGER_BODY_SQL; + + const createSql = `CREATE OR ALTER TRIGGER "${triggerResult.pureName}" ${triggerTiming} ${eventType} ON "${triggerResult.tableName}" ${body};`; + return createSql; +} + function getTriggerTiming(triggerType) { return eventMap[triggerType]?.triggerTiming || null; } @@ -86,4 +95,5 @@ module.exports = { getTriggerEventType, getTriggerTiming, getFormattedDefaultValue, + getTriggerCreateSql, }; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/triggers.js b/plugins/dbgate-plugin-firebird/src/backend/sql/triggers.js index 6e1a622b2..95a3f5d95 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/triggers.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/triggers.js @@ -2,7 +2,8 @@ module.exports = ` SELECT TRIM(rtr.RDB$TRIGGER_NAME) as "pureName", TRIM(rtr.RDB$RELATION_NAME) as "tableName", - rtr.RDB$TRIGGER_TYPE as TRIGGERTYPE + rtr.RDB$TRIGGER_TYPE as TRIGGERTYPE, + CAST(rtr.RDB$TRIGGER_SOURCE AS VARCHAR(8191)) AS TRIGGER_BODY_SQL FROM RDB$TRIGGERS rtr JOIN RDB$RELATIONS rel ON rtr.RDB$RELATION_NAME = rel.RDB$RELATION_NAME From 842d8dd7801d435dde05010642c695cf389713e4 Mon Sep 17 00:00:00 2001 From: Pavel Date: Fri, 23 May 2025 01:00:18 +0200 Subject: [PATCH 22/65] feat: add triggers to firebird tests --- integration-tests/engines.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/integration-tests/engines.js b/integration-tests/engines.js index c1eaaf9bb..f356363b0 100644 --- a/integration-tests/engines.js +++ b/integration-tests/engines.js @@ -695,6 +695,21 @@ const firebirdEngine = { user: 'SYSDBA', password: 'masterkey', }, + objects: [], + triggers: [ + { + testName: 'triggers after each row', + create: `CREATE OR ALTER TRIGGER ~obj1 AFTER INSERT ON ~t1 AS BEGIN END;`, + drop: 'DROP TRIGGER ~obj1;', + objectTypeField: 'triggers', + expected: { + pureName: 'obj1', + tableName: 't1', + eventType: 'INSERT', + triggerTiming: 'AFTER', + }, + }, + ], skipOnCI: false, // skipChangeColumn: true, // skipIndexes: true, From c20cac621a6cd6e84c44074f2660fdb102e39c05 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 27 May 2025 12:52:46 +0200 Subject: [PATCH 23/65] fix: update firebird workflows --- .github/workflows/run-tests.yaml | 12 ++++++------ workflow-templates/run-tests.yaml | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 650b443bf..e5bbb0984 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -106,11 +106,11 @@ jobs: image: 'firebirdsql/firebird:latest' container_name: firebird-db env: - - FIREBIRD_DATABASE=mydatabase.fdb - - FIREBIRD_USER=dbuser - - FIREBIRD_PASSWORD=dbpassword - - ISC_PASSWORD=masterkey - - FIREBIRD_TRACE=false - - FIREBIRD_USE_LEGACY_AUTH=true + FIREBIRD_DATABASE: mydatabase.fdb + FIREBIRD_USER: dbuser + FIREBIRD_PASSWORD: dbpassword + ISC_PASSWORD: masterkey + FIREBIRD_TRACE: false + FIREBIRD_USE_LEGACY_AUTH: true ports: - '3050:3050' diff --git a/workflow-templates/run-tests.yaml b/workflow-templates/run-tests.yaml index 5dc7c9f88..53cd22bf6 100644 --- a/workflow-templates/run-tests.yaml +++ b/workflow-templates/run-tests.yaml @@ -127,11 +127,11 @@ jobs: image: firebirdsql/firebird:latest container_name: firebird-db env: - - FIREBIRD_DATABASE=mydatabase.fdb - - FIREBIRD_USER=dbuser - - FIREBIRD_PASSWORD=dbpassword - - ISC_PASSWORD=masterkey - - FIREBIRD_TRACE=false - - FIREBIRD_USE_LEGACY_AUTH=true + FIREBIRD_DATABASE: mydatabase.fdb + FIREBIRD_USER: dbuser + FIREBIRD_PASSWORD: dbpassword + ISC_PASSWORD: masterkey + FIREBIRD_TRACE: false + FIREBIRD_USE_LEGACY_AUTH: true ports: - '3050:3050' From 1568dfc183bd69af0715f104395e230fd840a75e Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 27 May 2025 18:49:27 +0200 Subject: [PATCH 24/65] feat: add object ids to firebird queries --- .../src/backend/Analyser.js | 41 ++++++++++++++----- .../src/backend/sql/columns.js | 2 + .../src/backend/sql/foreignKeys.js | 2 + .../src/backend/sql/functions.js | 3 +- .../src/backend/sql/primaryKeys.js | 1 + .../src/backend/sql/procedures.js | 2 +- .../src/backend/sql/tables.js | 15 ++++--- .../src/backend/sql/triggers.js | 1 + 8 files changed, 48 insertions(+), 19 deletions(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js index 38f9ab6ee..725d84a02 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js @@ -16,35 +16,46 @@ class Analyser extends DatabaseAnalyser { } async _runAnalysis() { - const tablesResult = await this.driver.query(this.dbhan, sql.tables); - const columnsResult = await this.driver.query(this.dbhan, sql.columns); - const triggersResult = await this.driver.query(this.dbhan, sql.triggers); - const primaryKeysResult = await this.driver.query(this.dbhan, sql.primaryKeys); - const foreignKeysResult = await this.driver.query(this.dbhan, sql.foreignKeys); - const functionsResults = await this.driver.query(this.dbhan, sql.functions); - const functionParametersResults = await this.driver.query(this.dbhan, sql.functionParameters); - const proceduresResults = await this.driver.query(this.dbhan, sql.procedures); - const procedureParametersResults = await this.driver.query(this.dbhan, sql.procedureParameters); + const tablesResult = await this.analyserQuery(sql.tables, ['tables']); + const columnsResult = await this.analyserQuery(sql.columns, ['tables', 'views']); + const triggersResult = await this.analyserQuery(sql.triggers, ['triggers']); + const primaryKeysResult = await this.analyserQuery(sql.primaryKeys, ['primaryKeys']); + const foreignKeysResult = await this.analyserQuery(sql.foreignKeys, ['foreignKeys']); + const functionsResults = await this.analyserQuery(sql.functions, ['functions']); + const functionParametersResults = await this.analyserQuery(sql.functionParameters, ['functions']); + const proceduresResults = await this.analyserQuery(sql.procedures, ['procedures']); + const procedureParametersResults = await this.analyserQuery(sql.procedureParameters, ['procedures']); const columns = columnsResult.rows?.map(column => ({ ...column, + objectId: `tables:${column.columnName}`, dataType: getDataTypeString(column), defaultValue: getFormattedDefaultValue(column.defaultValue), })); const triggers = triggersResult.rows?.map(i => ({ ...i, + objectId: `triggers:${i.pureName}`, eventType: getTriggerEventType(i.TRIGGERTYPE), triggerTiming: getTriggerTiming(i.TRIGGERTYPE), createSql: getTriggerCreateSql(i), })); - const primaryKeys = primaryKeysResult.rows ?? []; + const primaryKeys = + primaryKeysResult.rows?.map(primaryKey => ({ + ...primaryKey, + objectId: `tables:${primaryKey.pureName}`, + })) ?? []; - const foreignKeys = foreignKeysResult.rows ?? []; + const foreignKeys = + foreignKeysResult.rows?.map(foreignKey => ({ + ...foreignKey, + objectId: `tables:${foreignKey.pureName}`, + })) ?? []; const functions = functionsResults.rows?.map(func => ({ ...func, + objectId: `functions:${func.pureName}`, returnType: functionParametersResults.rows?.filter( param => param.owningObjectName === func.pureName && param.parameterMode === 'RETURN' )?.dataType, @@ -58,6 +69,7 @@ class Analyser extends DatabaseAnalyser { const procedures = proceduresResults.rows.map(proc => ({ ...proc, + objectId: `procedures:${proc.pureName}`, parameters: procedureParametersResults.rows ?.filter(param => param.owningObjectName === proc.pureName) .map(param => ({ @@ -69,6 +81,7 @@ class Analyser extends DatabaseAnalyser { const tables = tablesResult.rows?.map(table => ({ ...table, + objectId: `tables:${table.pureName}`, columns: columns.filter(column => column.tableName === table.pureName), primaryKey: DatabaseAnalyser.extractPrimaryKeys(table, primaryKeys), foreignKeys: DatabaseAnalyser.extractForeignKeys(table, foreignKeys), @@ -81,6 +94,12 @@ class Analyser extends DatabaseAnalyser { procedures, }; } + + async _computeSingleObjectId() { + const { typeField, pureName } = this.singleObjectFilter; + console.log('Computing single object ID for', typeField, pureName); + this.singleObjectId = `${typeField}:${pureName}`; + } } module.exports = Analyser; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js index 521151460..33c4a97ac 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js @@ -37,6 +37,8 @@ LEFT JOIN rdb$collations co ON f.rdb$collation_id = co.rdb$collation_id WHERE r.rdb$system_flag = 0 +AND + ('columns:' || CAST(TRIM(rf.rdb$field_name) AS VARCHAR(255))) =OBJECT_ID_CONDITION ORDER BY "tableName", rf.rdb$field_position; `; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/foreignKeys.js b/plugins/dbgate-plugin-firebird/src/backend/sql/foreignKeys.js index b8fd22d3e..85a57513f 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/foreignKeys.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/foreignKeys.js @@ -27,6 +27,8 @@ JOIN AND iseg_fk.RDB$FIELD_POSITION = iseg_pk.RDB$FIELD_POSITION -- Critical for matching columns in composite keys WHERE rc_fk.RDB$CONSTRAINT_TYPE = 'FOREIGN KEY' +AND + ('tables:' || TRIM(rc_fk.RDB$RELATION_NAME)) =OBJECT_ID_CONDITION ORDER BY "pureName", "constraintName", diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/functions.js b/plugins/dbgate-plugin-firebird/src/backend/sql/functions.js index 694200960..5c2ea8cc3 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/functions.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/functions.js @@ -9,7 +9,8 @@ SELECT FROM RDB$FUNCTIONS F WHERE - COALESCE(F.RDB$SYSTEM_FLAG, 0) = 0 -- User-defined functions + COALESCE(F.RDB$SYSTEM_FLAG, 0) = 0 -- User-defined functions + AND ('funcitons:' || TRIM(F.RDB$FUNCTION_NAME)) =OBJECT_ID_CONDITION ORDER BY "pureName"; `; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/primaryKeys.js b/plugins/dbgate-plugin-firebird/src/backend/sql/primaryKeys.js index 50a5abe09..3a7875f1f 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/primaryKeys.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/primaryKeys.js @@ -20,6 +20,7 @@ JOIN WHERE rc.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' AND COALESCE(rel.RDB$SYSTEM_FLAG, 0) = 0 -- Typically, you only want user-defined tables + AND ('tables:' || TRIM(rc.RDB$RELATION_NAME)) =OBJECT_ID_CONDITION ORDER BY "pureName", "constraintName", diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/procedures.js b/plugins/dbgate-plugin-firebird/src/backend/sql/procedures.js index 7816d50d7..567101e61 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/procedures.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/procedures.js @@ -1,7 +1,6 @@ module.exports = ` SELECT TRIM(P.RDB$PROCEDURE_NAME) AS "pureName", - TRIM(P.RDB$PROCEDURE_NAME) AS "objectId", -- Using procedure name as a practical objectId TRIM('PROCEDURE') AS "objectTypeField", TRIM(P.RDB$DESCRIPTION) AS "objectComment", P.RDB$PROCEDURE_SOURCE AS "createSql", -- Contains the PSQL body @@ -11,6 +10,7 @@ FROM WHERE COALESCE(P.RDB$SYSTEM_FLAG, 0) = 0 -- Filter for user-defined procedures AND P.RDB$PROCEDURE_TYPE IS NOT NULL -- Ensure it's a valid procedure type (0, 1, or 2) + AND ('procedures:' || TRIM(P.RDB$PROCEDURE_NAME)) =OBJECT_ID_CONDITION ORDER BY "pureName"; `; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js b/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js index 0f4d20538..5c8147725 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js @@ -1,9 +1,12 @@ -module.exports = ` -SELECT +module.exports = `SELECT TRIM(RDB$RELATION_NAME) AS "pureName", RDB$DESCRIPTION AS "objectComment", RDB$FORMAT AS "objectTypeField" -FROM RDB$RELATIONS -WHERE RDB$SYSTEM_FLAG = 0 -- only user-defined tables -ORDER BY "pureName"; -`; +FROM + RDB$RELATIONS +WHERE + RDB$SYSTEM_FLAG = 0 -- only user-defined tables +AND + ('tables:' || TRIM(RDB$RELATION_NAME)) =OBJECT_ID_CONDITION +ORDER BY + "pureName";`; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/triggers.js b/plugins/dbgate-plugin-firebird/src/backend/sql/triggers.js index 95a3f5d95..bdb4f945c 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/triggers.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/triggers.js @@ -8,5 +8,6 @@ FROM RDB$TRIGGERS rtr JOIN RDB$RELATIONS rel ON rtr.RDB$RELATION_NAME = rel.RDB$RELATION_NAME WHERE rtr.RDB$SYSTEM_FLAG = 0 +AND ('triggers:' || TRIM(rtr.RDB$TRIGGER_NAME)) =OBJECT_ID_CONDITION ORDER BY rtr.RDB$TRIGGER_NAME `; From 2f7b3455e5d72b34b7faa96d2fb51dd86f1f485b Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 27 May 2025 19:05:02 +0200 Subject: [PATCH 25/65] feat: add views to firebird --- .../dbgate-plugin-firebird/src/backend/Analyser.js | 9 +++++++++ .../src/backend/sql/index.js | 2 ++ .../src/backend/sql/tables.js | 2 ++ .../src/backend/sql/views.js | 14 ++++++++++++++ 4 files changed, 27 insertions(+) create mode 100644 plugins/dbgate-plugin-firebird/src/backend/sql/views.js diff --git a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js index 725d84a02..9867412bf 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js @@ -25,6 +25,7 @@ class Analyser extends DatabaseAnalyser { const functionParametersResults = await this.analyserQuery(sql.functionParameters, ['functions']); const proceduresResults = await this.analyserQuery(sql.procedures, ['procedures']); const procedureParametersResults = await this.analyserQuery(sql.procedureParameters, ['procedures']); + const viewsResults = await this.analyserQuery(sql.views, ['views']); const columns = columnsResult.rows?.map(column => ({ ...column, @@ -87,7 +88,15 @@ class Analyser extends DatabaseAnalyser { foreignKeys: DatabaseAnalyser.extractForeignKeys(table, foreignKeys), })) ?? []; + const views = + viewsResults.rows?.map(view => ({ + ...view, + objectId: `views:${view.pureName}`, + columns: columns.filter(column => column.tableName === view.pureName), + })) ?? []; + return { + views, tables, triggers, functions, diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/index.js b/plugins/dbgate-plugin-firebird/src/backend/sql/index.js index a253c99a2..11dc78825 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/index.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/index.js @@ -8,10 +8,12 @@ const functions = require('./functions'); const functionParameters = require('./functionParameters'); const procedures = require('./procedures'); const procedureParameters = require('./procedureParameters'); +const views = require('./views'); module.exports = { version, columns, + views, tables, triggers, primaryKeys, diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js b/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js index 5c8147725..b62c60fb5 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/tables.js @@ -6,6 +6,8 @@ FROM RDB$RELATIONS WHERE RDB$SYSTEM_FLAG = 0 -- only user-defined tables +AND + RDB$RELATION_TYPE = 0 -- only tables (not views, etc.) AND ('tables:' || TRIM(RDB$RELATION_NAME)) =OBJECT_ID_CONDITION ORDER BY diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/views.js b/plugins/dbgate-plugin-firebird/src/backend/sql/views.js new file mode 100644 index 000000000..d3a4e0cc4 --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/views.js @@ -0,0 +1,14 @@ +module.exports = `SELECT + TRIM(RDB$RELATION_NAME) AS "pureName", + RDB$DESCRIPTION AS "objectComment", + RDB$FORMAT AS "objectTypeField" +FROM + RDB$RELATIONS +WHERE + RDB$SYSTEM_FLAG = 0 -- only user-defined tables +AND + RDB$RELATION_TYPE = 1 -- only views (not tables, etc.) +AND + ('tables:' || TRIM(RDB$RELATION_NAME)) =OBJECT_ID_CONDITION +ORDER BY + "pureName";`; From f7ca64a49dd1313b5a13afd09b74a281e3549f6a Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 27 May 2025 19:16:21 +0200 Subject: [PATCH 26/65] fix: remove container_name from workflows --- .github/workflows/run-tests.yaml | 1 - workflow-templates/run-tests.yaml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index e5bbb0984..fa6bbaa1b 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -104,7 +104,6 @@ jobs: - '8080:8080' firebird: image: 'firebirdsql/firebird:latest' - container_name: firebird-db env: FIREBIRD_DATABASE: mydatabase.fdb FIREBIRD_USER: dbuser diff --git a/workflow-templates/run-tests.yaml b/workflow-templates/run-tests.yaml index 53cd22bf6..0309fbbcd 100644 --- a/workflow-templates/run-tests.yaml +++ b/workflow-templates/run-tests.yaml @@ -125,7 +125,6 @@ jobs: firebird: image: firebirdsql/firebird:latest - container_name: firebird-db env: FIREBIRD_DATABASE: mydatabase.fdb FIREBIRD_USER: dbuser From 2c5c58dc9093e6df6f022f3d1689bea8d56f9e68 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 29 May 2025 10:23:26 +0200 Subject: [PATCH 27/65] fix: map datatype to lowerase variants in firebird --- .../src/backend/helpers.js | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/helpers.js b/plugins/dbgate-plugin-firebird/src/backend/helpers.js index 0b5f4cddf..cadaf62fe 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/helpers.js +++ b/plugins/dbgate-plugin-firebird/src/backend/helpers.js @@ -1,47 +1,47 @@ function getDataTypeString({ dataTypeCode, scale, length, precision }) { switch (dataTypeCode) { case 7: - return 'SMALLINT'; + return 'smallint'; case 8: - return 'INTEGER'; + return 'integer'; case 9: - return 'BIGINT'; + return 'bigint'; case 10: - return 'FLOAT'; + return 'float'; case 11: - return 'DOUBLE PRECISION'; + return 'DOUBLE precision'; case 12: - return 'DATE'; + return 'date'; case 13: - return 'TIME'; + return 'time'; case 14: - return `CHAR(${length})`; + return `char(${length})`; case 16: - return `DECIMAL(${precision}, ${scale})`; + return `decimal(${precision}, ${scale})`; case 27: - return 'DOUBLE PRECISION'; + return 'double precision'; case 35: - return 'BLOB'; + return 'blob'; case 37: - return `VARCHAR(${length})`; + return `varchar(${length})`; case 261: - return 'CSTRING'; + return 'cstring'; default: if (dataTypeCode === null || dataTypeCode === undefined) return 'UNKNOWN'; - return `UNKNOWN (${dataTypeCode})`; + return `unknown (${dataTypeCode})`; } } From 9a69f1108dc5106688563f0e6c53c91f5ff48b64 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 29 May 2025 11:22:16 +0200 Subject: [PATCH 28/65] fix: skipIncrementalAnalysis for firebird --- integration-tests/engines.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/engines.js b/integration-tests/engines.js index f356363b0..48511dedf 100644 --- a/integration-tests/engines.js +++ b/integration-tests/engines.js @@ -722,7 +722,7 @@ const firebirdEngine = { // skipChangeNullability: true, // skipDeploy: true, // supportRenameSqlObject: true, - // skipIncrementalAnalysis: true, + skipIncrementalAnalysis: true, // skipDefaultValue: true, // skipDropReferences: true, }; From a5adfb7c7f8a1ee67a566639ed21cdf474c9f79f Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 29 May 2025 14:52:44 +0200 Subject: [PATCH 29/65] feat: add uniques to firebird --- .../src/backend/Analyser.js | 92 +++++++++++-------- .../src/backend/sql/index.js | 2 + .../src/backend/sql/uniques.js | 23 +++++ 3 files changed, 81 insertions(+), 36 deletions(-) create mode 100644 plugins/dbgate-plugin-firebird/src/backend/sql/uniques.js diff --git a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js index 9867412bf..efdf72289 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js @@ -26,21 +26,24 @@ class Analyser extends DatabaseAnalyser { const proceduresResults = await this.analyserQuery(sql.procedures, ['procedures']); const procedureParametersResults = await this.analyserQuery(sql.procedureParameters, ['procedures']); const viewsResults = await this.analyserQuery(sql.views, ['views']); + const unqiuesResults = await this.analyserQuery(sql.uniques, ['tables']); - const columns = columnsResult.rows?.map(column => ({ - ...column, - objectId: `tables:${column.columnName}`, - dataType: getDataTypeString(column), - defaultValue: getFormattedDefaultValue(column.defaultValue), - })); + const columns = + columnsResult.rows?.map(column => ({ + ...column, + objectId: `tables:${column.columnName}`, + dataType: getDataTypeString(column), + defaultValue: getFormattedDefaultValue(column.defaultValue), + })) ?? []; - const triggers = triggersResult.rows?.map(i => ({ - ...i, - objectId: `triggers:${i.pureName}`, - eventType: getTriggerEventType(i.TRIGGERTYPE), - triggerTiming: getTriggerTiming(i.TRIGGERTYPE), - createSql: getTriggerCreateSql(i), - })); + const triggers = + triggersResult.rows?.map(i => ({ + ...i, + objectId: `triggers:${i.pureName}`, + eventType: getTriggerEventType(i.TRIGGERTYPE), + triggerTiming: getTriggerTiming(i.TRIGGERTYPE), + createSql: getTriggerCreateSql(i), + })) ?? []; const primaryKeys = primaryKeysResult.rows?.map(primaryKey => ({ @@ -54,30 +57,45 @@ class Analyser extends DatabaseAnalyser { objectId: `tables:${foreignKey.pureName}`, })) ?? []; - const functions = functionsResults.rows?.map(func => ({ - ...func, - objectId: `functions:${func.pureName}`, - returnType: functionParametersResults.rows?.filter( - param => param.owningObjectName === func.pureName && param.parameterMode === 'RETURN' - )?.dataType, - parameters: functionParametersResults.rows - ?.filter(param => param.owningObjectName === func.pureName) - .map(param => ({ - ...param, - dataType: getDataTypeString(param), - })), - })); + const functions = + functionsResults.rows?.map(func => ({ + ...func, + objectId: `functions:${func.pureName}`, + returnType: functionParametersResults.rows?.filter( + param => param.owningObjectName === func.pureName && param.parameterMode === 'RETURN' + )?.dataType, + parameters: functionParametersResults.rows + ?.filter(param => param.owningObjectName === func.pureName) + .map(param => ({ + ...param, + dataType: getDataTypeString(param), + })), + })) ?? []; - const procedures = proceduresResults.rows.map(proc => ({ - ...proc, - objectId: `procedures:${proc.pureName}`, - parameters: procedureParametersResults.rows - ?.filter(param => param.owningObjectName === proc.pureName) - .map(param => ({ - ...param, - dataType: getDataTypeString(param), - })), - })); + const uniques = + unqiuesResults.rows?.map(unique => ({ + pureName: unique.pureName, + constraintName: unique.constraintName, + constraintType: unique.constraintType, + columns: [ + { + columnName: unique.columnName, + isDescending: unique.isDescending, + }, + ], + })) ?? []; + + const procedures = + proceduresResults.rows?.map(proc => ({ + ...proc, + objectId: `procedures:${proc.pureName}`, + parameters: procedureParametersResults.rows + ?.filter(param => param.owningObjectName === proc.pureName) + .map(param => ({ + ...param, + dataType: getDataTypeString(param), + })), + })) ?? []; const tables = tablesResult.rows?.map(table => ({ @@ -86,7 +104,9 @@ class Analyser extends DatabaseAnalyser { columns: columns.filter(column => column.tableName === table.pureName), primaryKey: DatabaseAnalyser.extractPrimaryKeys(table, primaryKeys), foreignKeys: DatabaseAnalyser.extractForeignKeys(table, foreignKeys), + uniques: uniques.filter(unique => unique.pureName === table.pureName), })) ?? []; + console.log(uniques); const views = viewsResults.rows?.map(view => ({ diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/index.js b/plugins/dbgate-plugin-firebird/src/backend/sql/index.js index 11dc78825..d8c6060ce 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/index.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/index.js @@ -9,6 +9,7 @@ const functionParameters = require('./functionParameters'); const procedures = require('./procedures'); const procedureParameters = require('./procedureParameters'); const views = require('./views'); +const uniques = require('./uniques'); module.exports = { version, @@ -22,4 +23,5 @@ module.exports = { functionParameters, procedures, procedureParameters, + uniques, }; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/uniques.js b/plugins/dbgate-plugin-firebird/src/backend/sql/uniques.js new file mode 100644 index 000000000..1f19af34d --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/uniques.js @@ -0,0 +1,23 @@ +module.exports = ` +SELECT + TRIM(rc.RDB$CONSTRAINT_NAME) AS "constraintName", -- Name of the constraint + TRIM('unique') AS "constraintType", -- Type of the constraint + TRIM(rc.RDB$RELATION_NAME) AS "pureName", -- Context: Table the constraint is on + + -- Column specific fields from RDB$INDEX_SEGMENTS for the backing index + TRIM(s.RDB$FIELD_NAME) AS "columnName", -- Name of the column in the unique key + CASE COALESCE(i.RDB$INDEX_TYPE, 0) -- isDescending: 0 for ASC (default), 1 for DESC for the backing index + WHEN 1 THEN TRUE + ELSE FALSE + END AS "isDescending" +FROM + RDB$RELATION_CONSTRAINTS rc +JOIN + -- RDB$INDEX_NAME in RDB$RELATION_CONSTRAINTS is the name of the index that enforces the UNIQUE constraint + RDB$INDICES i ON rc.RDB$INDEX_NAME = i.RDB$INDEX_NAME +JOIN + RDB$INDEX_SEGMENTS s ON i.RDB$INDEX_NAME = s.RDB$INDEX_NAME +WHERE + rc.RDB$CONSTRAINT_TYPE = 'UNIQUE' -- Filter for UNIQUE constraints + AND COALESCE(i.RDB$SYSTEM_FLAG, 0) = 0 -- Typically, backing indexes for user UQ constraints are user-related. +`; From c9a5fe56768a75ceff38ba2cf3bb80f49ef5ad2e Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 29 May 2025 14:53:09 +0200 Subject: [PATCH 30/65] fix: make firebird singledatabase --- .../dbgate-plugin-firebird/src/backend/driver.js | 8 -------- .../dbgate-plugin-firebird/src/frontend/driver.js | 15 ++++++++------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/driver.js b/plugins/dbgate-plugin-firebird/src/backend/driver.js index be411482c..4af3ed392 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/backend/driver.js @@ -144,14 +144,6 @@ const driver = { }; }, - async listDatabases(dbhan) { - return [ - { - name: 'default', - }, - ]; - }, - async close(dbhan) { return new Promise((resolve, reject) => { dbhan.client.detach(err => { diff --git a/plugins/dbgate-plugin-firebird/src/frontend/driver.js b/plugins/dbgate-plugin-firebird/src/frontend/driver.js index 598b9bb7b..00512149e 100644 --- a/plugins/dbgate-plugin-firebird/src/frontend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/frontend/driver.js @@ -75,13 +75,14 @@ const firebirdDriverBase = { defaultPort: 3050, showConnectionField: field => ['port', 'user', 'password', 'server', 'databaseFile'].includes(field), getQuerySplitterOptions: () => firebirdSplitterOptions, - // beforeConnectionSave: connection => { - // const { databaseFile } = connection; - // return { - // singleDatabase: true, - // defaultDatabase: databaseFile, - // }; - // }, + beforeConnectionSave: connection => { + const { databaseFile } = connection; + return { + ...connection, + singleDatabase: true, + defaultDatabase: databaseFile, + }; + }, engine: 'firebird@dbgate-plugin-firebird', title: 'Firebird', supportsTransactions: true, From 4e6ae93b1368db4c5dc898480d7d4036aa1d3324 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 29 May 2025 14:53:34 +0200 Subject: [PATCH 31/65] fix: add dropColumnDependencies to firebird --- plugins/dbgate-plugin-firebird/src/frontend/driver.js | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/dbgate-plugin-firebird/src/frontend/driver.js b/plugins/dbgate-plugin-firebird/src/frontend/driver.js index 00512149e..4d48acfab 100644 --- a/plugins/dbgate-plugin-firebird/src/frontend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/frontend/driver.js @@ -12,6 +12,7 @@ const dialect = { enableConstraintsPerTable: true, stringAgg: true, offsetFirstSkipSyntax: true, + dropColumnDependencies: ['dependencies', 'foreignKeys', 'indexes', 'uniques'], quoteIdentifier(s) { return `"${s}"`; From 55b4b9e02ac21ccd09342076ce8d440cc2502ff5 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 29 May 2025 14:53:54 +0200 Subject: [PATCH 32/65] feat: add script method to firebird driver --- .../src/backend/driver.js | 53 ++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/driver.js b/plugins/dbgate-plugin-firebird/src/backend/driver.js index 4af3ed392..c1f6ae900 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/backend/driver.js @@ -1,4 +1,5 @@ const _ = require('lodash'); +const { splitQuery } = require('dbgate-query-splitter'); const stream = require('stream'); const driverBase = require('../frontend/driver'); const Analyser = require('./Analyser'); @@ -97,8 +98,15 @@ const driver = { } }, + async script(dbhan, sql, { useTransaction } = {}) { + if (useTransaction) { + return this.runSqlInTransaction(dbhan, sql); + } + + return this.query(dbhan, sql); + }, + async readQuery(dbhan, sql, structure) { - console.log('readQuery from SQL:', sql); const pass = new stream.PassThrough({ objectMode: true, highWaterMark: 100, @@ -155,6 +163,49 @@ const driver = { }); }); }, + + async runSqlInTransaction() { + let transactionPromise; + const sqlItems = splitQuery(sql, driver.sqlSplitterOptions); + + try { + transactionPromise = await new Promise((resolve, reject) => { + dbhan.db.transaction(Firebird.ISOLATION_SNAPSHOT, function (err, currentTransaction) { + if (err) return reject(err); + resolve(currentTransaction); + }); + }); + + for (let i = 0; i < sqlItems.length; i++) { + const currentSql = sqlItems[i]; + + await new Promise((resolve, reject) => { + transaction.query(currentSql, function (err, result) { + if (err) return reject(err); + resolve(result); + }); + }); + } + + await new Promise((resolve, reject) => { + transaction.commit(function (err) { + if (err) return reject(err); + resolve(); + }); + }); + } catch (error) { + if (transactionPromise) { + await new Promise((resolve, reject) => { + transactionPromise.rollback(function (rollbackErr) { + if (rollbackErr) { + return reject(rollbackErr); // Re-reject the rollback error + } + resolve(); + }); + }); + } + } + }, }; module.exports = driver; From 515339bbd8542c23dfa7651a91ba8f9e948353e8 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 29 May 2025 14:57:38 +0200 Subject: [PATCH 33/65] fix: add changeColumnDependencies to firebird --- plugins/dbgate-plugin-firebird/src/frontend/driver.js | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/dbgate-plugin-firebird/src/frontend/driver.js b/plugins/dbgate-plugin-firebird/src/frontend/driver.js index 4d48acfab..3a26a36ca 100644 --- a/plugins/dbgate-plugin-firebird/src/frontend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/frontend/driver.js @@ -13,6 +13,7 @@ const dialect = { stringAgg: true, offsetFirstSkipSyntax: true, dropColumnDependencies: ['dependencies', 'foreignKeys', 'indexes', 'uniques'], + changeColumnDependencies: ['dependencies', 'indexes', 'uniques'], quoteIdentifier(s) { return `"${s}"`; From 4ff5f9204e3a13a24fe5c0de660c8739f3c1bc0a Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 29 May 2025 15:15:57 +0200 Subject: [PATCH 34/65] fix: correctly skip inc analysis --- integration-tests/__tests__/table-analyse.spec.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integration-tests/__tests__/table-analyse.spec.js b/integration-tests/__tests__/table-analyse.spec.js index 705adf077..570a2e2f2 100644 --- a/integration-tests/__tests__/table-analyse.spec.js +++ b/integration-tests/__tests__/table-analyse.spec.js @@ -94,7 +94,7 @@ describe('Table analyse', () => { }) ); - test.each(engines.map(engine => [engine.label, engine]))( + test.each(engines.filter(x => !x.skipIncrementalAnalysis).map(engine => [engine.label, engine]))( 'Table add - incremental analysis - %s', testWrapper(async (conn, driver, engine) => { await runCommandOnDriver(conn, driver, dmp => dmp.put(t2Sql(engine))); @@ -112,7 +112,7 @@ describe('Table analyse', () => { }) ); - test.each(engines.map(engine => [engine.label, engine]))( + test.each(engines.filter(x => !x.skipIncrementalAnalysis).map(engine => [engine.label, engine]))( 'Table remove - incremental analysis - %s', testWrapper(async (conn, driver, engine) => { await runCommandOnDriver(conn, driver, dmp => dmp.put(t1Sql(engine))); @@ -130,7 +130,7 @@ describe('Table analyse', () => { }) ); - test.each(engines.map(engine => [engine.label, engine]))( + test.each(engines.filter(x => !x.skipIncrementalAnalysis).map(engine => [engine.label, engine]))( 'Table change - incremental analysis - %s', testWrapper(async (conn, driver, engine) => { await runCommandOnDriver(conn, driver, dmp => dmp.put(t1Sql(engine))); From 8baff1b0d24ddb13e412012fd2d0cfe8406db7a2 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 29 May 2025 15:20:39 +0200 Subject: [PATCH 35/65] fix: add object id condtion to firbeird uniques --- plugins/dbgate-plugin-firebird/src/backend/sql/uniques.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/uniques.js b/plugins/dbgate-plugin-firebird/src/backend/sql/uniques.js index 1f19af34d..093b0678f 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/uniques.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/uniques.js @@ -20,4 +20,6 @@ JOIN WHERE rc.RDB$CONSTRAINT_TYPE = 'UNIQUE' -- Filter for UNIQUE constraints AND COALESCE(i.RDB$SYSTEM_FLAG, 0) = 0 -- Typically, backing indexes for user UQ constraints are user-related. + AND + ('tables:' || TRIM(rc.RDB$RELATION_NAME)) =OBJECT_ID_CONDITION `; From da3e12cb7e10d6c12c066e866ae9c567e42bf3fd Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 29 May 2025 15:20:51 +0200 Subject: [PATCH 36/65] feat: add indexes to firebird --- .../src/backend/Analyser.js | 15 +++++++ .../src/backend/sql/index.js | 2 + .../src/backend/sql/indexes.js | 42 +++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 plugins/dbgate-plugin-firebird/src/backend/sql/indexes.js diff --git a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js index efdf72289..379afb532 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js @@ -27,6 +27,7 @@ class Analyser extends DatabaseAnalyser { const procedureParametersResults = await this.analyserQuery(sql.procedureParameters, ['procedures']); const viewsResults = await this.analyserQuery(sql.views, ['views']); const unqiuesResults = await this.analyserQuery(sql.uniques, ['tables']); + const indexesResults = await this.analyserQuery(sql.indexes, ['tables']); const columns = columnsResult.rows?.map(column => ({ @@ -85,6 +86,19 @@ class Analyser extends DatabaseAnalyser { ], })) ?? []; + const indexes = + indexesResults.rows?.map(index => ({ + pureName: index.pureName, + constraintName: index.constraintName, + constraintType: index.constraintType, + columns: [ + { + columnName: index.columnName, + isDescending: index.isDescending, + }, + ], + })) ?? []; + const procedures = proceduresResults.rows?.map(proc => ({ ...proc, @@ -105,6 +119,7 @@ class Analyser extends DatabaseAnalyser { primaryKey: DatabaseAnalyser.extractPrimaryKeys(table, primaryKeys), foreignKeys: DatabaseAnalyser.extractForeignKeys(table, foreignKeys), uniques: uniques.filter(unique => unique.pureName === table.pureName), + indexes: indexes.filter(index => index.pureName === table.pureName), })) ?? []; console.log(uniques); diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/index.js b/plugins/dbgate-plugin-firebird/src/backend/sql/index.js index d8c6060ce..1bfb12eb5 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/index.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/index.js @@ -10,6 +10,7 @@ const procedures = require('./procedures'); const procedureParameters = require('./procedureParameters'); const views = require('./views'); const uniques = require('./uniques'); +const indexes = require('./indexes'); module.exports = { version, @@ -24,4 +25,5 @@ module.exports = { procedures, procedureParameters, uniques, + indexes, }; diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/indexes.js b/plugins/dbgate-plugin-firebird/src/backend/sql/indexes.js new file mode 100644 index 000000000..e2797f22a --- /dev/null +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/indexes.js @@ -0,0 +1,42 @@ +module.exports = ` +SELECT -- Index name, maps to pureName + TRIM(I.RDB$INDEX_NAME) AS "constraintName", -- Index name, maps to constraintName + TRIM('index') AS "constraintType", -- ConstraintType for IndexInfo + TRIM(I.RDB$RELATION_NAME) AS "pureName", -- Context: Table the index is on + CASE COALESCE(I.RDB$UNIQUE_FLAG, 0) -- isUnique: 1 for unique, 0 or NULL for non-unique [cite: 46, 838] + WHEN 1 THEN TRUE + ELSE FALSE + END AS "isUnique", + CASE + WHEN I.RDB$EXPRESSION_SOURCE IS NOT NULL THEN TRIM('expression') -- indexType: if an expression index [cite: 46, 262] + ELSE TRIM('normal') + END AS "indexType", + I.RDB$CONDITION_SOURCE AS "idx_filterDefinition", -- filterDefinition: for partial indexes [cite: 46, 261, 838] + COALESCE(I.RDB$INDEX_INACTIVE, 0) AS "idx_isInactive", -- 0 for active, 1 for inactive [cite: 46, 838] + I.RDB$DESCRIPTION AS "idx_description", -- Index description/comment [cite: 46, 838] + + -- Column specific fields from RDB$INDEX_SEGMENTS + TRIM(S.RDB$FIELD_NAME) AS "columnName", -- columnName for ColumnReference [cite: 46, 837] + CASE COALESCE(I.RDB$INDEX_TYPE, 0) -- isDescending: 0 for ASC (default), 1 for DESC for the whole index [cite: 46, 838] + WHEN 1 THEN TRUE + ELSE FALSE + END AS "isDescending", + S.RDB$FIELD_POSITION AS "col_fieldPosition" -- 0-based position of the column in the index [cite: 46, 837] +FROM + RDB$INDICES I +JOIN + RDB$INDEX_SEGMENTS S ON I.RDB$INDEX_NAME = S.RDB$INDEX_NAME +WHERE + COALESCE(I.RDB$SYSTEM_FLAG, 0) = 0 -- Filter for user-defined indexes [cite: 46, 838] + AND I.RDB$FOREIGN_KEY IS NULL -- Exclude indexes backing foreign keys [cite: 46, 838] + -- (RDB$FOREIGN_KEY is not null if the index is for an FK) + AND NOT EXISTS ( -- Exclude indexes that are the chosen supporting index for a PK or UQ constraint + SELECT 1 + FROM RDB$RELATION_CONSTRAINTS rc + WHERE rc.RDB$INDEX_NAME = I.RDB$INDEX_NAME + AND rc.RDB$CONSTRAINT_TYPE IN ('PRIMARY KEY', 'UNIQUE') + ) + + AND + ('tables:' || TRIM(i.RDB$RELATION_NAME)) =OBJECT_ID_CONDITION +`; From 2766aedc01c59af680b781b3c1479906be09460d Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 29 May 2025 15:26:58 +0200 Subject: [PATCH 37/65] fix: correct databaseFile for engines with databseFileLocationOnServer --- integration-tests/tools.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/tools.js b/integration-tests/tools.js index 0a8b3e2b2..a1a14dfd9 100644 --- a/integration-tests/tools.js +++ b/integration-tests/tools.js @@ -47,7 +47,7 @@ async function prepareConnection(engine, database) { if (engine.generateDbFile) { return { ...connection, - databaseFile: `dbtemp/${database}`, + databaseFile: (engine.databaseFileLocationOnServer ?? 'dbtemp/') + database, isPreparedOnly: true, }; } else { From 225520a765e3fbd50cccd48a837db493c33a1cae Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 29 May 2025 22:52:38 +0200 Subject: [PATCH 38/65] feat: add useTransaction option to deployDb --- integration-tests/__tests__/deploy-database.spec.js | 1 + integration-tests/engines.js | 1 + packages/api/src/shell/deployDb.js | 11 ++++++++++- packages/api/src/shell/executeQuery.js | 4 +++- packages/dbmodel/bin/dbmodel.js | 6 ++++-- packages/types/test-engines.d.ts | 1 + 6 files changed, 20 insertions(+), 4 deletions(-) diff --git a/integration-tests/__tests__/deploy-database.spec.js b/integration-tests/__tests__/deploy-database.spec.js index 219a7f676..72578d0bd 100644 --- a/integration-tests/__tests__/deploy-database.spec.js +++ b/integration-tests/__tests__/deploy-database.spec.js @@ -131,6 +131,7 @@ async function testDatabaseDeploy(engine, conn, driver, dbModelsYaml, options) { driver, loadedDbModel: convertModelToEngine(loadedDbModel, driver), dbdiffOptionsExtra, + useTransaction: engine.runDeployInTransaction, }); } diff --git a/integration-tests/engines.js b/integration-tests/engines.js index 48511dedf..02ca03d7d 100644 --- a/integration-tests/engines.js +++ b/integration-tests/engines.js @@ -711,6 +711,7 @@ const firebirdEngine = { }, ], skipOnCI: false, + runDeployInTransaction: true, // skipChangeColumn: true, // skipIndexes: true, // skipStringLength: true, diff --git a/packages/api/src/shell/deployDb.js b/packages/api/src/shell/deployDb.js index abbcc4160..6fcfd943a 100644 --- a/packages/api/src/shell/deployDb.js +++ b/packages/api/src/shell/deployDb.js @@ -20,6 +20,7 @@ const crypto = require('crypto'); * @param {string} options.ignoreNameRegex - regex for ignoring objects by name * @param {string} options.targetSchema - target schema for deployment * @param {number} options.maxMissingTablesRatio - maximum ratio of missing tables in database. Safety check, if missing ratio is highe, deploy is stopped (preventing accidental drop of all tables) + * @param {boolean} options.useTransaction - run deploy in transaction. If not provided, it will be set to true if driver supports transactions */ async function deployDb({ connection, @@ -33,6 +34,7 @@ async function deployDb({ ignoreNameRegex = '', targetSchema = null, maxMissingTablesRatio = undefined, + useTransaction, }) { if (!driver) driver = requireEngineDriver(connection); const dbhan = systemConnection || (await connectUtility(driver, connection, 'read')); @@ -60,7 +62,14 @@ async function deployDb({ maxMissingTablesRatio, }); // console.log('RUNNING DEPLOY SCRIPT:', sql); - await executeQuery({ connection, systemConnection: dbhan, driver, sql, logScriptItems: true }); + await executeQuery({ + connection, + systemConnection: dbhan, + driver, + sql, + logScriptItems: true, + useTransaction, + }); await scriptDeployer.runPost(); } finally { diff --git a/packages/api/src/shell/executeQuery.js b/packages/api/src/shell/executeQuery.js index 3f54267f0..658d3b3dd 100644 --- a/packages/api/src/shell/executeQuery.js +++ b/packages/api/src/shell/executeQuery.js @@ -14,6 +14,7 @@ const logger = getLogger('execQuery'); * @param {string} [options.sql] - SQL query * @param {string} [options.sqlFile] - SQL file * @param {boolean} [options.logScriptItems] - whether to log script items instead of whole script + * @param {boolean} [options.useTransaction] - run query in transaction */ async function executeQuery({ connection = undefined, @@ -22,6 +23,7 @@ async function executeQuery({ sql, sqlFile = undefined, logScriptItems = false, + useTransaction, }) { if (!logScriptItems) { logger.info({ sql: getLimitedQuery(sql) }, `Execute query`); @@ -38,7 +40,7 @@ async function executeQuery({ try { logger.debug(`Running SQL query, length: ${sql.length}`); - await driver.script(dbhan, sql, { logScriptItems }); + await driver.script(dbhan, sql, { logScriptItems, useTransaction }); } finally { if (!systemConnection) { await driver.close(dbhan); diff --git a/packages/dbmodel/bin/dbmodel.js b/packages/dbmodel/bin/dbmodel.js index 68cf72569..8f72a536b 100755 --- a/packages/dbmodel/bin/dbmodel.js +++ b/packages/dbmodel/bin/dbmodel.js @@ -41,13 +41,14 @@ program 'regex, which table data will be loaded and stored in model (in load command)' ) .option('-e, --engine ', 'engine name, eg. mysql@dbgate-plugin-mysql') - .option('--commonjs', 'Creates CommonJS module'); + .option('--commonjs', 'Creates CommonJS module') + .option('--transaction', 'Run deploy query in transaction'); program .command('deploy ') .description('Deploys model to database') .action(modelFolder => { - const { engine, server, user, password, database } = program.opts(); + const { engine, server, user, password, database, transaction } = program.opts(); // const hooks = []; // if (program.autoIndexForeignKeys) hooks.push(dbmodel.hooks.autoIndexForeignKeys); @@ -61,6 +62,7 @@ program database, }, modelFolder, + useTransaction: transaction, }) ); }); diff --git a/packages/types/test-engines.d.ts b/packages/types/test-engines.d.ts index 271c38bb6..3a86bfb11 100644 --- a/packages/types/test-engines.d.ts +++ b/packages/types/test-engines.d.ts @@ -51,6 +51,7 @@ export type TestEngineInfo = { alterTableAddColumnSyntax?: boolean; dbSnapshotBySeconds?: boolean; setNullDefaultInsteadOfDrop?: boolean; + runDeployInTransaction?: boolean; useTextTypeForStrings?: boolean; From d5c0f7045e9c912b7e1510343ff1f2199e00bba4 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 3 Jun 2025 12:44:04 +0200 Subject: [PATCH 39/65] fix: add arguments to runSqlInTransaction --- plugins/dbgate-plugin-firebird/src/backend/driver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/driver.js b/plugins/dbgate-plugin-firebird/src/backend/driver.js index c1f6ae900..1cbd218b0 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/backend/driver.js @@ -164,7 +164,7 @@ const driver = { }); }, - async runSqlInTransaction() { + async runSqlInTransaction(dbhan, sql) { let transactionPromise; const sqlItems = splitQuery(sql, driver.sqlSplitterOptions); From a19648a6e878d4a1d2f3783a29851e0e43af0931 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 3 Jun 2025 13:07:46 +0200 Subject: [PATCH 40/65] fix: correct runSqlInTransaction --- .../src/backend/driver.js | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/driver.js b/plugins/dbgate-plugin-firebird/src/backend/driver.js index 1cbd218b0..3f7f9c2da 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/backend/driver.js @@ -98,11 +98,9 @@ const driver = { } }, - async script(dbhan, sql, { useTransaction } = {}) { - if (useTransaction) { - return this.runSqlInTransaction(dbhan, sql); - } + async script(dbhan, sql, { useTransaction } = {}) { + if (useTransaction) return this.runSqlInTransaction(dbhan, sql); return this.query(dbhan, sql); }, @@ -164,13 +162,18 @@ const driver = { }); }, + /** + * @param {import('dbgate-types').DatabaseHandle} dbhan + * @param {string} sql + */ async runSqlInTransaction(dbhan, sql) { + /** @type {Firebird.Transaction} */ let transactionPromise; const sqlItems = splitQuery(sql, driver.sqlSplitterOptions); try { transactionPromise = await new Promise((resolve, reject) => { - dbhan.db.transaction(Firebird.ISOLATION_SNAPSHOT, function (err, currentTransaction) { + dbhan.client.transaction(Firebird.ISOLATION_SNAPSHOT, function (err, currentTransaction) { if (err) return reject(err); resolve(currentTransaction); }); @@ -180,24 +183,32 @@ const driver = { const currentSql = sqlItems[i]; await new Promise((resolve, reject) => { - transaction.query(currentSql, function (err, result) { - if (err) return reject(err); + transactionPromise.query(currentSql, function (err, result) { + if (err) { + logger.error(extractErrorLogData(err), 'Error executing SQL in transaction'); + return reject(err); + } resolve(result); }); }); } await new Promise((resolve, reject) => { - transaction.commit(function (err) { - if (err) return reject(err); + transactionPromise.commit(function (err) { + if (err) { + logger.error(extractErrorLogData(err), 'Error committing transaction'); + return reject(err); + } resolve(); }); }); } catch (error) { + logger.error(extractErrorLogData(error), 'Transaction error'); if (transactionPromise) { await new Promise((resolve, reject) => { transactionPromise.rollback(function (rollbackErr) { if (rollbackErr) { + logger.error(extractErrorLogData(rollbackErr), 'Error rolling back transaction'); return reject(rollbackErr); // Re-reject the rollback error } resolve(); @@ -205,6 +216,8 @@ const driver = { }); } } + + return transactionPromise; }, }; From 8f4c61c2593a14203e29443e5b8bd58f57050d0d Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 3 Jun 2025 13:56:13 +0200 Subject: [PATCH 41/65] fix: correct transaction syntax for firebird --- plugins/dbgate-plugin-firebird/src/frontend/Dumper.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js b/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js index 6478f2e85..d5f567ad4 100644 --- a/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js +++ b/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js @@ -39,6 +39,10 @@ class Dumper extends SqlDumper { } } } + + beginTransaction() { + this.putCmd('^set ^transaction'); + } } module.exports = Dumper; From aba829c99139689b861fc3a43b0b18517f9cc3d7 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 3 Jun 2025 13:56:24 +0200 Subject: [PATCH 42/65] feat: skip data modifiaciton for firebird --- integration-tests/engines.js | 1 + 1 file changed, 1 insertion(+) diff --git a/integration-tests/engines.js b/integration-tests/engines.js index 02ca03d7d..bdf797aea 100644 --- a/integration-tests/engines.js +++ b/integration-tests/engines.js @@ -712,6 +712,7 @@ const firebirdEngine = { ], skipOnCI: false, runDeployInTransaction: true, + skipDataModifications: true, // skipChangeColumn: true, // skipIndexes: true, // skipStringLength: true, From b8899fcafaa732f8e6175b1c3c40931a17e4bcde Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 3 Jun 2025 14:11:01 +0200 Subject: [PATCH 43/65] fix: always pass runDeployInTransaction to scipt --- integration-tests/__tests__/deploy-database.spec.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/integration-tests/__tests__/deploy-database.spec.js b/integration-tests/__tests__/deploy-database.spec.js index 72578d0bd..2ef19b9dd 100644 --- a/integration-tests/__tests__/deploy-database.spec.js +++ b/integration-tests/__tests__/deploy-database.spec.js @@ -106,7 +106,9 @@ async function testDatabaseDeploy(engine, conn, driver, dbModelsYaml, options) { for (const loadedDbModel of dbModelsYaml) { if (_.isString(loadedDbModel)) { - await driver.script(conn, formatQueryWithoutParams(driver, loadedDbModel)); + await driver.script(conn, formatQueryWithoutParams(driver, loadedDbModel), { + useTransaction: engine.runDeployInTransaction, + }); } else { const { sql, isEmpty } = await generateDeploySql({ systemConnection: conn.isPreparedOnly ? undefined : conn, From ffb6cfaa4a86efbe95ce32874ab1f692c43669b2 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 3 Jun 2025 14:20:54 +0200 Subject: [PATCH 44/65] feat: add writeTable to firebird --- plugins/dbgate-plugin-firebird/src/backend/driver.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/driver.js b/plugins/dbgate-plugin-firebird/src/backend/driver.js index 3f7f9c2da..49a62721e 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/backend/driver.js @@ -43,6 +43,8 @@ const driver = { dbhan.client.query(sql, (err, result) => { if (err) { reject(err); + console.error(err); + console.error('Executing query:', sql); return; } @@ -98,6 +100,9 @@ const driver = { } }, + async writeTable(dbhan, name, options) { + return createBulkInsertStreamBase(this, stream, dbhan, name, options); + }, async script(dbhan, sql, { useTransaction } = {}) { if (useTransaction) return this.runSqlInTransaction(dbhan, sql); @@ -137,7 +142,7 @@ const driver = { }, async writeTable(dbhan, name, options) { - return createBulkInsertStream(this, stream, dbhan, name, options); + return createBulkInsertStreamBase(this, stream, dbhan, name, options); }, async getVersion(dbhan) { @@ -186,6 +191,7 @@ const driver = { transactionPromise.query(currentSql, function (err, result) { if (err) { logger.error(extractErrorLogData(err), 'Error executing SQL in transaction'); + logger.error({ sql: currentSql }, 'SQL that caused the error'); return reject(err); } resolve(result); From 696d4e73426dfe0a669cdd1888d8247c1811d81f Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 3 Jun 2025 16:36:40 +0200 Subject: [PATCH 45/65] feat: skip change column for firebird --- integration-tests/engines.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/engines.js b/integration-tests/engines.js index bdf797aea..512c673c4 100644 --- a/integration-tests/engines.js +++ b/integration-tests/engines.js @@ -713,7 +713,7 @@ const firebirdEngine = { skipOnCI: false, runDeployInTransaction: true, skipDataModifications: true, - // skipChangeColumn: true, + skipChangeColumn: true, // skipIndexes: true, // skipStringLength: true, // skipTriggers: true, From 159224700fa0e9fdf09508bbc6c0fb54de8ad69d Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 3 Jun 2025 16:52:51 +0200 Subject: [PATCH 46/65] fix: skip table rename for firebird --- integration-tests/__tests__/deploy-database.spec.js | 2 +- integration-tests/engines.js | 1 + packages/types/test-engines.d.ts | 1 + plugins/dbgate-plugin-firebird/src/frontend/driver.js | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/integration-tests/__tests__/deploy-database.spec.js b/integration-tests/__tests__/deploy-database.spec.js index 2ef19b9dd..77b35ba1a 100644 --- a/integration-tests/__tests__/deploy-database.spec.js +++ b/integration-tests/__tests__/deploy-database.spec.js @@ -609,7 +609,7 @@ describe('Deploy database', () => { }) ); - test.each(engines.filter(i => !i.skipDeploy).map(engine => [engine.label, engine]))( + test.each(engines.filter(i => !i.skipDeploy || !i.skipRenameTable).map(engine => [engine.label, engine]))( 'Mark table removed - %s', testWrapper(async (conn, driver, engine) => { await testDatabaseDeploy(engine, conn, driver, [[T1], [], []], { diff --git a/integration-tests/engines.js b/integration-tests/engines.js index 512c673c4..e4c39dd7e 100644 --- a/integration-tests/engines.js +++ b/integration-tests/engines.js @@ -725,6 +725,7 @@ const firebirdEngine = { // skipDeploy: true, // supportRenameSqlObject: true, skipIncrementalAnalysis: true, + skipRenameTable: true, // skipDefaultValue: true, // skipDropReferences: true, }; diff --git a/packages/types/test-engines.d.ts b/packages/types/test-engines.d.ts index 3a86bfb11..4388e5c85 100644 --- a/packages/types/test-engines.d.ts +++ b/packages/types/test-engines.d.ts @@ -45,6 +45,7 @@ export type TestEngineInfo = { skipChangeNullability?: boolean; skipRenameColumn?: boolean; skipDropReferences?: boolean; + skipRenameTable?: boolean; forceSortResults?: boolean; forceSortStructureColumns?: boolean; diff --git a/plugins/dbgate-plugin-firebird/src/frontend/driver.js b/plugins/dbgate-plugin-firebird/src/frontend/driver.js index 3a26a36ca..6ece62915 100644 --- a/plugins/dbgate-plugin-firebird/src/frontend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/frontend/driver.js @@ -38,6 +38,7 @@ const dialect = { allowMultipleValuesInsert: true, renameSqlObject: true, filteredIndexes: true, + disableRenameTable: true, }; const firebirdSplitterOptions = { From e4911a6f82ae44246bd3b7c3d368463df8de6545 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 3 Jun 2025 17:18:44 +0200 Subject: [PATCH 47/65] feat: discard result support for firebird query --- plugins/dbgate-plugin-firebird/src/backend/driver.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/driver.js b/plugins/dbgate-plugin-firebird/src/backend/driver.js index 49a62721e..5c2af650d 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/backend/driver.js @@ -38,7 +38,7 @@ const driver = { }; }, - async query(dbhan, sql) { + async query(dbhan, sql, { discardResult } = {}) { const res = await new Promise((resolve, reject) => { dbhan.client.query(sql, (err, result) => { if (err) { @@ -51,6 +51,14 @@ const driver = { resolve(result); }); }); + + if (discardResult) { + return { + rows: [], + columns: [], + }; + } + const columns = res?.[0] ? Object.keys(res[0]).map(i => ({ columnName: i })) : []; return { From 4177448d320e5a953aec0b689406ffeed7fcf573 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 3 Jun 2025 17:19:02 +0200 Subject: [PATCH 48/65] fix: correctly processing script outside of transactions for firebird --- plugins/dbgate-plugin-firebird/src/backend/driver.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/driver.js b/plugins/dbgate-plugin-firebird/src/backend/driver.js index 5c2af650d..7fc0791e3 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/backend/driver.js @@ -114,7 +114,11 @@ const driver = { async script(dbhan, sql, { useTransaction } = {}) { if (useTransaction) return this.runSqlInTransaction(dbhan, sql); - return this.query(dbhan, sql); + + const sqlItems = splitQuery(sql, driver.sqlSplitterOptions); + for (const sqlItem of sqlItems) { + await this.query(dbhan, sqlItem, { discardResult: true }); + } }, async readQuery(dbhan, sql, structure) { From 4e135987084be39a2430806c9a88e303884eeb71 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 3 Jun 2025 17:39:40 +0200 Subject: [PATCH 49/65] fix: add custom create index to firebird dumper --- .../src/frontend/Dumper.js | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js b/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js index d5f567ad4..954abbebe 100644 --- a/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js +++ b/plugins/dbgate-plugin-firebird/src/frontend/Dumper.js @@ -43,6 +43,27 @@ class Dumper extends SqlDumper { beginTransaction() { this.putCmd('^set ^transaction'); } + + createIndex(ix) { + const firstCol = ix.columns[0]; + this.put('^create'); + if (ix.isUnique) this.put(' ^unique'); + this.put( + ' %k ^index %i &n^on %f (&>&n', + firstCol.isDescending == true ? 'DESCENDING' : 'ASCENDING', + ix.constraintName, + ix + ); + + this.putCollection(',&n', ix.columns, col => { + this.put('%i', col.columnName); + }); + this.put('&<&n)'); + if (ix.filterDefinition && this.dialect.filteredIndexes) { + this.put('&n^where %s', ix.filterDefinition); + } + this.endCommand(); + } } module.exports = Dumper; From 38d87a7c8f339a7a73061807804753241d7578ff Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 3 Jun 2025 17:39:49 +0200 Subject: [PATCH 50/65] fix: update column deps for firebird --- plugins/dbgate-plugin-firebird/src/frontend/driver.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/dbgate-plugin-firebird/src/frontend/driver.js b/plugins/dbgate-plugin-firebird/src/frontend/driver.js index 6ece62915..76f00051c 100644 --- a/plugins/dbgate-plugin-firebird/src/frontend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/frontend/driver.js @@ -12,8 +12,9 @@ const dialect = { enableConstraintsPerTable: true, stringAgg: true, offsetFirstSkipSyntax: true, - dropColumnDependencies: ['dependencies', 'foreignKeys', 'indexes', 'uniques'], - changeColumnDependencies: ['dependencies', 'indexes', 'uniques'], + dropColumnDependencies: ['dependencies', 'primaryKeys', 'foreignKeys', 'indexes', 'uniques'], + changeColumnDependencies: ['dependencies', 'primaryKeys', 'indexes', 'uniques'], + renameColumnDependencies: ['dependencies', 'foreignKeys', 'uniques'], quoteIdentifier(s) { return `"${s}"`; From 58f1f749fca97d9c0a1761b319398c600ef14614 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 3 Jun 2025 18:15:07 +0200 Subject: [PATCH 51/65] fix: respect implicitNullDeclaration in alter database queries --- integration-tests/__tests__/alter-database.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/__tests__/alter-database.spec.js b/integration-tests/__tests__/alter-database.spec.js index ad3b11694..893063e31 100644 --- a/integration-tests/__tests__/alter-database.spec.js +++ b/integration-tests/__tests__/alter-database.spec.js @@ -29,7 +29,7 @@ async function testDatabaseDiff(conn, driver, mangle, createObject = null) { driver, `create table ~t2 ( ~id int not null primary key, - ~t1_id int null references ~t1(~id) + ~t1_id int ${driver.dialect.implicitNullDeclaration ? '' : 'null'} references ~t1(~id) )` ); From c270cba8d6df96804c6a85da47bcc94aaaf6c284 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 5 Jun 2025 10:37:04 +0200 Subject: [PATCH 52/65] fix: apply skipRenameTable filter correctly --- integration-tests/__tests__/deploy-database.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/__tests__/deploy-database.spec.js b/integration-tests/__tests__/deploy-database.spec.js index 77b35ba1a..e19cb3602 100644 --- a/integration-tests/__tests__/deploy-database.spec.js +++ b/integration-tests/__tests__/deploy-database.spec.js @@ -609,7 +609,7 @@ describe('Deploy database', () => { }) ); - test.each(engines.filter(i => !i.skipDeploy || !i.skipRenameTable).map(engine => [engine.label, engine]))( + test.each(engines.filter(i => !i.skipDeploy && !i.skipRenameTable).map(engine => [engine.label, engine]))( 'Mark table removed - %s', testWrapper(async (conn, driver, engine) => { await testDatabaseDeploy(engine, conn, driver, [[T1], [], []], { From 58c1b5b98dd4570820141bf7e8e1fee7efc86e9c Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 5 Jun 2025 11:35:00 +0200 Subject: [PATCH 53/65] fix:divide field length by 4 --- plugins/dbgate-plugin-firebird/src/backend/sql/columns.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js index 33c4a97ac..a88c1ac79 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js @@ -17,7 +17,7 @@ SELECT DISTINCT f.rdb$field_type AS "dataTypeCode", f.rdb$field_precision AS "precision", f.rdb$field_scale AS "scale", - f.rdb$field_length AS "length", + f.rdb$field_length / 4 AS "length", CAST(TRIM(rf.RDB$DEFAULT_SOURCE) AS VARCHAR(255)) AS "defaultValue", CAST(TRIM(rf.rdb$description) AS VARCHAR(255)) AS "columnComment", CASE From d6b05e44cbed76b92ebd2ac6d0cb377b00167bc1 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 5 Jun 2025 11:51:17 +0200 Subject: [PATCH 54/65] fix: skip all table renames for firebird --- integration-tests/__tests__/deploy-database.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/__tests__/deploy-database.spec.js b/integration-tests/__tests__/deploy-database.spec.js index e19cb3602..351ad5d92 100644 --- a/integration-tests/__tests__/deploy-database.spec.js +++ b/integration-tests/__tests__/deploy-database.spec.js @@ -825,7 +825,7 @@ describe('Deploy database', () => { }) ); - test.each(engines.filter(i => !i.skipDeploy).map(engine => [engine.label, engine]))( + test.each(engines.filter(i => !i.skipDeploy && !i.skipRenameTable).map(engine => [engine.label, engine]))( 'Mark table removed, one remains - %s', testWrapper(async (conn, driver, engine) => { await testDatabaseDeploy(engine, conn, driver, [[T1, T2], [T2], [T2]], { From da9b127468b79d7df89abf32c42ffbc1221ce2db Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 5 Jun 2025 12:31:36 +0200 Subject: [PATCH 55/65] fix: group indexes for firebird --- .../src/backend/Analyser.js | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js index 379afb532..91d39363b 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-firebird/src/backend/Analyser.js @@ -86,18 +86,16 @@ class Analyser extends DatabaseAnalyser { ], })) ?? []; - const indexes = - indexesResults.rows?.map(index => ({ - pureName: index.pureName, - constraintName: index.constraintName, - constraintType: index.constraintType, - columns: [ - { - columnName: index.columnName, - isDescending: index.isDescending, - }, - ], - })) ?? []; + const indexesGrouped = _.groupBy(indexesResults.rows, 'constraintName'); + const indexes = Object.values(indexesGrouped).map(indexGroup => ({ + pureName: indexGroup[0].pureName, + constraintName: indexGroup[0].constraintName, + constraintType: indexGroup[0].constraintType, + columns: indexGroup.map(index => ({ + columnName: index.columnName, + isDescending: index.isDescending, + })), + })); const procedures = proceduresResults.rows?.map(proc => ({ From dd90851477bce8f314aec4684dacfc23bf8d89b0 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 5 Jun 2025 14:24:33 +0200 Subject: [PATCH 56/65] fix: update collumns object id --- plugins/dbgate-plugin-firebird/src/backend/sql/columns.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js index a88c1ac79..4c554d296 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js +++ b/plugins/dbgate-plugin-firebird/src/backend/sql/columns.js @@ -38,7 +38,7 @@ LEFT JOIN WHERE r.rdb$system_flag = 0 AND - ('columns:' || CAST(TRIM(rf.rdb$field_name) AS VARCHAR(255))) =OBJECT_ID_CONDITION + ('tables:' || CAST(TRIM(rf.rdb$relation_name) AS VARCHAR(255))) =OBJECT_ID_CONDITION ORDER BY "tableName", rf.rdb$field_position; `; From e4cc4b6f585ed7147a8967299941809fc2a53b3c Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 5 Jun 2025 15:15:31 +0200 Subject: [PATCH 57/65] fix: process blob values, update firebird dialect --- .../src/backend/driver.js | 7 +--- .../src/backend/helpers.js | 39 +++++++++++++++++++ .../src/frontend/driver.js | 12 +++++- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/driver.js b/plugins/dbgate-plugin-firebird/src/backend/driver.js index 7fc0791e3..ebec5f431 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/backend/driver.js @@ -4,6 +4,7 @@ const stream = require('stream'); const driverBase = require('../frontend/driver'); const Analyser = require('./Analyser'); const Firebird = require('node-firebird'); +const { normalizeRow } = require('./helpers'); const { getLogger, extractErrorLogData, createBulkInsertStreamBase } = require('dbgate-tools'); const sql = require('./sql'); @@ -62,7 +63,7 @@ const driver = { const columns = res?.[0] ? Object.keys(res[0]).map(i => ({ columnName: i })) : []; return { - rows: res ?? [], + rows: res ? await Promise.all(res.map(normalizeRow)) : [], columns, }; }, @@ -108,10 +109,6 @@ const driver = { } }, - async writeTable(dbhan, name, options) { - return createBulkInsertStreamBase(this, stream, dbhan, name, options); - }, - async script(dbhan, sql, { useTransaction } = {}) { if (useTransaction) return this.runSqlInTransaction(dbhan, sql); diff --git a/plugins/dbgate-plugin-firebird/src/backend/helpers.js b/plugins/dbgate-plugin-firebird/src/backend/helpers.js index cadaf62fe..ff85f5485 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/helpers.js +++ b/plugins/dbgate-plugin-firebird/src/backend/helpers.js @@ -89,6 +89,43 @@ function getFormattedDefaultValue(defaultValue) { return defaultValue.replace(/^default\s*/i, ''); } +function blobStreamToString(stream, encoding = 'utf8') { + return new Promise((resolve, reject) => { + const chunks = []; + stream.on('data', chunk => { + chunks.push(chunk); + }); + stream.on('end', () => { + resolve(Buffer.concat(chunks).toString(encoding)); + }); + stream.on('error', err => { + reject(err); + }); + }); +} + +async function normalizeRow(row) { + const entries = await Promise.all( + Object.entries(row).map(async ([key, value]) => { + if (value === null || value === undefined) return [key, null]; + if (typeof value === 'function') { + const result = await new Promise((resolve, reject) => { + value(async (_err, _name, eventEmitter) => { + try { + const stringValue = await blobStreamToString(eventEmitter, 'utf8'); + resolve(stringValue); + } catch (error) { + reject(error); + } + }); + }); + return [key, result]; + } + return [key, value]; + }) + ); + return Object.fromEntries(entries); +} module.exports = { getDataTypeString, @@ -96,4 +133,6 @@ module.exports = { getTriggerTiming, getFormattedDefaultValue, getTriggerCreateSql, + blobStreamToString, + normalizeRow, }; diff --git a/plugins/dbgate-plugin-firebird/src/frontend/driver.js b/plugins/dbgate-plugin-firebird/src/frontend/driver.js index 76f00051c..7cff1ed3a 100644 --- a/plugins/dbgate-plugin-firebird/src/frontend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/frontend/driver.js @@ -7,7 +7,7 @@ const dialect = { ilike: true, multipleSchema: false, stringEscapeChar: "'", - fallbackDataType: 'varchar', + fallbackDataType: 'varchar(256)', anonymousPrimaryKey: false, enableConstraintsPerTable: true, stringAgg: true, @@ -15,6 +15,7 @@ const dialect = { dropColumnDependencies: ['dependencies', 'primaryKeys', 'foreignKeys', 'indexes', 'uniques'], changeColumnDependencies: ['dependencies', 'primaryKeys', 'indexes', 'uniques'], renameColumnDependencies: ['dependencies', 'foreignKeys', 'uniques'], + defaultValueBeforeNullability: true, quoteIdentifier(s) { return `"${s}"`; @@ -36,7 +37,7 @@ const dialect = { dropUnique: true, createCheck: true, dropCheck: true, - allowMultipleValuesInsert: true, + allowMultipleValuesInsert: false, renameSqlObject: true, filteredIndexes: true, disableRenameTable: true, @@ -87,6 +88,13 @@ const firebirdDriverBase = { defaultDatabase: databaseFile, }; }, + + adaptDataType(dataType) { + if (dataType?.toLowerCase() == 'datetime') return 'TIMESTAMP'; + if (dataType?.toLowerCase() == 'text') return 'BLOB SUB_TYPE 1 CHARACTER SET UTF8'; + return dataType; + }, + engine: 'firebird@dbgate-plugin-firebird', title: 'Firebird', supportsTransactions: true, From b74b6b32842c5c4aa849950f563d8d97eb2e09b2 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 5 Jun 2025 16:28:50 +0200 Subject: [PATCH 58/65] feat: transform rows suport for json lines reader --- packages/api/src/shell/importDbFromFolder.js | 7 ++++--- packages/api/src/shell/jsonLinesReader.js | 14 ++++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/api/src/shell/importDbFromFolder.js b/packages/api/src/shell/importDbFromFolder.js index 73b3c3456..f604ce9e0 100644 --- a/packages/api/src/shell/importDbFromFolder.js +++ b/packages/api/src/shell/importDbFromFolder.js @@ -17,8 +17,9 @@ const copyStream = require('./copyStream'); * @param {object} options.driver - driver object. If not provided, it will be loaded from connection * @param {string} options.folder - folder with model files (YAML files for tables, SQL files for views, procedures, ...) * @param {function[]} options.modelTransforms - array of functions for transforming model + * @param {((row: Record) => Record) | undefined} options.transformRow - function to transform each row */ -async function importDbFromFolder({ connection, systemConnection, driver, folder, modelTransforms }) { +async function importDbFromFolder({ connection, systemConnection, driver, folder, modelTransforms, transformRow }) { if (!driver) driver = requireEngineDriver(connection); const dbhan = systemConnection || (await connectUtility(driver, connection, 'read')); @@ -77,7 +78,7 @@ async function importDbFromFolder({ connection, systemConnection, driver, folder for (const table of modelAdapted.tables) { const fileName = path.join(folder, `${table.pureName}.jsonl`); if (await fs.exists(fileName)) { - const src = await jsonLinesReader({ fileName }); + const src = await jsonLinesReader({ fileName, transformRow }); const dst = await tableWriter({ systemConnection: dbhan, pureName: table.pureName, @@ -105,7 +106,7 @@ async function importDbFromFolder({ connection, systemConnection, driver, folder for (const file of fs.readdirSync(folder)) { if (!file.endsWith('.jsonl')) continue; const pureName = path.parse(file).name; - const src = await jsonLinesReader({ fileName: path.join(folder, file) }); + const src = await jsonLinesReader({ fileName: path.join(folder, file), transformRow }); const dst = await tableWriter({ systemConnection: dbhan, pureName, diff --git a/packages/api/src/shell/jsonLinesReader.js b/packages/api/src/shell/jsonLinesReader.js index da3d5d85d..1cf9cb578 100644 --- a/packages/api/src/shell/jsonLinesReader.js +++ b/packages/api/src/shell/jsonLinesReader.js @@ -6,10 +6,11 @@ const download = require('./download'); const logger = getLogger('jsonLinesReader'); class ParseStream extends stream.Transform { - constructor({ limitRows }) { + constructor({ limitRows, transformRow }) { super({ objectMode: true }); this.wasHeader = false; this.limitRows = limitRows; + this.transformRow = transformRow; this.rowsWritten = 0; } _transform(chunk, encoding, done) { @@ -26,7 +27,11 @@ class ParseStream extends stream.Transform { this.wasHeader = true; } if (!this.limitRows || this.rowsWritten < this.limitRows) { - this.push(obj); + if (this.transformRow) { + this.push(this.transformRow(obj)); + } else { + this.push(obj); + } this.rowsWritten += 1; } done(); @@ -39,9 +44,10 @@ class ParseStream extends stream.Transform { * @param {string} options.fileName - file name or URL * @param {string} options.encoding - encoding of the file * @param {number} options.limitRows - maximum number of rows to read + * @param {((row: Record) => Record) | undefined} options.transformRow - function to transform each row * @returns {Promise} - reader object */ -async function jsonLinesReader({ fileName, encoding = 'utf-8', limitRows = undefined }) { +async function jsonLinesReader({ fileName, encoding = 'utf-8', limitRows = undefined, transformRow }) { logger.info(`Reading file ${fileName}`); const downloadedFile = await download(fileName); @@ -52,7 +58,7 @@ async function jsonLinesReader({ fileName, encoding = 'utf-8', limitRows = undef encoding ); const liner = byline(fileStream); - const parser = new ParseStream({ limitRows }); + const parser = new ParseStream({ limitRows, transformRow }); return [liner, parser]; } From 5760ada3b427c63413efe3e47dd677f19e21ac04 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 5 Jun 2025 16:31:17 +0200 Subject: [PATCH 59/65] feat: transform firebird model rows --- integration-tests/__tests__/db-import-export.spec.js | 1 + integration-tests/engines.js | 10 ++++++++++ packages/types/test-engines.d.ts | 2 ++ 3 files changed, 13 insertions(+) diff --git a/integration-tests/__tests__/db-import-export.spec.js b/integration-tests/__tests__/db-import-export.spec.js index 7ec7a56f1..28985d3d1 100644 --- a/integration-tests/__tests__/db-import-export.spec.js +++ b/integration-tests/__tests__/db-import-export.spec.js @@ -193,6 +193,7 @@ describe('DB Import/export', () => { systemConnection: conn, driver, folder: path.join(__dirname, '../../e2e-tests/data/my-guitar-shop'), + transformRow: engine.transformModelRow, }); const res1 = await runQueryOnDriver(conn, driver, dmp => dmp.put(`select count(*) as ~cnt from ~categories`)); diff --git a/integration-tests/engines.js b/integration-tests/engines.js index e4c39dd7e..eadc46113 100644 --- a/integration-tests/engines.js +++ b/integration-tests/engines.js @@ -726,6 +726,16 @@ const firebirdEngine = { // supportRenameSqlObject: true, skipIncrementalAnalysis: true, skipRenameTable: true, + transformModelRow: row => { + return Object.fromEntries( + Object.entries(row).map(([key, value]) => { + if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/.test(value)) { + return [key, value.replace('T', ' ')]; + } + return [key, value]; + }) + ); + }, // skipDefaultValue: true, // skipDropReferences: true, }; diff --git a/packages/types/test-engines.d.ts b/packages/types/test-engines.d.ts index 4388e5c85..caa8c2d54 100644 --- a/packages/types/test-engines.d.ts +++ b/packages/types/test-engines.d.ts @@ -93,4 +93,6 @@ export type TestEngineInfo = { }>; objects?: Array; + + transformModelRow?: (row: Record) => Record; }; From d1925945b4659878315c3e9925b75b07e3bbbb03 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Mon, 9 Jun 2025 14:43:55 +0200 Subject: [PATCH 60/65] skipped failed tests --- integration-tests/engines.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration-tests/engines.js b/integration-tests/engines.js index eadc46113..fcef9373c 100644 --- a/integration-tests/engines.js +++ b/integration-tests/engines.js @@ -720,7 +720,7 @@ const firebirdEngine = { skipDataReplicator: true, skipAutoIncrement: true, // skipDropColumn: true, - // skipRenameColumn: true, + skipRenameColumn: true, // skipChangeNullability: true, // skipDeploy: true, // supportRenameSqlObject: true, @@ -737,7 +737,7 @@ const firebirdEngine = { ); }, // skipDefaultValue: true, - // skipDropReferences: true, + skipDropReferences: true, }; const enginesOnCi = [ From 20d947a1990af1a40ffb79adb33f1d993692754b Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Tue, 10 Jun 2025 16:46:16 +0200 Subject: [PATCH 61/65] readme for firebird --- plugins/dbgate-plugin-firebird/README.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 plugins/dbgate-plugin-firebird/README.md diff --git a/plugins/dbgate-plugin-firebird/README.md b/plugins/dbgate-plugin-firebird/README.md new file mode 100644 index 000000000..17e32ea2e --- /dev/null +++ b/plugins/dbgate-plugin-firebird/README.md @@ -0,0 +1,6 @@ +[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier) +[![NPM version](https://img.shields.io/npm/v/dbgate-plugin-firebird.svg)](https://www.npmjs.com/package/dbgate-plugin-firebird) + +# dbgate-plugin-firebird + +Firebid/Interbase plugin for DbGate \ No newline at end of file From 1e2474921bd36a304dfe7a1853367248b5098fbb Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 12 Jun 2025 13:29:46 +0200 Subject: [PATCH 62/65] Revert "feat: transform firebird model rows" This reverts commit 5760ada3b427c63413efe3e47dd677f19e21ac04. --- integration-tests/__tests__/db-import-export.spec.js | 1 - integration-tests/engines.js | 10 ---------- packages/types/test-engines.d.ts | 2 -- 3 files changed, 13 deletions(-) diff --git a/integration-tests/__tests__/db-import-export.spec.js b/integration-tests/__tests__/db-import-export.spec.js index 28985d3d1..7ec7a56f1 100644 --- a/integration-tests/__tests__/db-import-export.spec.js +++ b/integration-tests/__tests__/db-import-export.spec.js @@ -193,7 +193,6 @@ describe('DB Import/export', () => { systemConnection: conn, driver, folder: path.join(__dirname, '../../e2e-tests/data/my-guitar-shop'), - transformRow: engine.transformModelRow, }); const res1 = await runQueryOnDriver(conn, driver, dmp => dmp.put(`select count(*) as ~cnt from ~categories`)); diff --git a/integration-tests/engines.js b/integration-tests/engines.js index fcef9373c..1fb4f28dd 100644 --- a/integration-tests/engines.js +++ b/integration-tests/engines.js @@ -726,16 +726,6 @@ const firebirdEngine = { // supportRenameSqlObject: true, skipIncrementalAnalysis: true, skipRenameTable: true, - transformModelRow: row => { - return Object.fromEntries( - Object.entries(row).map(([key, value]) => { - if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/.test(value)) { - return [key, value.replace('T', ' ')]; - } - return [key, value]; - }) - ); - }, // skipDefaultValue: true, skipDropReferences: true, }; diff --git a/packages/types/test-engines.d.ts b/packages/types/test-engines.d.ts index caa8c2d54..4388e5c85 100644 --- a/packages/types/test-engines.d.ts +++ b/packages/types/test-engines.d.ts @@ -93,6 +93,4 @@ export type TestEngineInfo = { }>; objects?: Array; - - transformModelRow?: (row: Record) => Record; }; From 17711bc5c9ea3fff7bb46ce97b04aee038135bb3 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 12 Jun 2025 13:29:48 +0200 Subject: [PATCH 63/65] Revert "feat: transform rows suport for json lines reader" This reverts commit b74b6b32842c5c4aa849950f563d8d97eb2e09b2. --- packages/api/src/shell/importDbFromFolder.js | 7 +++---- packages/api/src/shell/jsonLinesReader.js | 14 ++++---------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/packages/api/src/shell/importDbFromFolder.js b/packages/api/src/shell/importDbFromFolder.js index f604ce9e0..73b3c3456 100644 --- a/packages/api/src/shell/importDbFromFolder.js +++ b/packages/api/src/shell/importDbFromFolder.js @@ -17,9 +17,8 @@ const copyStream = require('./copyStream'); * @param {object} options.driver - driver object. If not provided, it will be loaded from connection * @param {string} options.folder - folder with model files (YAML files for tables, SQL files for views, procedures, ...) * @param {function[]} options.modelTransforms - array of functions for transforming model - * @param {((row: Record) => Record) | undefined} options.transformRow - function to transform each row */ -async function importDbFromFolder({ connection, systemConnection, driver, folder, modelTransforms, transformRow }) { +async function importDbFromFolder({ connection, systemConnection, driver, folder, modelTransforms }) { if (!driver) driver = requireEngineDriver(connection); const dbhan = systemConnection || (await connectUtility(driver, connection, 'read')); @@ -78,7 +77,7 @@ async function importDbFromFolder({ connection, systemConnection, driver, folder for (const table of modelAdapted.tables) { const fileName = path.join(folder, `${table.pureName}.jsonl`); if (await fs.exists(fileName)) { - const src = await jsonLinesReader({ fileName, transformRow }); + const src = await jsonLinesReader({ fileName }); const dst = await tableWriter({ systemConnection: dbhan, pureName: table.pureName, @@ -106,7 +105,7 @@ async function importDbFromFolder({ connection, systemConnection, driver, folder for (const file of fs.readdirSync(folder)) { if (!file.endsWith('.jsonl')) continue; const pureName = path.parse(file).name; - const src = await jsonLinesReader({ fileName: path.join(folder, file), transformRow }); + const src = await jsonLinesReader({ fileName: path.join(folder, file) }); const dst = await tableWriter({ systemConnection: dbhan, pureName, diff --git a/packages/api/src/shell/jsonLinesReader.js b/packages/api/src/shell/jsonLinesReader.js index 1cf9cb578..da3d5d85d 100644 --- a/packages/api/src/shell/jsonLinesReader.js +++ b/packages/api/src/shell/jsonLinesReader.js @@ -6,11 +6,10 @@ const download = require('./download'); const logger = getLogger('jsonLinesReader'); class ParseStream extends stream.Transform { - constructor({ limitRows, transformRow }) { + constructor({ limitRows }) { super({ objectMode: true }); this.wasHeader = false; this.limitRows = limitRows; - this.transformRow = transformRow; this.rowsWritten = 0; } _transform(chunk, encoding, done) { @@ -27,11 +26,7 @@ class ParseStream extends stream.Transform { this.wasHeader = true; } if (!this.limitRows || this.rowsWritten < this.limitRows) { - if (this.transformRow) { - this.push(this.transformRow(obj)); - } else { - this.push(obj); - } + this.push(obj); this.rowsWritten += 1; } done(); @@ -44,10 +39,9 @@ class ParseStream extends stream.Transform { * @param {string} options.fileName - file name or URL * @param {string} options.encoding - encoding of the file * @param {number} options.limitRows - maximum number of rows to read - * @param {((row: Record) => Record) | undefined} options.transformRow - function to transform each row * @returns {Promise} - reader object */ -async function jsonLinesReader({ fileName, encoding = 'utf-8', limitRows = undefined, transformRow }) { +async function jsonLinesReader({ fileName, encoding = 'utf-8', limitRows = undefined }) { logger.info(`Reading file ${fileName}`); const downloadedFile = await download(fileName); @@ -58,7 +52,7 @@ async function jsonLinesReader({ fileName, encoding = 'utf-8', limitRows = undef encoding ); const liner = byline(fileStream); - const parser = new ParseStream({ limitRows, transformRow }); + const parser = new ParseStream({ limitRows }); return [liner, parser]; } From d708616a6aa00e8d9085c2ab77214c2c9bc06e58 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 12 Jun 2025 13:44:24 +0200 Subject: [PATCH 64/65] feat: add createFirebirdInsertStream with datetime fields transform --- .../src/backend/driver.js | 4 +-- .../src/backend/helpers.js | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/plugins/dbgate-plugin-firebird/src/backend/driver.js b/plugins/dbgate-plugin-firebird/src/backend/driver.js index ebec5f431..f6c9a4c56 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/driver.js +++ b/plugins/dbgate-plugin-firebird/src/backend/driver.js @@ -4,7 +4,7 @@ const stream = require('stream'); const driverBase = require('../frontend/driver'); const Analyser = require('./Analyser'); const Firebird = require('node-firebird'); -const { normalizeRow } = require('./helpers'); +const { normalizeRow, createFirebirdInsertStream } = require('./helpers'); const { getLogger, extractErrorLogData, createBulkInsertStreamBase } = require('dbgate-tools'); const sql = require('./sql'); @@ -151,7 +151,7 @@ const driver = { }, async writeTable(dbhan, name, options) { - return createBulkInsertStreamBase(this, stream, dbhan, name, options); + return createFirebirdInsertStream(this, stream, dbhan, name, options); }, async getVersion(dbhan) { diff --git a/plugins/dbgate-plugin-firebird/src/backend/helpers.js b/plugins/dbgate-plugin-firebird/src/backend/helpers.js index ff85f5485..2c53e38a3 100644 --- a/plugins/dbgate-plugin-firebird/src/backend/helpers.js +++ b/plugins/dbgate-plugin-firebird/src/backend/helpers.js @@ -1,3 +1,5 @@ +const { createBulkInsertStreamBase } = require('dbgate-tools'); + function getDataTypeString({ dataTypeCode, scale, length, precision }) { switch (dataTypeCode) { case 7: @@ -127,6 +129,34 @@ async function normalizeRow(row) { return Object.fromEntries(entries); } +function transformRow(row) { + return Object.fromEntries( + Object.entries(row).map(([key, value]) => { + if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/.test(value)) { + return [key, value.replace('T', ' ')]; + } + return [key, value]; + }) + ); +} + +function createFirebirdInsertStream(driver, stream, dbhan, name, options) { + const writable = createBulkInsertStreamBase(driver, stream, dbhan, name, options); + + writable.addRow = async row => { + const transformedRow = transformRow(row); + + if (writable.structure) { + writable.buffer.push(transformedRow); + } else { + writable.structure = transformedRow; + await writable.checkStructure(); + } + }; + + return writable; +} + module.exports = { getDataTypeString, getTriggerEventType, @@ -135,4 +165,5 @@ module.exports = { getTriggerCreateSql, blobStreamToString, normalizeRow, + createFirebirdInsertStream, }; From 0e0e8e9d18f54e4d11ec7cd4e6c2c105b5790b6b Mon Sep 17 00:00:00 2001 From: CI workflows Date: Thu, 12 Jun 2025 13:30:21 +0000 Subject: [PATCH 65/65] chore: auto-update github workflows --- .github/workflows/build-app-beta.yaml | 34 +++++++-------- .github/workflows/build-app-pro-beta.yaml | 36 ++++++++-------- .github/workflows/build-app-pro.yaml | 36 ++++++++-------- .github/workflows/build-app.yaml | 34 +++++++-------- .github/workflows/build-cloud-pro.yaml | 44 ++++++++++---------- .github/workflows/build-docker-pro.yaml | 20 ++++----- .github/workflows/build-docker.yaml | 22 +++++----- .github/workflows/build-npm-pro.yaml | 14 +++---- .github/workflows/build-npm.yaml | 12 +++--- .github/workflows/build-test-containers.yaml | 4 +- .github/workflows/diflow.yaml | 2 +- .github/workflows/e2e-pro.yaml | 16 +++---- .github/workflows/process-templates.yaml | 4 +- .github/workflows/run-tests.yaml | 18 ++++---- 14 files changed, 148 insertions(+), 148 deletions(-) diff --git a/.github/workflows/build-app-beta.yaml b/.github/workflows/build-app-beta.yaml index 9d10bdeda..b238d00c0 100644 --- a/.github/workflows/build-app-beta.yaml +++ b/.github/workflows/build-app-beta.yaml @@ -5,10 +5,10 @@ name: Electron app BETA 'on': push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+' + - v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+ jobs: build: - runs-on: '${{ matrix.os }}' + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: @@ -24,7 +24,7 @@ jobs: echo "PYTHON=/opt/homebrew/bin/python3.11" >> $GITHUB_ENV - name: Context env: - GITHUB_CONTEXT: '${{ toJson(github) }}' + GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -58,7 +58,7 @@ jobs: yarn printSecrets env: - GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' + GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} - name: fillPackagedPlugins run: | @@ -71,16 +71,16 @@ jobs: yarn run build:app env: - GH_TOKEN: '${{ secrets.GH_TOKEN }}' - WIN_CSC_LINK: '${{ secrets.WINCERT_2025 }}' - WIN_CSC_KEY_PASSWORD: '${{ secrets.WINCERT_2025_PASSWORD }}' - CSC_LINK: '${{ secrets.APPLECERT_CERTIFICATE }}' - CSC_KEY_PASSWORD: '${{ secrets.APPLECERT_PASSWORD }}' - APPLE_ID: '${{ secrets.APPLE_ID }}' - APPLE_TEAM_ID: '${{ secrets.APPLE_TEAM_ID }}' - APPLE_ID_PASSWORD: '${{ secrets.APPLE_ID_PASSWORD }}' - SNAPCRAFT_STORE_CREDENTIALS: '${{secrets.SNAPCRAFT_LOGIN}}' - APPLE_APP_SPECIFIC_PASSWORD: '${{secrets.APPLE_APP_SPECIFIC_PASSWORD}}' + GH_TOKEN: ${{ secrets.GH_TOKEN }} + WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }} + WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }} + CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }} + CSC_KEY_PASSWORD: ${{ secrets.APPLECERT_PASSWORD }} + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} + SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} + APPLE_APP_SPECIFIC_PASSWORD: ${{secrets.APPLE_APP_SPECIFIC_PASSWORD}} - name: Copy artifacts run: | mkdir artifacts @@ -111,16 +111,16 @@ jobs: - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: '${{ matrix.os }}' + name: ${{ matrix.os }} path: artifacts - name: Release uses: softprops/action-gh-release@v1 - if: 'startsWith(github.ref, ''refs/tags/'')' + if: startsWith(github.ref, 'refs/tags/') with: files: artifacts/** prerelease: true env: - GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Print content of notarization-error.log if: failure() && matrix.os == 'macos-14' run: | diff --git a/.github/workflows/build-app-pro-beta.yaml b/.github/workflows/build-app-pro-beta.yaml index d8d1140cc..c42910a0a 100644 --- a/.github/workflows/build-app-pro-beta.yaml +++ b/.github/workflows/build-app-pro-beta.yaml @@ -5,10 +5,10 @@ name: Electron app PREMIUM BETA 'on': push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+-premium-beta.[0-9]+' + - v[0-9]+.[0-9]+.[0-9]+-premium-beta.[0-9]+ jobs: build: - runs-on: '${{ matrix.os }}' + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: @@ -24,7 +24,7 @@ jobs: echo "PYTHON=/opt/homebrew/bin/python3.11" >> $GITHUB_ENV - name: Context env: - GITHUB_CONTEXT: '${{ toJson(github) }}' + GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -37,7 +37,7 @@ jobs: uses: actions/checkout@v2 with: repository: dbgate/dbgate-pro - token: '${{ secrets.GH_TOKEN }}' + token: ${{ secrets.GH_TOKEN }} path: dbgate-pro ref: ecea1eef17c69c56b0633317e24a68c5220a4810 - name: Merge dbgate/dbgate-pro @@ -88,7 +88,7 @@ jobs: yarn printSecrets env: - GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' + GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} - name: fillPackagedPlugins run: | cd .. @@ -102,16 +102,16 @@ jobs: yarn run build:app env: - GH_TOKEN: '${{ secrets.GH_TOKEN }}' - WIN_CSC_LINK: '${{ secrets.WINCERT_2025 }}' - WIN_CSC_KEY_PASSWORD: '${{ secrets.WINCERT_2025_PASSWORD }}' - CSC_LINK: '${{ secrets.APPLECERT_CERTIFICATE }}' - CSC_KEY_PASSWORD: '${{ secrets.APPLECERT_PASSWORD }}' - APPLE_ID: '${{ secrets.APPLE_ID }}' - APPLE_TEAM_ID: '${{ secrets.APPLE_TEAM_ID }}' - APPLE_ID_PASSWORD: '${{ secrets.APPLE_ID_PASSWORD }}' - SNAPCRAFT_STORE_CREDENTIALS: '${{secrets.SNAPCRAFT_LOGIN}}' - APPLE_APP_SPECIFIC_PASSWORD: '${{secrets.APPLE_APP_SPECIFIC_PASSWORD}}' + GH_TOKEN: ${{ secrets.GH_TOKEN }} + WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }} + WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }} + CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }} + CSC_KEY_PASSWORD: ${{ secrets.APPLECERT_PASSWORD }} + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} + SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} + APPLE_APP_SPECIFIC_PASSWORD: ${{secrets.APPLE_APP_SPECIFIC_PASSWORD}} - name: Copy artifacts run: | mkdir artifacts @@ -142,16 +142,16 @@ jobs: - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: '${{ matrix.os }}' + name: ${{ matrix.os }} path: artifacts - name: Release uses: softprops/action-gh-release@v1 - if: 'startsWith(github.ref, ''refs/tags/'')' + if: startsWith(github.ref, 'refs/tags/') with: files: artifacts/** prerelease: true env: - GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Print content of notarization-error.log if: failure() && matrix.os == 'macos-14' run: | diff --git a/.github/workflows/build-app-pro.yaml b/.github/workflows/build-app-pro.yaml index c8c28e26e..010b49a21 100644 --- a/.github/workflows/build-app-pro.yaml +++ b/.github/workflows/build-app-pro.yaml @@ -5,10 +5,10 @@ name: Electron app PREMIUM 'on': push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+' + - v[0-9]+.[0-9]+.[0-9]+ jobs: build: - runs-on: '${{ matrix.os }}' + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: @@ -24,7 +24,7 @@ jobs: echo "PYTHON=/opt/homebrew/bin/python3.11" >> $GITHUB_ENV - name: Context env: - GITHUB_CONTEXT: '${{ toJson(github) }}' + GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -37,7 +37,7 @@ jobs: uses: actions/checkout@v2 with: repository: dbgate/dbgate-pro - token: '${{ secrets.GH_TOKEN }}' + token: ${{ secrets.GH_TOKEN }} path: dbgate-pro ref: ecea1eef17c69c56b0633317e24a68c5220a4810 - name: Merge dbgate/dbgate-pro @@ -88,7 +88,7 @@ jobs: yarn printSecrets env: - GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' + GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} - name: fillPackagedPlugins run: | cd .. @@ -102,16 +102,16 @@ jobs: yarn run build:app env: - GH_TOKEN: '${{ secrets.GH_TOKEN }}' - WIN_CSC_LINK: '${{ secrets.WINCERT_2025 }}' - WIN_CSC_KEY_PASSWORD: '${{ secrets.WINCERT_2025_PASSWORD }}' - CSC_LINK: '${{ secrets.APPLECERT_CERTIFICATE }}' - CSC_KEY_PASSWORD: '${{ secrets.APPLECERT_PASSWORD }}' - APPLE_ID: '${{ secrets.APPLE_ID }}' - APPLE_TEAM_ID: '${{ secrets.APPLE_TEAM_ID }}' - APPLE_ID_PASSWORD: '${{ secrets.APPLE_ID_PASSWORD }}' - SNAPCRAFT_STORE_CREDENTIALS: '${{secrets.SNAPCRAFT_LOGIN}}' - APPLE_APP_SPECIFIC_PASSWORD: '${{secrets.APPLE_APP_SPECIFIC_PASSWORD}}' + GH_TOKEN: ${{ secrets.GH_TOKEN }} + WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }} + WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }} + CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }} + CSC_KEY_PASSWORD: ${{ secrets.APPLECERT_PASSWORD }} + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} + SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} + APPLE_APP_SPECIFIC_PASSWORD: ${{secrets.APPLE_APP_SPECIFIC_PASSWORD}} - name: Copy artifacts run: | mkdir artifacts @@ -142,16 +142,16 @@ jobs: - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: '${{ matrix.os }}' + name: ${{ matrix.os }} path: artifacts - name: Release uses: softprops/action-gh-release@v1 - if: 'startsWith(github.ref, ''refs/tags/'')' + if: startsWith(github.ref, 'refs/tags/') with: files: artifacts/** prerelease: false env: - GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Print content of notarization-error.log if: failure() && matrix.os == 'macos-14' run: | diff --git a/.github/workflows/build-app.yaml b/.github/workflows/build-app.yaml index bc4ae305b..db0785eac 100644 --- a/.github/workflows/build-app.yaml +++ b/.github/workflows/build-app.yaml @@ -5,10 +5,10 @@ name: Electron app 'on': push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+' + - v[0-9]+.[0-9]+.[0-9]+ jobs: build: - runs-on: '${{ matrix.os }}' + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: @@ -24,7 +24,7 @@ jobs: echo "PYTHON=/opt/homebrew/bin/python3.11" >> $GITHUB_ENV - name: Context env: - GITHUB_CONTEXT: '${{ toJson(github) }}' + GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -54,7 +54,7 @@ jobs: yarn printSecrets env: - GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' + GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} - name: fillPackagedPlugins run: | @@ -67,16 +67,16 @@ jobs: yarn run build:app env: - GH_TOKEN: '${{ secrets.GH_TOKEN }}' - WIN_CSC_LINK: '${{ secrets.WINCERT_2025 }}' - WIN_CSC_KEY_PASSWORD: '${{ secrets.WINCERT_2025_PASSWORD }}' - CSC_LINK: '${{ secrets.APPLECERT_CERTIFICATE }}' - CSC_KEY_PASSWORD: '${{ secrets.APPLECERT_PASSWORD }}' - APPLE_ID: '${{ secrets.APPLE_ID }}' - APPLE_TEAM_ID: '${{ secrets.APPLE_TEAM_ID }}' - APPLE_ID_PASSWORD: '${{ secrets.APPLE_ID_PASSWORD }}' - SNAPCRAFT_STORE_CREDENTIALS: '${{secrets.SNAPCRAFT_LOGIN}}' - APPLE_APP_SPECIFIC_PASSWORD: '${{secrets.APPLE_APP_SPECIFIC_PASSWORD}}' + GH_TOKEN: ${{ secrets.GH_TOKEN }} + WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }} + WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }} + CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }} + CSC_KEY_PASSWORD: ${{ secrets.APPLECERT_PASSWORD }} + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} + SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} + APPLE_APP_SPECIFIC_PASSWORD: ${{secrets.APPLE_APP_SPECIFIC_PASSWORD}} - name: generatePadFile run: | yarn generatePadFile @@ -114,16 +114,16 @@ jobs: - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: '${{ matrix.os }}' + name: ${{ matrix.os }} path: artifacts - name: Release uses: softprops/action-gh-release@v1 - if: 'startsWith(github.ref, ''refs/tags/'')' + if: startsWith(github.ref, 'refs/tags/') with: files: artifacts/** prerelease: false env: - GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Print content of notarization-error.log if: failure() && matrix.os == 'macos-14' run: | diff --git a/.github/workflows/build-cloud-pro.yaml b/.github/workflows/build-cloud-pro.yaml index 22b2c1911..b3a3f5e52 100644 --- a/.github/workflows/build-cloud-pro.yaml +++ b/.github/workflows/build-cloud-pro.yaml @@ -5,11 +5,11 @@ name: Cloud images PREMIUM 'on': push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+' - - 'v[0-9]+.[0-9]+.[0-9]+-packer-beta.[0-9]+' + - v[0-9]+.[0-9]+.[0-9]+ + - v[0-9]+.[0-9]+.[0-9]+-packer-beta.[0-9]+ jobs: build: - runs-on: '${{ matrix.os }}' + runs-on: ${{ matrix.os }} strategy: matrix: os: @@ -17,7 +17,7 @@ jobs: steps: - name: Context env: - GITHUB_CONTEXT: '${{ toJson(github) }}' + GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -37,7 +37,7 @@ jobs: uses: actions/checkout@v2 with: repository: dbgate/dbgate-pro - token: '${{ secrets.GH_TOKEN }}' + token: ${{ secrets.GH_TOKEN }} path: dbgate-pro ref: ecea1eef17c69c56b0633317e24a68c5220a4810 - name: Merge dbgate/dbgate-pro @@ -72,7 +72,7 @@ jobs: cd dbgate-merged yarn printSecrets env: - GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' + GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} - name: Prepare packer build run: | cd .. @@ -87,16 +87,16 @@ jobs: - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: '${{ matrix.os }}' + name: ${{ matrix.os }} path: artifacts - name: Release uses: softprops/action-gh-release@v1 - if: 'startsWith(github.ref, ''refs/tags/'')' + if: startsWith(github.ref, 'refs/tags/') with: files: artifacts/** prerelease: true env: - GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Run `packer init` for Azure run: | cd ../dbgate-merged/packer @@ -110,33 +110,33 @@ jobs: cd ../dbgate-merged/packer packer init ./aws-ubuntu.pkr.hcl env: - AWS_ACCESS_KEY_ID: '${{secrets.AWS_ACCESS_KEY_ID}}' - AWS_SECRET_ACCESS_KEY: '${{secrets.AWS_SECRET_ACCESS_KEY}}' - AWS_DEFAULT_REGION: '${{secrets.AWS_DEFAULT_REGION}}' + AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}} + AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}} + AWS_DEFAULT_REGION: ${{secrets.AWS_DEFAULT_REGION}} - name: Run `packer build` for AWS run: | cd ../dbgate-merged/packer packer build ./aws-ubuntu.pkr.hcl env: - AWS_ACCESS_KEY_ID: '${{secrets.AWS_ACCESS_KEY_ID}}' - AWS_SECRET_ACCESS_KEY: '${{secrets.AWS_SECRET_ACCESS_KEY}}' - AWS_DEFAULT_REGION: '${{secrets.AWS_DEFAULT_REGION}}' + AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}} + AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}} + AWS_DEFAULT_REGION: ${{secrets.AWS_DEFAULT_REGION}} - name: Delete old Azure VMs run: | cd ../dbgate-merged/packer chmod +x delete-old-azure-images.sh ./delete-old-azure-images.sh env: - AZURE_CLIENT_ID: '${{secrets.AZURE_CLIENT_ID}}' - AZURE_CLIENT_SECRET: '${{secrets.AZURE_CLIENT_SECRET}}' - AZURE_TENANT_ID: '${{secrets.AZURE_TENANT_ID}}' - AZURE_SUBSCRIPTION_ID: '${{secrets.AZURE_SUBSCRIPTION_ID}}' + AZURE_CLIENT_ID: ${{secrets.AZURE_CLIENT_ID}} + AZURE_CLIENT_SECRET: ${{secrets.AZURE_CLIENT_SECRET}} + AZURE_TENANT_ID: ${{secrets.AZURE_TENANT_ID}} + AZURE_SUBSCRIPTION_ID: ${{secrets.AZURE_SUBSCRIPTION_ID}} - name: Delete old AMIs (AWS) run: | cd ../dbgate-merged/packer chmod +x delete-old-amis.sh ./delete-old-amis.sh env: - AWS_ACCESS_KEY_ID: '${{secrets.AWS_ACCESS_KEY_ID}}' - AWS_SECRET_ACCESS_KEY: '${{secrets.AWS_SECRET_ACCESS_KEY}}' - AWS_DEFAULT_REGION: '${{secrets.AWS_DEFAULT_REGION}}' + AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}} + AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}} + AWS_DEFAULT_REGION: ${{secrets.AWS_DEFAULT_REGION}} diff --git a/.github/workflows/build-docker-pro.yaml b/.github/workflows/build-docker-pro.yaml index 3e4579096..48b655590 100644 --- a/.github/workflows/build-docker-pro.yaml +++ b/.github/workflows/build-docker-pro.yaml @@ -5,11 +5,11 @@ name: Docker image PREMIUM 'on': push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+' - - 'v[0-9]+.[0-9]+.[0-9]+-premium-beta.[0-9]+' + - v[0-9]+.[0-9]+.[0-9]+ + - v[0-9]+.[0-9]+.[0-9]+-premium-beta.[0-9]+ jobs: build: - runs-on: '${{ matrix.os }}' + runs-on: ${{ matrix.os }} strategy: matrix: os: @@ -17,7 +17,7 @@ jobs: steps: - name: Context env: - GITHUB_CONTEXT: '${{ toJson(github) }}' + GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -42,7 +42,7 @@ jobs: uses: actions/checkout@v2 with: repository: dbgate/dbgate-pro - token: '${{ secrets.GH_TOKEN }}' + token: ${{ secrets.GH_TOKEN }} path: dbgate-pro ref: ecea1eef17c69c56b0633317e24a68c5220a4810 - name: Merge dbgate/dbgate-pro @@ -83,7 +83,7 @@ jobs: yarn printSecrets env: - GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' + GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} - name: Prepare docker image run: | cd .. @@ -97,12 +97,12 @@ jobs: - name: Login to DockerHub uses: docker/login-action@v2 with: - username: '${{ secrets.DOCKER_USERNAME }}' - password: '${{ secrets.DOCKER_PASSWORD }}' + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and push uses: docker/build-push-action@v3 with: push: true context: ../dbgate-merged/docker - tags: '${{ steps.meta.outputs.tags }}' - platforms: 'linux/amd64,linux/arm64' + tags: ${{ steps.meta.outputs.tags }} + platforms: linux/amd64,linux/arm64 diff --git a/.github/workflows/build-docker.yaml b/.github/workflows/build-docker.yaml index 09c38abdf..644335b1d 100644 --- a/.github/workflows/build-docker.yaml +++ b/.github/workflows/build-docker.yaml @@ -5,11 +5,11 @@ name: Docker image Community 'on': push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+' - - 'v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+' + - v[0-9]+.[0-9]+.[0-9]+ + - v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+ jobs: build: - runs-on: '${{ matrix.os }}' + runs-on: ${{ matrix.os }} strategy: matrix: os: @@ -17,7 +17,7 @@ jobs: steps: - name: Context env: - GITHUB_CONTEXT: '${{ toJson(github) }}' + GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -70,7 +70,7 @@ jobs: yarn printSecrets env: - GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' + GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} - name: Prepare docker image run: | @@ -82,20 +82,20 @@ jobs: - name: Login to DockerHub uses: docker/login-action@v2 with: - username: '${{ secrets.DOCKER_USERNAME }}' - password: '${{ secrets.DOCKER_PASSWORD }}' + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and push uses: docker/build-push-action@v3 with: push: true context: ./docker - tags: '${{ steps.meta.outputs.tags }}' - platforms: 'linux/amd64,linux/arm64,linux/arm/v7' + tags: ${{ steps.meta.outputs.tags }} + platforms: linux/amd64,linux/arm64,linux/arm/v7 - name: Build and push alpine uses: docker/build-push-action@v3 with: push: true context: ./docker file: ./docker/Dockerfile-alpine - tags: '${{ steps.alpmeta.outputs.tags }}' - platforms: 'linux/amd64,linux/arm64,linux/arm/v7' + tags: ${{ steps.alpmeta.outputs.tags }} + platforms: linux/amd64,linux/arm64,linux/arm/v7 diff --git a/.github/workflows/build-npm-pro.yaml b/.github/workflows/build-npm-pro.yaml index 1e077de7b..3e1ed86d7 100644 --- a/.github/workflows/build-npm-pro.yaml +++ b/.github/workflows/build-npm-pro.yaml @@ -5,11 +5,11 @@ name: NPM packages PREMIUM 'on': push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+' - - 'v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+' + - v[0-9]+.[0-9]+.[0-9]+ + - v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+ jobs: build: - runs-on: '${{ matrix.os }}' + runs-on: ${{ matrix.os }} strategy: matrix: os: @@ -17,7 +17,7 @@ jobs: steps: - name: Context env: - GITHUB_CONTEXT: '${{ toJson(github) }}' + GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -30,7 +30,7 @@ jobs: uses: actions/checkout@v2 with: repository: dbgate/dbgate-pro - token: '${{ secrets.GH_TOKEN }}' + token: ${{ secrets.GH_TOKEN }} path: dbgate-pro ref: ecea1eef17c69c56b0633317e24a68c5220a4810 - name: Merge dbgate/dbgate-pro @@ -51,7 +51,7 @@ jobs: node adjustNpmPackageJsonPremium - name: Configure NPM token env: - NPM_TOKEN: '${{ secrets.NPM_TOKEN }}' + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} run: | cd .. cd dbgate-merged @@ -77,7 +77,7 @@ jobs: cd dbgate-merged yarn printSecrets env: - GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' + GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} - name: Publish dbgate-api-premium run: | cd .. diff --git a/.github/workflows/build-npm.yaml b/.github/workflows/build-npm.yaml index f204115dd..0c79e5097 100644 --- a/.github/workflows/build-npm.yaml +++ b/.github/workflows/build-npm.yaml @@ -5,11 +5,11 @@ name: NPM packages 'on': push: tags: - - 'v[0-9]+.[0-9]+.[0-9]+' - - 'v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+' + - v[0-9]+.[0-9]+.[0-9]+ + - v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+ jobs: build: - runs-on: '${{ matrix.os }}' + runs-on: ${{ matrix.os }} strategy: matrix: os: @@ -17,7 +17,7 @@ jobs: steps: - name: Context env: - GITHUB_CONTEXT: '${{ toJson(github) }}' + GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - uses: actions/checkout@v2 with: @@ -28,7 +28,7 @@ jobs: node-version: 18.x - name: Configure NPM token env: - NPM_TOKEN: '${{ secrets.NPM_TOKEN }}' + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} run: | npm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN}" - name: yarn install @@ -41,7 +41,7 @@ jobs: run: | yarn printSecrets env: - GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}' + GIST_UPLOAD_SECRET: ${{secrets.GIST_UPLOAD_SECRET}} - name: Publish types working-directory: packages/types run: | diff --git a/.github/workflows/build-test-containers.yaml b/.github/workflows/build-test-containers.yaml index af2c5bc81..90346f8f1 100644 --- a/.github/workflows/build-test-containers.yaml +++ b/.github/workflows/build-test-containers.yaml @@ -30,8 +30,8 @@ jobs: uses: docker/login-action@v2 with: registry: ghcr.io - username: '${{ github.actor }}' - password: '${{ secrets.GITHUB_TOKEN }}' + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Push mysql-ssh-login to GHCR run: | docker tag dbgate/mysql-ssh-login:latest ghcr.io/dbgate/mysql-ssh-login:latest diff --git a/.github/workflows/diflow.yaml b/.github/workflows/diflow.yaml index a9b8fbd91..064fd8be8 100644 --- a/.github/workflows/diflow.yaml +++ b/.github/workflows/diflow.yaml @@ -33,4 +33,4 @@ jobs: cd diflow node dist/diflow.js sync -r https://DIFLOW_GIT_SECRET@github.com/dbgate/dbgate-diflow-config.git -b master env: - DIFLOW_GIT_SECRET: '${{ secrets.DIFLOW_GIT_SECRET }}' + DIFLOW_GIT_SECRET: ${{ secrets.DIFLOW_GIT_SECRET }} diff --git a/.github/workflows/e2e-pro.yaml b/.github/workflows/e2e-pro.yaml index ae8dffb02..991a1540f 100644 --- a/.github/workflows/e2e-pro.yaml +++ b/.github/workflows/e2e-pro.yaml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v2 with: repository: dbgate/dbgate-pro - token: '${{ secrets.GH_TOKEN }}' + token: ${{ secrets.GH_TOKEN }} path: dbgate-pro ref: ecea1eef17c69c56b0633317e24a68c5220a4810 - name: Merge dbgate/dbgate-pro @@ -70,7 +70,7 @@ jobs: name: screenshots path: screenshots - name: Push E2E screenshots - if: '${{ github.ref_name == ''master'' }}' + if: ${{ github.ref_name == 'master' }} run: | git config --global user.email "info@dbgate.info" git config --global user.name "GitHub Actions" @@ -89,25 +89,25 @@ jobs: ports: - '16000:5432' mysql-cypress: - image: 'mysql:8.0.18' + image: mysql:8.0.18 ports: - '16004:3306' env: MYSQL_ROOT_PASSWORD: Pwd2020Db mysql-ssh-login: - image: 'ghcr.io/dbgate/mysql-ssh-login:latest' + image: ghcr.io/dbgate/mysql-ssh-login:latest ports: - '16012:22' mysql-ssh-keyfile: - image: 'ghcr.io/dbgate/mysql-ssh-keyfile:latest' + image: ghcr.io/dbgate/mysql-ssh-keyfile:latest ports: - '16008:22' dex: - image: 'ghcr.io/dbgate/dex:latest' + image: ghcr.io/dbgate/dex:latest ports: - '16009:5556' mongo: - image: 'mongo:4.0.12' + image: mongo:4.0.12 env: MONGO_INITDB_ROOT_USERNAME: root MONGO_INITDB_ROOT_PASSWORD: Pwd2020Db @@ -126,7 +126,7 @@ jobs: SA_PASSWORD: Pwd2020Db MSSQL_PID: Express oracle: - image: 'gvenzl/oracle-xe:21-slim' + image: gvenzl/oracle-xe:21-slim env: ORACLE_PASSWORD: Pwd2020Db ports: diff --git a/.github/workflows/process-templates.yaml b/.github/workflows/process-templates.yaml index 0e12a4be3..5baa3490e 100644 --- a/.github/workflows/process-templates.yaml +++ b/.github/workflows/process-templates.yaml @@ -15,7 +15,7 @@ jobs: - name: Check out repository uses: actions/checkout@v3 with: - token: '${{ secrets.WORKFLOW_CHANGE_ACCESS_TOKEN }}' + token: ${{ secrets.WORKFLOW_CHANGE_ACCESS_TOKEN }} - name: git pull run: | git pull @@ -47,5 +47,5 @@ jobs: - name: Push changes uses: ad-m/github-push-action@v0.6.0 with: - github_token: '${{ secrets.WORKFLOW_CHANGE_ACCESS_TOKEN }}' + github_token: ${{ secrets.WORKFLOW_CHANGE_ACCESS_TOKEN }} branch: master diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index fa6bbaa1b..3a62c5b8a 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -45,19 +45,19 @@ jobs: - uses: tanmen/jest-reporter@v1 if: always() with: - github-token: '${{ secrets.GITHUB_TOKEN }}' + github-token: ${{ secrets.GITHUB_TOKEN }} result-file: integration-tests/result.json action-name: Integration tests - uses: tanmen/jest-reporter@v1 if: always() with: - github-token: '${{ secrets.GITHUB_TOKEN }}' + github-token: ${{ secrets.GITHUB_TOKEN }} result-file: packages/filterparser/result.json action-name: Filter parser test results - uses: tanmen/jest-reporter@v1 if: always() with: - github-token: '${{ secrets.GITHUB_TOKEN }}' + github-token: ${{ secrets.GITHUB_TOKEN }} result-file: packages/datalib/result.json action-name: Datalib (perspectives) test results services: @@ -69,7 +69,7 @@ jobs: ports: - '15000:5432' mysql-integr: - image: 'mysql:8.0.18' + image: mysql:8.0.18 env: MYSQL_ROOT_PASSWORD: Pwd2020Db ports: @@ -83,27 +83,27 @@ jobs: ports: - '15002:1433' clickhouse-integr: - image: 'bitnami/clickhouse:24.8.4' + image: bitnami/clickhouse:24.8.4 env: CLICKHOUSE_ADMIN_PASSWORD: Pwd2020Db ports: - '15005:8123' oracle-integr: - image: 'gvenzl/oracle-xe:21-slim' + image: gvenzl/oracle-xe:21-slim env: ORACLE_PASSWORD: Pwd2020Db ports: - '15006:1521' cassandradb: - image: 'cassandra:5.0.2' + image: cassandra:5.0.2 ports: - '15942:9042' libsql: - image: 'ghcr.io/tursodatabase/libsql-server:latest' + image: ghcr.io/tursodatabase/libsql-server:latest ports: - '8080:8080' firebird: - image: 'firebirdsql/firebird:latest' + image: firebirdsql/firebird:latest env: FIREBIRD_DATABASE: mydatabase.fdb FIREBIRD_USER: dbuser