diff --git a/packages/sqltree/src/dumpSqlCommand.ts b/packages/sqltree/src/dumpSqlCommand.ts index b16f3c34d..0c3f2c667 100644 --- a/packages/sqltree/src/dumpSqlCommand.ts +++ b/packages/sqltree/src/dumpSqlCommand.ts @@ -62,10 +62,13 @@ export function dumpSqlSelect(dmp: SqlDumper, cmd: Select) { } export function dumpSqlUpdate(dmp: SqlDumper, cmd: Update) { - dmp.put('^update '); - dumpSqlSourceRef(dmp, cmd.from); - - dmp.put('&n^set '); + if (cmd.alterTableUpdateSyntax) { + dmp.put('^alter ^table %f &n^update ', cmd.from?.name); + } else { + dmp.put('^update '); + dumpSqlSourceRef(dmp, cmd.from); + dmp.put('&n^set '); + } dmp.put('&>'); dmp.putCollection(', ', cmd.fields, col => { dmp.put('%i=', col.targetColumn); @@ -81,8 +84,14 @@ export function dumpSqlUpdate(dmp: SqlDumper, cmd: Update) { } export function dumpSqlDelete(dmp: SqlDumper, cmd: Delete) { - dmp.put('^delete ^from '); - dumpSqlSourceRef(dmp, cmd.from); + if (cmd.alterTableDeleteSyntax) { + dmp.put('^alter ^table '); + dumpSqlSourceRef(dmp, cmd.from); + dmp.put('^delete '); + } else { + dmp.put('^delete ^from '); + dumpSqlSourceRef(dmp, cmd.from); + } if (cmd.where) { dmp.put('&n^where '); diff --git a/packages/sqltree/src/types.ts b/packages/sqltree/src/types.ts index 44a1e2ea7..c2fe24674 100644 --- a/packages/sqltree/src/types.ts +++ b/packages/sqltree/src/types.ts @@ -26,12 +26,17 @@ export interface Update { fields: UpdateField[]; from: FromDefinition; where?: Condition; + // ALTER TABLE xxx UPDATE col1=val1 - syntax for ClickHouse + alterTableUpdateSyntax?: boolean; } export interface Delete { commandType: 'delete'; from: FromDefinition; where?: Condition; + + // ALTER TABLE xxx DELETE - syntax for ClickHouse + alterTableDeleteSyntax?: boolean; } export interface Insert { diff --git a/packages/tools/src/driverBase.ts b/packages/tools/src/driverBase.ts index a16206688..e67433fc3 100644 --- a/packages/tools/src/driverBase.ts +++ b/packages/tools/src/driverBase.ts @@ -173,4 +173,8 @@ export const driverBase = { parseSqlNull: true, parseHexAsBuffer: true, }, + + createSaveChangeSetScript(changeSet, dbinfo, defaultCreator) { + return defaultCreator(changeSet, dbinfo); + }, }; diff --git a/packages/types/engines.d.ts b/packages/types/engines.d.ts index d054e6e1f..477bb784e 100644 --- a/packages/types/engines.d.ts +++ b/packages/types/engines.d.ts @@ -223,6 +223,11 @@ export interface EngineDriver extends FilterBehaviourProvider { getCollectionExportQueryJson(collection: string, condition: any, sort?: CollectionSortDefinition): {}; getScriptTemplates(objectTypeField: keyof DatabaseInfo): { label: string; scriptTemplate: string }[]; getScriptTemplateContent(scriptTemplate: string, props: any): Promise; + createSaveChangeSetScript( + changeSet: any, + dbinfo: DatabaseInfo, + defaultCreator: (changeSet: any, dbinfo: DatabaseInfo) => any + ): any[]; analyserClass?: any; dumperClass?: any; diff --git a/packages/web/src/tabs/TableDataTab.svelte b/packages/web/src/tabs/TableDataTab.svelte index d2094f96d..83a6f13df 100644 --- a/packages/web/src/tabs/TableDataTab.svelte +++ b/packages/web/src/tabs/TableDataTab.svelte @@ -71,10 +71,7 @@ changeSetToSql, createChangeSet, createGridCache, - createGridConfig, getDeleteCascades, - TableFormViewDisplay, - TableGridDisplay, } from 'dbgate-datalib'; import { findEngineDriver } from 'dbgate-tools'; import { reloadDataCacheFunc } from 'dbgate-datalib'; @@ -160,7 +157,11 @@ export function save() { const driver = findEngineDriver($connection, $extensions); - const script = changeSetToSql($changeSetStore?.value, $dbinfo); + + const script = driver.createSaveChangeSetScript($changeSetStore?.value, $dbinfo, () => + changeSetToSql($changeSetStore?.value, $dbinfo) + ); + const deleteCascades = getDeleteCascades($changeSetStore?.value, $dbinfo); const sql = scriptToSql(driver, script); const deleteCascadesScripts = _.map(deleteCascades, ({ title, commands }) => ({ diff --git a/plugins/dbgate-plugin-clickhouse/src/frontend/driver.js b/plugins/dbgate-plugin-clickhouse/src/frontend/driver.js index 819490ae1..242c858df 100644 --- a/plugins/dbgate-plugin-clickhouse/src/frontend/driver.js +++ b/plugins/dbgate-plugin-clickhouse/src/frontend/driver.js @@ -1,6 +1,7 @@ const { driverBase } = require('dbgate-tools'); const Dumper = require('./Dumper'); const { mysqlSplitterOptions } = require('dbgate-query-splitter/lib/options'); +const _cloneDeepWith = require('lodash/cloneDeepWith'); /** @type {import('dbgate-types').SqlDialect} */ const dialect = { @@ -40,6 +41,35 @@ const driver = { usage == 'editor' ? { ...mysqlSplitterOptions, ignoreComments: true, preventSingleLineSplit: true } : mysqlSplitterOptions, + + createSaveChangeSetScript(changeSet, dbinfo, defaultCreator) { + function removeConditionSource(cmd) { + cmd.where = _cloneDeepWith(cmd.where, (expr) => { + if (expr.exprType == 'column') { + return { + ...expr, + source: undefined, + }; + } + }); + } + + const res = defaultCreator(changeSet, dbinfo); + for (const cmd of res) { + if (cmd.commandType == 'update') { + cmd.alterTableUpdateSyntax = true; + removeConditionSource(cmd); + } + if (cmd.commandType == 'delete') { + const table = dbinfo?.tables?.find((x) => x.pureName == cmd?.from?.name?.pureName); + if (table?.tableEngine != 'MergeTree') { + cmd.alterTableDeleteSyntax = true; + } + removeConditionSource(cmd); + } + } + return res; + }, }; module.exports = driver;