diff --git a/packages/types/dbinfo.d.ts b/packages/types/dbinfo.d.ts index 609669fa2..45511e271 100644 --- a/packages/types/dbinfo.d.ts +++ b/packages/types/dbinfo.d.ts @@ -132,7 +132,9 @@ export interface CallableObjectInfo extends SqlObjectInfo { export interface ProcedureInfo extends CallableObjectInfo {} -export interface FunctionInfo extends CallableObjectInfo {} +export interface FunctionInfo extends CallableObjectInfo { + returnType?: string; +} export interface TriggerInfo extends SqlObjectInfo {} diff --git a/packages/web/src/tabs/QueryTab.svelte b/packages/web/src/tabs/QueryTab.svelte index 731170c98..23b50e8a1 100644 --- a/packages/web/src/tabs/QueryTab.svelte +++ b/packages/web/src/tabs/QueryTab.svelte @@ -219,7 +219,7 @@ return null; } - return { ...driver.getQuerySplitterOptions('editor'), queryParameterStyle }; + return { ...driver.getQuerySplitterOptions('editor'), queryParameterStyle, allowDollarDollarString: false }; } async function executeCore(sql, startLine = 0) { diff --git a/plugins/dbgate-plugin-mysql/src/frontend/Dumper.js b/plugins/dbgate-plugin-mysql/src/frontend/Dumper.js index d5a41fff8..7878e1aa5 100644 --- a/plugins/dbgate-plugin-mysql/src/frontend/Dumper.js +++ b/plugins/dbgate-plugin-mysql/src/frontend/Dumper.js @@ -97,6 +97,46 @@ class Dumper extends SqlDumper { selectScopeIdentity() { this.put('^select ^last_insert_id()'); } + + callableTemplate(func) { + const parameters = (func.parameters || []).filter(x => x.parameterMode != 'RETURN'); + + const putParameters = (parameters, delimiter) => { + this.putCollection(delimiter, parameters || [], param => { + if (param.parameterMode == 'IN') { + this.putRaw('@' + param.parameterName); + } else { + this.putRaw('@' + param.parameterName + 'Output'); + } + }); + }; + + const putSetParamters = parameters => { + for (const param of parameters || []) { + if (param.parameterMode == 'IN') { + this.put('SET @%s = :%s', param.parameterName, param.parameterName); + this.endCommand(); + } + } + this.put('&n'); + }; + + if (func.objectTypeField == 'procedures') { + putSetParamters(func.parameters); + this.put('^call %f(&>&n', func); + putParameters(parameters, ',&n'); + this.put('&<&n)'); + this.endCommand(); + } + + if (func.objectTypeField == 'functions') { + putSetParamters(parameters); + this.put('^select %f(&>&n', func); + putParameters(parameters, ',&n'); + this.put('&<&n)'); + this.endCommand(); + } + } } module.exports = Dumper; diff --git a/plugins/dbgate-plugin-postgres/src/backend/Analyser.js b/plugins/dbgate-plugin-postgres/src/backend/Analyser.js index 90bb94ab8..bae89b4eb 100644 --- a/plugins/dbgate-plugin-postgres/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-postgres/src/backend/Analyser.js @@ -346,6 +346,7 @@ class Analyser extends DatabaseAnalyser { schemaName: func.schema_name, contentHash: func.hash_code, parameters: functionNameToParameters[`${func.schema_name}.${func.pure_name}`], + returnType: func.data_type, })), }; diff --git a/plugins/dbgate-plugin-postgres/src/frontend/Dumper.js b/plugins/dbgate-plugin-postgres/src/frontend/Dumper.js index 963fc1dc1..898f6167d 100644 --- a/plugins/dbgate-plugin-postgres/src/frontend/Dumper.js +++ b/plugins/dbgate-plugin-postgres/src/frontend/Dumper.js @@ -109,6 +109,57 @@ class Dumper extends SqlDumper { const column = table.columns && table.columns.find(x => x.autoIncrement); this.put("^SELECT currval(pg_get_serial_sequence('%f','%s'))", table, column ? column.columnName : null); } + + callableTemplate(func) { + const putDeclareParamters = parameters => { + for (const param of parameters.filter(i => i.parameterMode != 'RETURN')) { + if (param.parameterMode == 'IN') { + this.put('%s %s := :%s', param.parameterName, param.dataType, param.parameterName); + this.endCommand(); + } else { + this.put('%s %s', param.parameterName, param.dataType); + this.endCommand(); + } + } + this.put('&n'); + }; + + const putParameters = (parameters, delimiter) => { + this.putCollection(delimiter, parameters || [], param => { + this.putRaw(param.parameterName); + }); + }; + + if (func.objectTypeField == 'procedures') { + this.put('^do $$&n'); + this.put('^declare&n'); + putDeclareParamters(func.parameters); + this.put('^begin&n'); + this.put('^call %f(&>&n', func); + putParameters(func.parameters, ',&n'); + this.put('&<&n)'); + this.endCommand(); + this.put('&n'); + this.put('^end $$'); + this.endCommand(); + } + + if (func.objectTypeField == 'functions') { + this.put('^do $$&n'); + this.put('^declare&n'); + this.put('result %s', func.returnType); + this.endCommand(); + putDeclareParamters(func.parameters); + this.put('^begin&n'); + this.put('result := %f(&>&n', func); + putParameters(func.parameters, ',&n'); + this.put('&<&n)'); + this.endCommand(); + this.put('&n'); + this.put('^end $$'); + this.endCommand(); + } + } } module.exports = Dumper;