diff --git a/plugins/dbgate-plugin-mysql/src/backend/Analyser.js b/plugins/dbgate-plugin-mysql/src/backend/Analyser.js index ae68e0ce2..9419e507b 100644 --- a/plugins/dbgate-plugin-mysql/src/backend/Analyser.js +++ b/plugins/dbgate-plugin-mysql/src/backend/Analyser.js @@ -60,6 +60,18 @@ function getColumnInfo( }; } +function getParametersSqlString(parameters = []) { + if (!parameters?.length) return ''; + + return parameters + .map(i => { + const mode = i.parameterMode ? `${i.parameterMode} ` : ''; + const dataType = i.dataType ? ` ${i.dataType.toUpperCase()}` : ''; + return mode + i.parameterName + dataType; + }) + .join(', '); +} + class Analyser extends DatabaseAnalyser { constructor(dbhan, driver, version) { super(dbhan, driver, version); @@ -114,6 +126,24 @@ class Analyser extends DatabaseAnalyser { this.feedback({ analysingMessage: 'Loading programmables' }); const programmables = await this.analyserQuery('programmables', ['procedures', 'functions']); + const parameters = await this.analyserQuery('parameters', ['procedures', 'functions']); + + const functionParameters = parameters.rows.filter(x => x.routineType == 'FUNCTION'); + const functionNameToParameters = functionParameters.reduce((acc, row) => { + if (!acc[row.pureName]) acc[row.pureName] = []; + + acc[row.pureName].push(row); + return acc; + }, {}); + + const procedureParameters = parameters.rows.filter(x => x.routineType == 'PROCEDURE'); + const procedureNameToParameters = procedureParameters.reduce((acc, row) => { + if (!acc[row.pureName]) acc[row.pureName] = []; + + acc[row.pureName].push(row); + return acc; + }, {}); + this.feedback({ analysingMessage: 'Loading view texts' }); const viewTexts = await this.getViewTexts(views.rows.map(x => x.pureName)); this.feedback({ analysingMessage: 'Loading indexes' }); @@ -174,20 +204,26 @@ class Analyser extends DatabaseAnalyser { .map(x => _.omit(x, ['objectType'])) .map(x => ({ ...x, - createSql: `DELIMITER //\n\nCREATE PROCEDURE \`${x.pureName}\`()\n${x.routineDefinition}\n\nDELIMITER ;\n`, + createSql: `DELIMITER //\n\nCREATE PROCEDURE \`${x.pureName}\`(${getParametersSqlString( + procedureNameToParameters[x.pureName] + )})\n${x.routineDefinition}\n\nDELIMITER ;\n`, objectId: x.pureName, contentHash: _.isDate(x.modifyDate) ? x.modifyDate.toISOString() : x.modifyDate, + parameters: procedureNameToParameters[x.pureName], })), functions: programmables.rows .filter(x => x.objectType == 'FUNCTION') .map(x => _.omit(x, ['objectType'])) .map(x => ({ ...x, - createSql: `CREATE FUNCTION \`${x.pureName}\`()\nRETURNS ${x.returnDataType} ${ - x.isDeterministic == 'YES' ? 'DETERMINISTIC' : 'NOT DETERMINISTIC' - }\n${x.routineDefinition}`, + createSql: `CREATE FUNCTION \`${x.pureName}\`(${getParametersSqlString( + functionNameToParameters[x.pureName].filter(i => i.parameterMode !== 'RETURN') + )})\nRETURNS ${x.returnDataType} ${x.isDeterministic == 'YES' ? 'DETERMINISTIC' : 'NOT DETERMINISTIC'}\n${ + x.routineDefinition + }`, objectId: x.pureName, contentHash: _.isDate(x.modifyDate) ? x.modifyDate.toISOString() : x.modifyDate, + parameters: functionNameToParameters[x.pureName], })), }; this.feedback({ analysingMessage: null }); diff --git a/plugins/dbgate-plugin-mysql/src/backend/sql/index.js b/plugins/dbgate-plugin-mysql/src/backend/sql/index.js index 4839071e7..8c3e095fa 100644 --- a/plugins/dbgate-plugin-mysql/src/backend/sql/index.js +++ b/plugins/dbgate-plugin-mysql/src/backend/sql/index.js @@ -10,6 +10,7 @@ const procedureModifications = require('./procedureModifications'); const functionModifications = require('./functionModifications'); const uniqueNames = require('./uniqueNames'); const viewTexts = require('./viewTexts'); +const parameters = require('./parameters'); module.exports = { columns, @@ -19,6 +20,7 @@ module.exports = { tableModifications, views, programmables, + parameters, procedureModifications, functionModifications, indexes, diff --git a/plugins/dbgate-plugin-mysql/src/backend/sql/parameters.js b/plugins/dbgate-plugin-mysql/src/backend/sql/parameters.js new file mode 100644 index 000000000..d884ea3d7 --- /dev/null +++ b/plugins/dbgate-plugin-mysql/src/backend/sql/parameters.js @@ -0,0 +1,22 @@ +module.exports = ` +SELECT + r.SPECIFIC_NAME AS pureName, + CASE + WHEN COALESCE(NULLIF(PARAMETER_MODE, ''), 'RETURN') = 'RETURN' THEN 'Return' + ELSE PARAMETER_NAME + END AS parameterName, + p.CHARACTER_MAXIMUM_LENGTH AS charMaxLength, + p.NUMERIC_PRECISION AS numericPrecision, + p.NUMERIC_SCALE AS numericScale, + p.DTD_IDENTIFIER AS dataType, + COALESCE(NULLIF(PARAMETER_MODE, ''), 'RETURN') AS parameterMode, + r.ROUTINE_TYPE AS routineType -- Function or Procedure +FROM + information_schema.PARAMETERS p +JOIN + information_schema.ROUTINES r +ON + p.SPECIFIC_NAME = r.SPECIFIC_NAME +WHERE + r.ROUTINE_SCHEMA = '#DATABASE#' AND r.ROUTINE_NAME =OBJECT_ID_CONDITION +`;