diff --git a/packages/types/dbinfo.d.ts b/packages/types/dbinfo.d.ts
index b5b59d1ec..680bbb236 100644
--- a/packages/types/dbinfo.d.ts
+++ b/packages/types/dbinfo.d.ts
@@ -35,7 +35,7 @@ export interface IndexInfo extends ColumnsConstraintInfo {
isUnique: boolean;
// indexType: 'normal' | 'clustered' | 'xml' | 'spatial' | 'fulltext';
indexType?: string;
- // condition for filtered index (SQL Server)
+ // condition for filtered index (SQL Server)
filterDefinition?: string;
}
@@ -118,9 +118,23 @@ export interface ViewInfo extends SqlObjectInfo {
columns: ColumnInfo[];
}
-export interface ProcedureInfo extends SqlObjectInfo {}
+export interface ParameterInfo {
+ objectId?: string | number;
+ parentObjectId?: string | number;
+ pureName: string;
+ dataType: string;
+ fullDataType: string;
+ maxLength?: number;
+ precision?: number;
+ scale?: string;
+ isOutputParameter?: boolean;
+}
+export interface ProcedureInfo extends SqlObjectInfo {
+ parameters?: ParameterInfo[];
+}
export interface FunctionInfo extends SqlObjectInfo {
+ parameters?: ParameterInfo[];
// returnDataType?: string;
}
diff --git a/packages/web/src/appobj/AppObjectListItem.svelte b/packages/web/src/appobj/AppObjectListItem.svelte
index 2b61b232b..395127e63 100644
--- a/packages/web/src/appobj/AppObjectListItem.svelte
+++ b/packages/web/src/appobj/AppObjectListItem.svelte
@@ -62,7 +62,7 @@
{#if (isExpanded || isExpandedBySearch) && subItemsComponent}
+ export const extractKey = ({ columnName }) => columnName;
+
+
+
+
+
diff --git a/packages/web/src/appobj/SubProcedureParamList.svelte b/packages/web/src/appobj/SubProcedureParamList.svelte
new file mode 100644
index 000000000..206321594
--- /dev/null
+++ b/packages/web/src/appobj/SubProcedureParamList.svelte
@@ -0,0 +1,15 @@
+
+
+ ({
+ ...data,
+ ...parameter,
+ }))}
+ module={parameterAppObject}
+/>
diff --git a/packages/web/src/icons/FontIcon.svelte b/packages/web/src/icons/FontIcon.svelte
index 90cdae967..1f8d6930f 100644
--- a/packages/web/src/icons/FontIcon.svelte
+++ b/packages/web/src/icons/FontIcon.svelte
@@ -63,6 +63,7 @@
'icon open-in-new': 'mdi mdi-open-in-new',
'icon add-folder': 'mdi mdi-folder-plus-outline',
'icon add-column': 'mdi mdi-table-column-plus-after',
+ 'icon parameter': 'mdi mdi-at',
'icon window-restore': 'mdi mdi-window-restore',
'icon window-maximize': 'mdi mdi-window-maximize',
diff --git a/packages/web/src/widgets/ConnectionList.svelte b/packages/web/src/widgets/ConnectionList.svelte
index 4b84fe07d..61ba93bc3 100644
--- a/packages/web/src/widgets/ConnectionList.svelte
+++ b/packages/web/src/widgets/ConnectionList.svelte
@@ -251,7 +251,7 @@
SubDatabaseList}
expandOnClick
isExpandable={data => $openedConnections.includes(data._id) && !data.singleDatabase}
{filter}
@@ -275,7 +275,7 @@
SubDatabaseList}
expandOnClick
isExpandable={data => $openedConnections.includes(data._id) && !data.singleDatabase}
{filter}
diff --git a/packages/web/src/widgets/SqlObjectList.svelte b/packages/web/src/widgets/SqlObjectList.svelte
index a71d4cbc4..04151597b 100644
--- a/packages/web/src/widgets/SqlObjectList.svelte
+++ b/packages/web/src/widgets/SqlObjectList.svelte
@@ -52,6 +52,7 @@
import AppObjectListHandler from './AppObjectListHandler.svelte';
import { matchDatabaseObjectAppObject } from '../appobj/appObjectTools';
import FocusedConnectionInfoWidget from './FocusedConnectionInfoWidget.svelte';
+ import SubProcedureParamList from '../appobj/SubProcedureParamList.svelte';
export let conid;
export let database;
@@ -232,9 +233,16 @@
.map(x => ({ ...x, conid, database }))}
module={databaseObjectAppObject}
groupFunc={data => getObjectTypeFieldLabel(data.objectTypeField, driver)}
- subItemsComponent={SubColumnParamList}
+ subItemsComponent={data =>
+ data.objectTypeField == 'procedures' || data.objectTypeField == 'functions'
+ ? SubProcedureParamList
+ : SubColumnParamList}
isExpandable={data =>
- data.objectTypeField == 'tables' || data.objectTypeField == 'views' || data.objectTypeField == 'matviews'}
+ data.objectTypeField == 'tables' ||
+ data.objectTypeField == 'views' ||
+ data.objectTypeField == 'matviews' ||
+ ((data.objectTypeField == 'procedures' || data.objectTypeField == 'functions') &&
+ !!data.parameters?.length)}
expandIconFunc={chevronExpandIcon}
{filter}
passProps={{
diff --git a/plugins/dbgate-plugin-mssql/src/backend/MsSqlAnalyser.js b/plugins/dbgate-plugin-mssql/src/backend/MsSqlAnalyser.js
index 1eac0ea32..72b4060f9 100644
--- a/plugins/dbgate-plugin-mssql/src/backend/MsSqlAnalyser.js
+++ b/plugins/dbgate-plugin-mssql/src/backend/MsSqlAnalyser.js
@@ -31,6 +31,18 @@ function simplifyComutedExpression(expr) {
return expr;
}
+function getFullDataTypeName({ dataType, charMaxLength, numericScale, numericPrecision }) {
+ let fullDataType = dataType;
+ if (charMaxLength && isTypeString(dataType)) {
+ fullDataType = `${dataType}(${charMaxLength < 0 ? 'MAX' : charMaxLength})`;
+ }
+ if (numericPrecision && numericScale && isTypeNumeric(dataType)) {
+ fullDataType = `${dataType}(${numericPrecision},${numericScale})`;
+ }
+
+ return fullDataType;
+}
+
function getColumnInfo({
isNullable,
isIdentity,
@@ -43,13 +55,12 @@ function getColumnInfo({
defaultConstraint,
computedExpression,
}) {
- let fullDataType = dataType;
- if (charMaxLength && isTypeString(dataType)) {
- fullDataType = `${dataType}(${charMaxLength < 0 ? 'MAX' : charMaxLength})`;
- }
- if (numericPrecision && numericScale && isTypeNumeric(dataType)) {
- fullDataType = `${dataType}(${numericPrecision},${numericScale})`;
- }
+ const fullDataType = getFullDataTypeName({
+ dataType,
+ charMaxLength,
+ numericPrecision,
+ numericScale,
+ });
if (defaultValue) {
defaultValue = defaultValue.trim();
@@ -116,7 +127,11 @@ class MsSqlAnalyser extends DatabaseAnalyser {
this.feedback({ analysingMessage: 'Loading views' });
const viewsRows = await this.analyserQuery('views', ['views']);
this.feedback({ analysingMessage: 'Loading procedures & functions' });
+
const programmableRows = await this.analyserQuery('programmables', ['procedures', 'functions']);
+ const prodceureParameterRows = await this.analyserQuery('proceduresParameters');
+ const functionParameterRows = await this.analyserQuery('functionParameters');
+
this.feedback({ analysingMessage: 'Loading view columns' });
const viewColumnRows = await this.analyserQuery('viewColumns', ['views']);
@@ -157,20 +172,46 @@ class MsSqlAnalyser extends DatabaseAnalyser {
columns: viewColumnRows.rows.filter(col => col.objectId == row.objectId).map(getColumnInfo),
}));
+ const prodceureParameter = prodceureParameterRows.rows.map(row => ({
+ ...row,
+ fullDataType: getFullDataTypeName(row),
+ }));
+
+ const prodceureToParameters = prodceureParameter.reduce((acc, parameter) => {
+ if (!acc[parameter.parentObjectId]) acc[parameter.parentObjectId] = [];
+ acc[parameter.parentObjectId].push(parameter);
+
+ return acc;
+ }, {});
+
const procedures = programmableRows.rows
.filter(x => x.sqlObjectType.trim() == 'P')
.map(row => ({
...row,
contentHash: row.modifyDate && row.modifyDate.toISOString(),
createSql: getCreateSql(row),
+ parameters: prodceureToParameters[row.objectId],
}));
+ const functionParameters = functionParameterRows.rows.map(row => ({
+ ...row,
+ fullDataType: getFullDataTypeName(row),
+ }));
+
+ const functionToParameters = functionParameters.reduce((acc, parameter) => {
+ if (!acc[parameter.parentObjectId]) acc[parameter.parentObjectId] = [];
+
+ acc[parameter.parentObjectId].push(parameter);
+ return acc;
+ }, {});
+
const functions = programmableRows.rows
.filter(x => ['FN', 'IF', 'TF'].includes(x.sqlObjectType.trim()))
.map(row => ({
...row,
contentHash: row.modifyDate && row.modifyDate.toISOString(),
createSql: getCreateSql(row),
+ parameters: functionToParameters[row.objectId],
}));
this.feedback({ analysingMessage: null });
diff --git a/plugins/dbgate-plugin-mssql/src/backend/sql/functionParameters.js b/plugins/dbgate-plugin-mssql/src/backend/sql/functionParameters.js
new file mode 100644
index 000000000..f7b40dc72
--- /dev/null
+++ b/plugins/dbgate-plugin-mssql/src/backend/sql/functionParameters.js
@@ -0,0 +1,26 @@
+module.exports = `
+SELECT
+ o.object_id as parentObjectId,
+ p.object_id AS parameterObjectId,
+ CASE
+ WHEN p.name IS NULL OR LTRIM(RTRIM(p.name)) = '' THEN
+ '@Output'
+ ELSE
+ p.name
+ END AS pureName,
+ TYPE_NAME(p.user_type_id) AS dataType,
+ p.max_length AS charMaxLength,
+ p.precision AS precision,
+ p.scale AS scale,
+ p.is_output AS isOutputParameter,
+ p.parameter_id AS parameterIndex
+FROM
+ sys.objects o
+JOIN
+ sys.parameters p ON o.object_id = p.object_id
+WHERE
+ o.type IN ('FN', 'IF', 'TF')
+ORDER BY
+ p.object_id,
+ p.parameter_id;
+`;
diff --git a/plugins/dbgate-plugin-mssql/src/backend/sql/index.js b/plugins/dbgate-plugin-mssql/src/backend/sql/index.js
index 563b8d080..6352b6a9b 100644
--- a/plugins/dbgate-plugin-mssql/src/backend/sql/index.js
+++ b/plugins/dbgate-plugin-mssql/src/backend/sql/index.js
@@ -7,6 +7,8 @@ const modifications = require('./modifications');
const loadSqlCode = require('./loadSqlCode');
const views = require('./views');
const programmables = require('./programmables');
+const proceduresParameters = require('./proceduresParameters');
+const functionParameters = require('./functionParameters');
const viewColumns = require('./viewColumns');
const indexes = require('./indexes');
const indexcols = require('./indexcols');
@@ -20,6 +22,8 @@ module.exports = {
loadSqlCode,
views,
programmables,
+ proceduresParameters,
+ functionParameters,
viewColumns,
indexes,
indexcols,
diff --git a/plugins/dbgate-plugin-mssql/src/backend/sql/proceduresParameters.js b/plugins/dbgate-plugin-mssql/src/backend/sql/proceduresParameters.js
new file mode 100644
index 000000000..00c7b2c9f
--- /dev/null
+++ b/plugins/dbgate-plugin-mssql/src/backend/sql/proceduresParameters.js
@@ -0,0 +1,21 @@
+module.exports = `
+SELECT
+ o.object_id as parentObjectId,
+ p.object_id as objectId,
+ p.name AS pureName,
+ TYPE_NAME(p.user_type_id) AS dataType,
+ p.max_length AS charMaxLength,
+ p.precision AS precision,
+ p.scale AS scale,
+ p.is_output AS isOutputParameter,
+ p.parameter_id AS parameterIndex
+FROM
+ sys.objects o
+JOIN
+ sys.parameters p ON o.object_id = p.object_id
+WHERE
+ o.type = 'P'
+ORDER BY
+ o.object_id,
+ p.parameter_id;
+`;