mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-25 01:45:59 +00:00
Merge branch 'master' of https://github.com/dbgate/dbgate
This commit is contained in:
@@ -10,6 +10,14 @@ function flatSource() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function flatSourceParameters() {
|
||||||
|
return _.flatten(
|
||||||
|
engines.map(engine =>
|
||||||
|
(engine.parameters || []).map(parameter => [engine.label, parameter.testName, parameter, engine])
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const obj1Match = expect.objectContaining({
|
const obj1Match = expect.objectContaining({
|
||||||
pureName: 'obj1',
|
pureName: 'obj1',
|
||||||
});
|
});
|
||||||
@@ -78,7 +86,7 @@ describe('Object analyse', () => {
|
|||||||
const structure2 = await driver.analyseIncremental(conn, structure1);
|
const structure2 = await driver.analyseIncremental(conn, structure1);
|
||||||
expect(structure2[type].length).toEqual(0);
|
expect(structure2[type].length).toEqual(0);
|
||||||
|
|
||||||
await driver.query(conn, structure1[type][0].createSql, { discardResult: true });
|
await driver.script(conn, structure1[type][0].createSql);
|
||||||
|
|
||||||
const structure3 = await driver.analyseIncremental(conn, structure2);
|
const structure3 = await driver.analyseIncremental(conn, structure2);
|
||||||
|
|
||||||
@@ -86,4 +94,45 @@ describe('Object analyse', () => {
|
|||||||
expect(structure3[type][0]).toEqual(type.includes('views') ? view1Match : obj1Match);
|
expect(structure3[type][0]).toEqual(type.includes('views') ? view1Match : obj1Match);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test.each(flatSourceParameters())(
|
||||||
|
'Test parameters simple analyse - %s - %s',
|
||||||
|
testWrapper(async (conn, driver, testName, parameter, engine) => {
|
||||||
|
for (const sql of initSql) await driver.query(conn, sql, { discardResult: true });
|
||||||
|
for (const sql of engine.parametersOtherSql) await driver.query(conn, sql, { discardResult: true });
|
||||||
|
|
||||||
|
await driver.query(conn, parameter.create, { discardResult: true });
|
||||||
|
const structure = await driver.analyseFull(conn);
|
||||||
|
|
||||||
|
const parameters = structure[parameter.objectTypeField].find(x => x.pureName == 'obj1').parameters;
|
||||||
|
|
||||||
|
expect(parameters.length).toEqual(parameter.list.length);
|
||||||
|
for (let i = 0; i < parameters.length; i += 1) {
|
||||||
|
expect(parameters[i]).toEqual(expect.objectContaining(parameter.list[i]));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
test.each(flatSourceParameters())(
|
||||||
|
'Test parameters create SQL - %s - %s',
|
||||||
|
testWrapper(async (conn, driver, testName, parameter, engine) => {
|
||||||
|
for (const sql of initSql) await driver.query(conn, sql, { discardResult: true });
|
||||||
|
for (const sql of engine.parametersOtherSql) await driver.query(conn, sql, { discardResult: true });
|
||||||
|
|
||||||
|
await driver.query(conn, parameter.create, { discardResult: true });
|
||||||
|
const structure1 = await driver.analyseFull(conn);
|
||||||
|
await driver.query(conn, parameter.drop, { discardResult: true });
|
||||||
|
|
||||||
|
const obj = structure1[parameter.objectTypeField].find(x => x.pureName == 'obj1');
|
||||||
|
await driver.script(conn, obj.createSql);
|
||||||
|
|
||||||
|
const structure2 = await driver.analyseFull(conn);
|
||||||
|
const parameters = structure2[parameter.objectTypeField].find(x => x.pureName == 'obj1').parameters;
|
||||||
|
|
||||||
|
expect(parameters.length).toEqual(parameter.list.length);
|
||||||
|
for (let i = 0; i < parameters.length; i += 1) {
|
||||||
|
expect(parameters[i]).toEqual(expect.objectContaining(parameter.list[i]));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,7 +28,16 @@ const engines = [
|
|||||||
port: 15001,
|
port: 15001,
|
||||||
},
|
},
|
||||||
// skipOnCI: true,
|
// skipOnCI: true,
|
||||||
objects: [views],
|
objects: [
|
||||||
|
views,
|
||||||
|
{
|
||||||
|
type: 'procedures',
|
||||||
|
create1: 'CREATE PROCEDURE obj1() BEGIN SELECT * FROM t1; END',
|
||||||
|
create2: 'CREATE PROCEDURE obj2() BEGIN SELECT * FROM t2; END',
|
||||||
|
drop1: 'DROP PROCEDURE obj1',
|
||||||
|
drop2: 'DROP PROCEDURE obj2',
|
||||||
|
},
|
||||||
|
],
|
||||||
dbSnapshotBySeconds: true,
|
dbSnapshotBySeconds: true,
|
||||||
dumpFile: 'data/chinook-mysql.sql',
|
dumpFile: 'data/chinook-mysql.sql',
|
||||||
dumpChecks: [
|
dumpChecks: [
|
||||||
@@ -37,6 +46,68 @@ const engines = [
|
|||||||
res: '25',
|
res: '25',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
parametersOtherSql: ['CREATE PROCEDURE obj2(a int, b int) BEGIN SELECT * FROM t1; END'],
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
testName: 'simple',
|
||||||
|
create: 'CREATE PROCEDURE obj1(a int) BEGIN SELECT * FROM t1; END',
|
||||||
|
drop: 'DROP PROCEDURE obj1',
|
||||||
|
objectTypeField: 'procedures',
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
parameterName: 'a',
|
||||||
|
parameterMode: 'IN',
|
||||||
|
dataType: 'int',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: 'paramTypes',
|
||||||
|
create: 'CREATE PROCEDURE obj1(a int, b varchar(50), c numeric(10,2)) BEGIN SELECT * FROM t1; END',
|
||||||
|
drop: 'DROP PROCEDURE obj1',
|
||||||
|
objectTypeField: 'procedures',
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
parameterName: 'a',
|
||||||
|
parameterMode: 'IN',
|
||||||
|
dataType: 'int',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameterName: 'b',
|
||||||
|
parameterMode: 'IN',
|
||||||
|
dataType: 'varchar(50)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameterName: 'c',
|
||||||
|
parameterMode: 'IN',
|
||||||
|
dataType: 'decimal(10,2)',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: 'paramModes',
|
||||||
|
create: 'CREATE PROCEDURE obj1(IN a int, OUT b int, INOUT c int) BEGIN SELECT * FROM t1; END',
|
||||||
|
drop: 'DROP PROCEDURE obj1',
|
||||||
|
objectTypeField: 'procedures',
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
parameterName: 'a',
|
||||||
|
parameterMode: 'IN',
|
||||||
|
dataType: 'int',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameterName: 'b',
|
||||||
|
parameterMode: 'OUT',
|
||||||
|
dataType: 'int',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameterName: 'c',
|
||||||
|
parameterMode: 'INOUT',
|
||||||
|
dataType: 'int',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'MariaDB',
|
label: 'MariaDB',
|
||||||
@@ -105,6 +176,94 @@ const engines = [
|
|||||||
res: '25',
|
res: '25',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
|
parametersOtherSql: ['CREATE PROCEDURE obj2(a integer, b integer) LANGUAGE SQL AS $$ select * from t1 $$'],
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
testName: 'simple',
|
||||||
|
create: 'CREATE PROCEDURE obj1(a integer) LANGUAGE SQL AS $$ select * from t1 $$',
|
||||||
|
drop: 'DROP PROCEDURE obj1',
|
||||||
|
objectTypeField: 'procedures',
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
parameterName: 'a',
|
||||||
|
parameterMode: 'IN',
|
||||||
|
dataType: 'integer',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: 'dataTypes',
|
||||||
|
create:
|
||||||
|
'CREATE PROCEDURE obj1(a integer, b varchar(20), c numeric(18,2)) LANGUAGE SQL AS $$ select * from t1 $$',
|
||||||
|
drop: 'DROP PROCEDURE obj1',
|
||||||
|
objectTypeField: 'procedures',
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
parameterName: 'a',
|
||||||
|
parameterMode: 'IN',
|
||||||
|
dataType: 'integer',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameterName: 'b',
|
||||||
|
parameterMode: 'IN',
|
||||||
|
dataType: 'varchar',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameterName: 'c',
|
||||||
|
parameterMode: 'IN',
|
||||||
|
dataType: 'numeric',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: 'paramModes',
|
||||||
|
create: 'CREATE PROCEDURE obj1(IN a integer, INOUT b integer) LANGUAGE SQL AS $$ select * from t1 $$',
|
||||||
|
drop: 'DROP PROCEDURE obj1',
|
||||||
|
objectTypeField: 'procedures',
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
parameterName: 'a',
|
||||||
|
parameterMode: 'IN',
|
||||||
|
dataType: 'integer',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameterName: 'b',
|
||||||
|
parameterMode: 'INOUT',
|
||||||
|
dataType: 'integer',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: 'paramModesFunction',
|
||||||
|
objectTypeField: 'functions',
|
||||||
|
create: `
|
||||||
|
create or replace function obj1(
|
||||||
|
out min_len int,
|
||||||
|
out max_len int)
|
||||||
|
language plpgsql
|
||||||
|
as $$
|
||||||
|
begin
|
||||||
|
select min(id),
|
||||||
|
max(id)
|
||||||
|
into min_len, max_len
|
||||||
|
from t1;
|
||||||
|
end;$$`,
|
||||||
|
drop: 'DROP FUNCTION obj1',
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
parameterName: 'min_len',
|
||||||
|
parameterMode: 'OUT',
|
||||||
|
dataType: 'integer',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameterName: 'max_len',
|
||||||
|
parameterMode: 'OUT',
|
||||||
|
dataType: 'integer',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'SQL Server',
|
label: 'SQL Server',
|
||||||
@@ -129,6 +288,63 @@ const engines = [
|
|||||||
drop2: 'DROP PROCEDURE obj2',
|
drop2: 'DROP PROCEDURE obj2',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
parametersOtherSql: ['CREATE PROCEDURE obj2 (@p1 int, @p2 int) AS SELECT id from t1'],
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
testName: 'simple',
|
||||||
|
create: 'CREATE PROCEDURE obj1 (@param1 int) AS SELECT id from t1',
|
||||||
|
drop: 'DROP PROCEDURE obj1',
|
||||||
|
objectTypeField: 'procedures',
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
parameterName: '@param1',
|
||||||
|
parameterMode: 'IN',
|
||||||
|
dataType: 'int',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: 'dataTypes',
|
||||||
|
create: 'CREATE PROCEDURE obj1 (@p1 bit, @p2 nvarchar(20), @p3 decimal(18,2), @p4 float) AS SELECT id from t1',
|
||||||
|
drop: 'DROP PROCEDURE obj1',
|
||||||
|
objectTypeField: 'procedures',
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
parameterName: '@p1',
|
||||||
|
parameterMode: 'IN',
|
||||||
|
dataType: 'bit',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameterName: '@p2',
|
||||||
|
parameterMode: 'IN',
|
||||||
|
dataType: 'nvarchar(20)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameterName: '@p3',
|
||||||
|
parameterMode: 'IN',
|
||||||
|
dataType: 'decimal(18,2)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parameterName: '@p4',
|
||||||
|
parameterMode: 'IN',
|
||||||
|
dataType: 'float',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: 'outputParam',
|
||||||
|
create: 'CREATE PROCEDURE obj1 (@p1 int OUTPUT) AS SELECT id from t1',
|
||||||
|
drop: 'DROP PROCEDURE obj1',
|
||||||
|
objectTypeField: 'procedures',
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
parameterName: '@p1',
|
||||||
|
parameterMode: 'OUT',
|
||||||
|
dataType: 'int',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
supportSchemas: true,
|
supportSchemas: true,
|
||||||
supportRenameSqlObject: true,
|
supportRenameSqlObject: true,
|
||||||
defaultSchemaName: 'dbo',
|
defaultSchemaName: 'dbo',
|
||||||
@@ -188,10 +404,10 @@ const engines = [
|
|||||||
|
|
||||||
const filterLocal = [
|
const filterLocal = [
|
||||||
// filter local testing
|
// filter local testing
|
||||||
'-MySQL',
|
'MySQL',
|
||||||
'-MariaDB',
|
'-MariaDB',
|
||||||
'-PostgreSQL',
|
'-PostgreSQL',
|
||||||
'SQL Server',
|
'-SQL Server',
|
||||||
'-SQLite',
|
'-SQLite',
|
||||||
'-CockroachDB',
|
'-CockroachDB',
|
||||||
'-ClickHouse',
|
'-ClickHouse',
|
||||||
|
|||||||
16
packages/types/dbinfo.d.ts
vendored
16
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,21 @@ export interface ViewInfo extends SqlObjectInfo {
|
|||||||
columns: ColumnInfo[];
|
columns: ColumnInfo[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProcedureInfo extends SqlObjectInfo {}
|
export type ParameterMode = 'IN' | 'OUT' | 'INOUT' | 'RETURN';
|
||||||
|
|
||||||
|
export interface ParameterInfo {
|
||||||
|
schemaName: string;
|
||||||
|
parameterName?: string;
|
||||||
|
pureName: string;
|
||||||
|
dataType: string;
|
||||||
|
parameterMode?: ParameterMode;
|
||||||
|
}
|
||||||
|
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.parameterName}
|
||||||
|
extInfo={data.parameterMode && data.parameterMode !== 'IN' ? `${data.dataType} ${data.parameterMode}` : data.dataType}
|
||||||
|
icon={'icon parameter'}
|
||||||
|
disableHover
|
||||||
|
/>
|
||||||
14
packages/web/src/appobj/SubProcedureParamList.svelte
Normal file
14
packages/web/src/appobj/SubProcedureParamList.svelte
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<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',
|
||||||
|
|||||||
@@ -274,7 +274,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}
|
||||||
@@ -298,7 +298,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;
|
||||||
@@ -238,9 +239,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 procedureParameterRows = 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 procedureParameter = procedureParameterRows.rows.map(row => ({
|
||||||
|
...row,
|
||||||
|
dataType: getFullDataTypeName(row),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const prodceureToParameters = procedureParameter.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,
|
||||||
|
dataType: 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,47 @@
|
|||||||
|
module.exports = `
|
||||||
|
SELECT
|
||||||
|
o.object_id as parentObjectId,
|
||||||
|
p.object_id AS parameterObjectId,
|
||||||
|
o.name as pureName,
|
||||||
|
CASE
|
||||||
|
WHEN p.name IS NULL OR LTRIM(RTRIM(p.name)) = '' THEN
|
||||||
|
'@Output'
|
||||||
|
ELSE
|
||||||
|
p.name
|
||||||
|
END AS parameterName,
|
||||||
|
TYPE_NAME(p.user_type_id) AS dataType,
|
||||||
|
CASE
|
||||||
|
WHEN TYPE_NAME(p.user_type_id) = 'nvarchar' THEN p.max_length / 2
|
||||||
|
ELSE p.max_length
|
||||||
|
END AS charMaxLength,
|
||||||
|
CASE
|
||||||
|
WHEN p.is_output = 1 THEN 'OUT'
|
||||||
|
ELSE 'IN'
|
||||||
|
END AS parameterMode,
|
||||||
|
CASE
|
||||||
|
WHEN TYPE_NAME(p.user_type_id) IN ('numeric', 'decimal') THEN p.precision
|
||||||
|
ELSE NULL
|
||||||
|
END AS numericPrecision,
|
||||||
|
CASE
|
||||||
|
WHEN TYPE_NAME(p.user_type_id) IN ('numeric', 'decimal') THEN p.scale
|
||||||
|
ELSE NULL
|
||||||
|
END AS numericScale,
|
||||||
|
CASE
|
||||||
|
WHEN p.is_output = 1 THEN 'OUT'
|
||||||
|
ELSE 'IN'
|
||||||
|
END AS parameterMode,
|
||||||
|
p.parameter_id AS parameterIndex,
|
||||||
|
s.name as schemaName
|
||||||
|
FROM
|
||||||
|
sys.objects o
|
||||||
|
JOIN
|
||||||
|
sys.parameters p ON o.object_id = p.object_id
|
||||||
|
INNER JOIN
|
||||||
|
sys.schemas s ON s.schema_id=o.schema_id
|
||||||
|
WHERE
|
||||||
|
o.type IN ('FN', 'IF', 'TF')
|
||||||
|
and o.object_id =OBJECT_ID_CONDITION and s.name =SCHEMA_NAME_CONDITION
|
||||||
|
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,38 @@
|
|||||||
|
module.exports = `
|
||||||
|
SELECT
|
||||||
|
o.object_id as parentObjectId,
|
||||||
|
p.object_id as objectId,
|
||||||
|
o.name as pureName,
|
||||||
|
p.name AS parameterName,
|
||||||
|
TYPE_NAME(p.user_type_id) AS dataType,
|
||||||
|
CASE
|
||||||
|
WHEN TYPE_NAME(p.user_type_id) = 'nvarchar' THEN p.max_length / 2
|
||||||
|
ELSE p.max_length
|
||||||
|
END AS charMaxLength,
|
||||||
|
CASE
|
||||||
|
WHEN p.is_output = 1 THEN 'OUT'
|
||||||
|
ELSE 'IN'
|
||||||
|
END AS parameterMode,
|
||||||
|
CASE
|
||||||
|
WHEN TYPE_NAME(p.user_type_id) IN ('numeric', 'decimal') THEN p.precision
|
||||||
|
ELSE NULL
|
||||||
|
END AS numericPrecision,
|
||||||
|
CASE
|
||||||
|
WHEN TYPE_NAME(p.user_type_id) IN ('numeric', 'decimal') THEN p.scale
|
||||||
|
ELSE NULL
|
||||||
|
END AS numericScale,
|
||||||
|
p.parameter_id AS parameterIndex,
|
||||||
|
s.name as schemaName
|
||||||
|
FROM
|
||||||
|
sys.objects o
|
||||||
|
JOIN
|
||||||
|
sys.parameters p ON o.object_id = p.object_id
|
||||||
|
INNER JOIN
|
||||||
|
sys.schemas s ON s.schema_id=o.schema_id
|
||||||
|
WHERE
|
||||||
|
o.type = 'P'
|
||||||
|
and o.object_id =OBJECT_ID_CONDITION and s.name =SCHEMA_NAME_CONDITION
|
||||||
|
ORDER BY
|
||||||
|
o.object_id,
|
||||||
|
p.parameter_id;
|
||||||
|
`;
|
||||||
@@ -15,6 +15,11 @@ function quoteDefaultValue(value) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeTypeName(typeName) {
|
||||||
|
if (/int\(\d+\)/.test(typeName)) return 'int';
|
||||||
|
return typeName;
|
||||||
|
}
|
||||||
|
|
||||||
function getColumnInfo(
|
function getColumnInfo(
|
||||||
{
|
{
|
||||||
isNullable,
|
isNullable,
|
||||||
@@ -60,6 +65,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 {
|
class Analyser extends DatabaseAnalyser {
|
||||||
constructor(dbhan, driver, version) {
|
constructor(dbhan, driver, version) {
|
||||||
super(dbhan, driver, version);
|
super(dbhan, driver, version);
|
||||||
@@ -114,6 +131,30 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
this.feedback({ analysingMessage: 'Loading programmables' });
|
this.feedback({ analysingMessage: 'Loading programmables' });
|
||||||
const programmables = await this.analyserQuery('programmables', ['procedures', 'functions']);
|
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.schemaName}.${row.pureName}`]) acc[`${row.schemaName}.${row.pureName}`] = [];
|
||||||
|
|
||||||
|
acc[`${row.schemaName}.${row.pureName}`].push({
|
||||||
|
...row,
|
||||||
|
dataType: normalizeTypeName(row.dataType),
|
||||||
|
});
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const procedureParameters = parameters.rows.filter(x => x.routineType == 'PROCEDURE');
|
||||||
|
const procedureNameToParameters = procedureParameters.reduce((acc, row) => {
|
||||||
|
if (!acc[`${row.schemaName}.${row.pureName}`]) acc[`${row.schemaName}.${row.pureName}`] = [];
|
||||||
|
|
||||||
|
acc[`${row.schemaName}.${row.pureName}`].push({
|
||||||
|
...row,
|
||||||
|
dataType: normalizeTypeName(row.dataType),
|
||||||
|
});
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
this.feedback({ analysingMessage: 'Loading view texts' });
|
this.feedback({ analysingMessage: 'Loading view texts' });
|
||||||
const viewTexts = await this.getViewTexts(views.rows.map(x => x.pureName));
|
const viewTexts = await this.getViewTexts(views.rows.map(x => x.pureName));
|
||||||
this.feedback({ analysingMessage: 'Loading indexes' });
|
this.feedback({ analysingMessage: 'Loading indexes' });
|
||||||
@@ -174,20 +215,26 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
.map(x => _.omit(x, ['objectType']))
|
.map(x => _.omit(x, ['objectType']))
|
||||||
.map(x => ({
|
.map(x => ({
|
||||||
...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.schemaName}.${x.pureName}`]
|
||||||
|
)})\n${x.routineDefinition}\n\nDELIMITER ;\n`,
|
||||||
objectId: x.pureName,
|
objectId: x.pureName,
|
||||||
contentHash: _.isDate(x.modifyDate) ? x.modifyDate.toISOString() : x.modifyDate,
|
contentHash: _.isDate(x.modifyDate) ? x.modifyDate.toISOString() : x.modifyDate,
|
||||||
|
parameters: procedureNameToParameters[`${x.schemaName}.${x.pureName}`],
|
||||||
})),
|
})),
|
||||||
functions: programmables.rows
|
functions: programmables.rows
|
||||||
.filter(x => x.objectType == 'FUNCTION')
|
.filter(x => x.objectType == 'FUNCTION')
|
||||||
.map(x => _.omit(x, ['objectType']))
|
.map(x => _.omit(x, ['objectType']))
|
||||||
.map(x => ({
|
.map(x => ({
|
||||||
...x,
|
...x,
|
||||||
createSql: `CREATE FUNCTION \`${x.pureName}\`()\nRETURNS ${x.returnDataType} ${
|
createSql: `CREATE FUNCTION \`${x.pureName}\`(${getParametersSqlString(
|
||||||
x.isDeterministic == 'YES' ? 'DETERMINISTIC' : 'NOT DETERMINISTIC'
|
functionNameToParameters[`${x.schemaName}.${x.pureName}`]?.filter(i => i.parameterMode !== 'RETURN')
|
||||||
}\n${x.routineDefinition}`,
|
)})\nRETURNS ${x.returnDataType} ${x.isDeterministic == 'YES' ? 'DETERMINISTIC' : 'NOT DETERMINISTIC'}\n${
|
||||||
|
x.routineDefinition
|
||||||
|
}`,
|
||||||
objectId: x.pureName,
|
objectId: x.pureName,
|
||||||
contentHash: _.isDate(x.modifyDate) ? x.modifyDate.toISOString() : x.modifyDate,
|
contentHash: _.isDate(x.modifyDate) ? x.modifyDate.toISOString() : x.modifyDate,
|
||||||
|
parameters: functionNameToParameters[`${x.schemaName}.${x.pureName}`],
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
this.feedback({ analysingMessage: null });
|
this.feedback({ analysingMessage: null });
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ const procedureModifications = require('./procedureModifications');
|
|||||||
const functionModifications = require('./functionModifications');
|
const functionModifications = require('./functionModifications');
|
||||||
const uniqueNames = require('./uniqueNames');
|
const uniqueNames = require('./uniqueNames');
|
||||||
const viewTexts = require('./viewTexts');
|
const viewTexts = require('./viewTexts');
|
||||||
|
const parameters = require('./parameters');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
columns,
|
columns,
|
||||||
@@ -19,6 +20,7 @@ module.exports = {
|
|||||||
tableModifications,
|
tableModifications,
|
||||||
views,
|
views,
|
||||||
programmables,
|
programmables,
|
||||||
|
parameters,
|
||||||
procedureModifications,
|
procedureModifications,
|
||||||
functionModifications,
|
functionModifications,
|
||||||
indexes,
|
indexes,
|
||||||
|
|||||||
26
plugins/dbgate-plugin-mysql/src/backend/sql/parameters.js
Normal file
26
plugins/dbgate-plugin-mysql/src/backend/sql/parameters.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
module.exports = `
|
||||||
|
SELECT
|
||||||
|
r.ROUTINE_SCHEMA AS schemaName,
|
||||||
|
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
|
||||||
|
p.ORDINAL_POSITION AS ordinalPosition
|
||||||
|
FROM
|
||||||
|
information_schema.PARAMETERS p
|
||||||
|
JOIN
|
||||||
|
information_schema.ROUTINES r
|
||||||
|
ON
|
||||||
|
p.SPECIFIC_NAME = r.SPECIFIC_NAME AND r.ROUTINE_SCHEMA = p.SPECIFIC_SCHEMA
|
||||||
|
WHERE
|
||||||
|
r.ROUTINE_SCHEMA = '#DATABASE#' AND r.ROUTINE_NAME =OBJECT_ID_CONDITION
|
||||||
|
ORDER BY
|
||||||
|
r.ROUTINE_SCHEMA, r.SPECIFIC_NAME, p.ORDINAL_POSITION
|
||||||
|
`;
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
module.exports = `
|
module.exports = `
|
||||||
select
|
select
|
||||||
|
ROUTINE_SCHEMA AS schemaName,
|
||||||
ROUTINE_NAME as pureName,
|
ROUTINE_NAME as pureName,
|
||||||
ROUTINE_TYPE as objectType,
|
ROUTINE_TYPE as objectType,
|
||||||
COALESCE(LAST_ALTERED, CREATED) as modifyDate,
|
COALESCE(LAST_ALTERED, CREATED) as modifyDate,
|
||||||
|
|||||||
@@ -49,6 +49,19 @@ 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()}` : '';
|
||||||
|
const parameterName = i.parameterName ?? '';
|
||||||
|
return `${mode}${parameterName}${dataType}`;
|
||||||
|
})
|
||||||
|
.join(', ');
|
||||||
|
}
|
||||||
|
|
||||||
class Analyser extends DatabaseAnalyser {
|
class Analyser extends DatabaseAnalyser {
|
||||||
constructor(dbhan, driver, version) {
|
constructor(dbhan, driver, version) {
|
||||||
super(dbhan, driver, version);
|
super(dbhan, driver, version);
|
||||||
@@ -144,6 +157,9 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
this.feedback({ analysingMessage: 'Loading routines' });
|
this.feedback({ analysingMessage: 'Loading routines' });
|
||||||
const routines = await this.analyserQuery('routines', ['procedures', 'functions']);
|
const routines = await this.analyserQuery('routines', ['procedures', 'functions']);
|
||||||
|
|
||||||
|
this.feedback({ analysingMessage: 'Loading routine parameters' });
|
||||||
|
const routineParametersRows = await this.analyserQuery('proceduresParameters');
|
||||||
|
|
||||||
this.feedback({ analysingMessage: 'Loading indexes' });
|
this.feedback({ analysingMessage: 'Loading indexes' });
|
||||||
const indexes = this.driver.__analyserInternals.skipIndexes
|
const indexes = this.driver.__analyserInternals.skipIndexes
|
||||||
? { rows: [] }
|
? { rows: [] }
|
||||||
@@ -191,6 +207,40 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
columnName: x.column_name,
|
columnName: x.column_name,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const procedureParameters = routineParametersRows.rows
|
||||||
|
.filter(i => i.routine_type == 'PROCEDURE')
|
||||||
|
.map(i => ({
|
||||||
|
pureName: i.pure_name,
|
||||||
|
parameterName: i.parameter_name,
|
||||||
|
dataType: normalizeTypeName(i.data_type),
|
||||||
|
parameterMode: i.parameter_mode,
|
||||||
|
schemaName: i.schema_name,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const procedureNameToParameters = procedureParameters.reduce((acc, row) => {
|
||||||
|
if (!acc[`${row.schemaName}.${row.pureName}`]) acc[`${row.schemaName}.${row.pureName}`] = [];
|
||||||
|
acc[`${row.schemaName}.${row.pureName}`].push(row);
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const functionParameters = routineParametersRows.rows
|
||||||
|
.filter(i => i.routine_type == 'FUNCTION')
|
||||||
|
.map(i => ({
|
||||||
|
pureName: i.pure_name,
|
||||||
|
parameterName: i.parameter_name,
|
||||||
|
dataType: normalizeTypeName(i.data_type),
|
||||||
|
parameterMode: i.parameter_mode,
|
||||||
|
schemaName: i.schema_name,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const functionNameToParameters = functionParameters.reduce((acc, row) => {
|
||||||
|
if (!acc[`${row.schemaName}.${row.pureName}`]) acc[`${row.schemaName}.${row.pureName}`] = [];
|
||||||
|
acc[`${row.schemaName}.${row.pureName}`].push(row);
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
const res = {
|
const res = {
|
||||||
tables: tables.rows.map(table => {
|
tables: tables.rows.map(table => {
|
||||||
const newTable = {
|
const newTable = {
|
||||||
@@ -279,17 +329,23 @@ class Analyser extends DatabaseAnalyser {
|
|||||||
objectId: `procedures:${proc.schema_name}.${proc.pure_name}`,
|
objectId: `procedures:${proc.schema_name}.${proc.pure_name}`,
|
||||||
pureName: proc.pure_name,
|
pureName: proc.pure_name,
|
||||||
schemaName: proc.schema_name,
|
schemaName: proc.schema_name,
|
||||||
createSql: `CREATE PROCEDURE "${proc.schema_name}"."${proc.pure_name}"() LANGUAGE ${proc.language}\nAS\n$$\n${proc.definition}\n$$`,
|
createSql: `CREATE PROCEDURE "${proc.schema_name}"."${proc.pure_name}"(${getParametersSqlString(
|
||||||
|
procedureNameToParameters[`${proc.schema_name}.${proc.pure_name}`]
|
||||||
|
)}) LANGUAGE ${proc.language}\nAS\n$$\n${proc.definition}\n$$`,
|
||||||
contentHash: proc.hash_code,
|
contentHash: proc.hash_code,
|
||||||
|
parameters: procedureNameToParameters[`${proc.schema_name}.${proc.pure_name}`],
|
||||||
})),
|
})),
|
||||||
functions: routines.rows
|
functions: routines.rows
|
||||||
.filter(x => x.object_type == 'FUNCTION')
|
.filter(x => x.object_type == 'FUNCTION')
|
||||||
.map(func => ({
|
.map(func => ({
|
||||||
objectId: `functions:${func.schema_name}.${func.pure_name}`,
|
objectId: `functions:${func.schema_name}.${func.pure_name}`,
|
||||||
createSql: `CREATE FUNCTION "${func.schema_name}"."${func.pure_name}"() RETURNS ${func.data_type} LANGUAGE ${func.language}\nAS\n$$\n${func.definition}\n$$`,
|
createSql: `CREATE FUNCTION "${func.schema_name}"."${func.pure_name}"(${getParametersSqlString(
|
||||||
|
functionNameToParameters[`${func.schema_name}.${func.pure_name}`]
|
||||||
|
)}) RETURNS ${func.data_type.toUpperCase()} LANGUAGE ${func.language}\nAS\n$$\n${func.definition}\n$$`,
|
||||||
pureName: func.pure_name,
|
pureName: func.pure_name,
|
||||||
schemaName: func.schema_name,
|
schemaName: func.schema_name,
|
||||||
contentHash: func.hash_code,
|
contentHash: func.hash_code,
|
||||||
|
parameters: functionNameToParameters[`${func.schema_name}.${func.pure_name}`],
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ const indexcols = require('./indexcols');
|
|||||||
const uniqueNames = require('./uniqueNames');
|
const uniqueNames = require('./uniqueNames');
|
||||||
const geometryColumns = require('./geometryColumns');
|
const geometryColumns = require('./geometryColumns');
|
||||||
const geographyColumns = require('./geographyColumns');
|
const geographyColumns = require('./geographyColumns');
|
||||||
|
const proceduresParameters = require('./proceduresParameters');
|
||||||
|
|
||||||
const fk_keyColumnUsage = require('./fk_key_column_usage');
|
const fk_keyColumnUsage = require('./fk_key_column_usage');
|
||||||
const fk_referentialConstraints = require('./fk_referential_constraints');
|
const fk_referentialConstraints = require('./fk_referential_constraints');
|
||||||
@@ -39,4 +40,5 @@ module.exports = {
|
|||||||
uniqueNames,
|
uniqueNames,
|
||||||
geometryColumns,
|
geometryColumns,
|
||||||
geographyColumns,
|
geographyColumns,
|
||||||
|
proceduresParameters,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
module.exports = `
|
||||||
|
SELECT
|
||||||
|
proc.specific_schema AS schema_name,
|
||||||
|
proc.routine_name AS pure_name,
|
||||||
|
proc.routine_type as routine_type,
|
||||||
|
args.parameter_name AS parameter_name,
|
||||||
|
args.parameter_mode,
|
||||||
|
args.data_type AS data_type,
|
||||||
|
args.ordinal_position AS parameter_index,
|
||||||
|
args.parameter_mode AS parameter_mode
|
||||||
|
FROM
|
||||||
|
information_schema.routines proc
|
||||||
|
LEFT JOIN
|
||||||
|
information_schema.parameters args
|
||||||
|
ON proc.specific_schema = args.specific_schema
|
||||||
|
AND proc.specific_name = args.specific_name
|
||||||
|
WHERE
|
||||||
|
proc.specific_schema NOT IN ('pg_catalog', 'information_schema') -- Exclude system schemas
|
||||||
|
AND args.parameter_name IS NOT NULL
|
||||||
|
AND proc.routine_type IN ('PROCEDURE', 'FUNCTION') -- Filter for procedures
|
||||||
|
AND proc.specific_schema !~ '^_timescaledb_'
|
||||||
|
AND proc.specific_schema =SCHEMA_NAME_CONDITION
|
||||||
|
AND (
|
||||||
|
(routine_type = 'PROCEDURE' AND ('procedures:' || proc.specific_schema || '.' || routine_name) =OBJECT_ID_CONDITION)
|
||||||
|
OR
|
||||||
|
(routine_type = 'FUNCTION' AND ('functions:' || proc.specific_schema || '.' || routine_name) =OBJECT_ID_CONDITION)
|
||||||
|
)
|
||||||
|
ORDER BY
|
||||||
|
schema_name,
|
||||||
|
args.ordinal_position;
|
||||||
|
`;
|
||||||
Reference in New Issue
Block a user