mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-27 04:25:59 +00:00
feat: stored procedures and funciton parameters support for mssql
This commit is contained in:
18
packages/types/dbinfo.d.ts
vendored
18
packages/types/dbinfo.d.ts
vendored
@@ -35,7 +35,7 @@ export interface IndexInfo extends ColumnsConstraintInfo {
|
|||||||
isUnique: boolean;
|
isUnique: boolean;
|
||||||
// indexType: 'normal' | 'clustered' | 'xml' | 'spatial' | 'fulltext';
|
// indexType: 'normal' | 'clustered' | 'xml' | 'spatial' | 'fulltext';
|
||||||
indexType?: string;
|
indexType?: string;
|
||||||
// condition for filtered index (SQL Server)
|
// condition for filtered index (SQL Server)
|
||||||
filterDefinition?: string;
|
filterDefinition?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,9 +118,23 @@ export interface ViewInfo extends SqlObjectInfo {
|
|||||||
columns: ColumnInfo[];
|
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 {
|
export interface FunctionInfo extends SqlObjectInfo {
|
||||||
|
parameters?: ParameterInfo[];
|
||||||
// returnDataType?: string;
|
// returnDataType?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
{#if (isExpanded || isExpandedBySearch) && subItemsComponent}
|
{#if (isExpanded || isExpandedBySearch) && subItemsComponent}
|
||||||
<div class="subitems">
|
<div class="subitems">
|
||||||
<svelte:component
|
<svelte:component
|
||||||
this={subItemsComponent}
|
this={subItemsComponent(data)}
|
||||||
{data}
|
{data}
|
||||||
{filter}
|
{filter}
|
||||||
{passProps}
|
{passProps}
|
||||||
|
|||||||
18
packages/web/src/appobj/ParameterAppObject.svelte
Normal file
18
packages/web/src/appobj/ParameterAppObject.svelte
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<script lang="ts" context="module">
|
||||||
|
export const extractKey = ({ columnName }) => columnName;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import AppObjectCore from './AppObjectCore.svelte';
|
||||||
|
|
||||||
|
export let data;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<AppObjectCore
|
||||||
|
{...$$restProps}
|
||||||
|
{data}
|
||||||
|
title={data.pureName}
|
||||||
|
extInfo={data.isOutputParameter ? `data.fullDataType OUT` : data.fullDataType}
|
||||||
|
icon={'icon parameter'}
|
||||||
|
disableHover
|
||||||
|
/>
|
||||||
15
packages/web/src/appobj/SubProcedureParamList.svelte
Normal file
15
packages/web/src/appobj/SubProcedureParamList.svelte
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import AppObjectList from './AppObjectList.svelte';
|
||||||
|
import * as parameterAppObject from './ParameterAppObject.svelte';
|
||||||
|
|
||||||
|
export let data;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<AppObjectList
|
||||||
|
list={data.parameters ||
|
||||||
|
[].map(parameter => ({
|
||||||
|
...data,
|
||||||
|
...parameter,
|
||||||
|
}))}
|
||||||
|
module={parameterAppObject}
|
||||||
|
/>
|
||||||
@@ -63,6 +63,7 @@
|
|||||||
'icon open-in-new': 'mdi mdi-open-in-new',
|
'icon open-in-new': 'mdi mdi-open-in-new',
|
||||||
'icon add-folder': 'mdi mdi-folder-plus-outline',
|
'icon add-folder': 'mdi mdi-folder-plus-outline',
|
||||||
'icon add-column': 'mdi mdi-table-column-plus-after',
|
'icon add-column': 'mdi mdi-table-column-plus-after',
|
||||||
|
'icon parameter': 'mdi mdi-at',
|
||||||
|
|
||||||
'icon window-restore': 'mdi mdi-window-restore',
|
'icon window-restore': 'mdi mdi-window-restore',
|
||||||
'icon window-maximize': 'mdi mdi-window-maximize',
|
'icon window-maximize': 'mdi mdi-window-maximize',
|
||||||
|
|||||||
@@ -251,7 +251,7 @@
|
|||||||
<AppObjectList
|
<AppObjectList
|
||||||
list={connectionsWithParent}
|
list={connectionsWithParent}
|
||||||
module={connectionAppObject}
|
module={connectionAppObject}
|
||||||
subItemsComponent={SubDatabaseList}
|
subItemsComponent={() => SubDatabaseList}
|
||||||
expandOnClick
|
expandOnClick
|
||||||
isExpandable={data => $openedConnections.includes(data._id) && !data.singleDatabase}
|
isExpandable={data => $openedConnections.includes(data._id) && !data.singleDatabase}
|
||||||
{filter}
|
{filter}
|
||||||
@@ -275,7 +275,7 @@
|
|||||||
<AppObjectList
|
<AppObjectList
|
||||||
list={connectionsWithoutParent}
|
list={connectionsWithoutParent}
|
||||||
module={connectionAppObject}
|
module={connectionAppObject}
|
||||||
subItemsComponent={SubDatabaseList}
|
subItemsComponent={() => SubDatabaseList}
|
||||||
expandOnClick
|
expandOnClick
|
||||||
isExpandable={data => $openedConnections.includes(data._id) && !data.singleDatabase}
|
isExpandable={data => $openedConnections.includes(data._id) && !data.singleDatabase}
|
||||||
{filter}
|
{filter}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@
|
|||||||
import AppObjectListHandler from './AppObjectListHandler.svelte';
|
import AppObjectListHandler from './AppObjectListHandler.svelte';
|
||||||
import { matchDatabaseObjectAppObject } from '../appobj/appObjectTools';
|
import { matchDatabaseObjectAppObject } from '../appobj/appObjectTools';
|
||||||
import FocusedConnectionInfoWidget from './FocusedConnectionInfoWidget.svelte';
|
import FocusedConnectionInfoWidget from './FocusedConnectionInfoWidget.svelte';
|
||||||
|
import SubProcedureParamList from '../appobj/SubProcedureParamList.svelte';
|
||||||
|
|
||||||
export let conid;
|
export let conid;
|
||||||
export let database;
|
export let database;
|
||||||
@@ -232,9 +233,16 @@
|
|||||||
.map(x => ({ ...x, conid, database }))}
|
.map(x => ({ ...x, conid, database }))}
|
||||||
module={databaseObjectAppObject}
|
module={databaseObjectAppObject}
|
||||||
groupFunc={data => getObjectTypeFieldLabel(data.objectTypeField, driver)}
|
groupFunc={data => getObjectTypeFieldLabel(data.objectTypeField, driver)}
|
||||||
subItemsComponent={SubColumnParamList}
|
subItemsComponent={data =>
|
||||||
|
data.objectTypeField == 'procedures' || data.objectTypeField == 'functions'
|
||||||
|
? SubProcedureParamList
|
||||||
|
: SubColumnParamList}
|
||||||
isExpandable={data =>
|
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}
|
expandIconFunc={chevronExpandIcon}
|
||||||
{filter}
|
{filter}
|
||||||
passProps={{
|
passProps={{
|
||||||
|
|||||||
@@ -31,6 +31,18 @@ function simplifyComutedExpression(expr) {
|
|||||||
return 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({
|
function getColumnInfo({
|
||||||
isNullable,
|
isNullable,
|
||||||
isIdentity,
|
isIdentity,
|
||||||
@@ -43,13 +55,12 @@ function getColumnInfo({
|
|||||||
defaultConstraint,
|
defaultConstraint,
|
||||||
computedExpression,
|
computedExpression,
|
||||||
}) {
|
}) {
|
||||||
let fullDataType = dataType;
|
const fullDataType = getFullDataTypeName({
|
||||||
if (charMaxLength && isTypeString(dataType)) {
|
dataType,
|
||||||
fullDataType = `${dataType}(${charMaxLength < 0 ? 'MAX' : charMaxLength})`;
|
charMaxLength,
|
||||||
}
|
numericPrecision,
|
||||||
if (numericPrecision && numericScale && isTypeNumeric(dataType)) {
|
numericScale,
|
||||||
fullDataType = `${dataType}(${numericPrecision},${numericScale})`;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (defaultValue) {
|
if (defaultValue) {
|
||||||
defaultValue = defaultValue.trim();
|
defaultValue = defaultValue.trim();
|
||||||
@@ -116,7 +127,11 @@ class MsSqlAnalyser extends DatabaseAnalyser {
|
|||||||
this.feedback({ analysingMessage: 'Loading views' });
|
this.feedback({ analysingMessage: 'Loading views' });
|
||||||
const viewsRows = await this.analyserQuery('views', ['views']);
|
const viewsRows = await this.analyserQuery('views', ['views']);
|
||||||
this.feedback({ analysingMessage: 'Loading procedures & functions' });
|
this.feedback({ analysingMessage: 'Loading procedures & functions' });
|
||||||
|
|
||||||
const programmableRows = await this.analyserQuery('programmables', ['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' });
|
this.feedback({ analysingMessage: 'Loading view columns' });
|
||||||
const viewColumnRows = await this.analyserQuery('viewColumns', ['views']);
|
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),
|
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
|
const procedures = programmableRows.rows
|
||||||
.filter(x => x.sqlObjectType.trim() == 'P')
|
.filter(x => x.sqlObjectType.trim() == 'P')
|
||||||
.map(row => ({
|
.map(row => ({
|
||||||
...row,
|
...row,
|
||||||
contentHash: row.modifyDate && row.modifyDate.toISOString(),
|
contentHash: row.modifyDate && row.modifyDate.toISOString(),
|
||||||
createSql: getCreateSql(row),
|
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
|
const functions = programmableRows.rows
|
||||||
.filter(x => ['FN', 'IF', 'TF'].includes(x.sqlObjectType.trim()))
|
.filter(x => ['FN', 'IF', 'TF'].includes(x.sqlObjectType.trim()))
|
||||||
.map(row => ({
|
.map(row => ({
|
||||||
...row,
|
...row,
|
||||||
contentHash: row.modifyDate && row.modifyDate.toISOString(),
|
contentHash: row.modifyDate && row.modifyDate.toISOString(),
|
||||||
createSql: getCreateSql(row),
|
createSql: getCreateSql(row),
|
||||||
|
parameters: functionToParameters[row.objectId],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.feedback({ analysingMessage: null });
|
this.feedback({ analysingMessage: null });
|
||||||
|
|||||||
@@ -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;
|
||||||
|
`;
|
||||||
@@ -7,6 +7,8 @@ const modifications = require('./modifications');
|
|||||||
const loadSqlCode = require('./loadSqlCode');
|
const loadSqlCode = require('./loadSqlCode');
|
||||||
const views = require('./views');
|
const views = require('./views');
|
||||||
const programmables = require('./programmables');
|
const programmables = require('./programmables');
|
||||||
|
const proceduresParameters = require('./proceduresParameters');
|
||||||
|
const functionParameters = require('./functionParameters');
|
||||||
const viewColumns = require('./viewColumns');
|
const viewColumns = require('./viewColumns');
|
||||||
const indexes = require('./indexes');
|
const indexes = require('./indexes');
|
||||||
const indexcols = require('./indexcols');
|
const indexcols = require('./indexcols');
|
||||||
@@ -20,6 +22,8 @@ module.exports = {
|
|||||||
loadSqlCode,
|
loadSqlCode,
|
||||||
views,
|
views,
|
||||||
programmables,
|
programmables,
|
||||||
|
proceduresParameters,
|
||||||
|
functionParameters,
|
||||||
viewColumns,
|
viewColumns,
|
||||||
indexes,
|
indexes,
|
||||||
indexcols,
|
indexcols,
|
||||||
|
|||||||
@@ -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;
|
||||||
|
`;
|
||||||
Reference in New Issue
Block a user