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,