mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-06 17:30:25 +08:00
Merge branch 'dev' of https://gitee.com/objs/mayfly-go into dev
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -88,6 +88,20 @@
|
|||||||
"font_class": "gauss",
|
"font_class": "gauss",
|
||||||
"unicode": "e683",
|
"unicode": "e683",
|
||||||
"unicode_decimal": 59011
|
"unicode_decimal": 59011
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "34836637",
|
||||||
|
"name": "kingbase",
|
||||||
|
"font_class": "kingbase",
|
||||||
|
"unicode": "e882",
|
||||||
|
"unicode_decimal": 59522
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "33047500",
|
||||||
|
"name": "vastbase",
|
||||||
|
"font_class": "vastbase",
|
||||||
|
"unicode": "e62b",
|
||||||
|
"unicode_decimal": 58923
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ const emit = defineEmits(['update:queryForm', 'update:selectionData', 'pageChang
|
|||||||
|
|
||||||
export interface PageTableProps {
|
export interface PageTableProps {
|
||||||
size?: string;
|
size?: string;
|
||||||
pageApi: Api; // 请求表格数据的 api
|
pageApi?: Api; // 请求表格数据的 api
|
||||||
columns: TableColumn[]; // 列配置项 ==> 必传
|
columns: TableColumn[]; // 列配置项 ==> 必传
|
||||||
showSelection?: boolean;
|
showSelection?: boolean;
|
||||||
selectable?: (row: any) => boolean; // 是否可选
|
selectable?: (row: any) => boolean; // 是否可选
|
||||||
@@ -257,7 +257,7 @@ const changeSimpleFormItem = (searchItem: SearchItem) => {
|
|||||||
nowSearchItem.value = searchItem;
|
nowSearchItem.value = searchItem;
|
||||||
};
|
};
|
||||||
|
|
||||||
const { tableData, total, loading, search, reset, getTableData, handlePageNumChange, handlePageSizeChange } = usePageTable(
|
let { tableData, total, loading, search, reset, getTableData, handlePageNumChange, handlePageSizeChange } = usePageTable(
|
||||||
props.pageable,
|
props.pageable,
|
||||||
props.pageApi,
|
props.pageApi,
|
||||||
queryForm,
|
queryForm,
|
||||||
@@ -288,6 +288,13 @@ watch(isShowSearch, () => {
|
|||||||
calcuTableHeight();
|
calcuTableHeight();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.data,
|
||||||
|
(newValue: any) => {
|
||||||
|
tableData = newValue;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
calcuTableHeight();
|
calcuTableHeight();
|
||||||
useEventListener(window, 'resize', calcuTableHeight);
|
useEventListener(window, 'resize', calcuTableHeight);
|
||||||
|
|||||||
@@ -104,7 +104,11 @@ const loadTags = async () => {
|
|||||||
const tags = await tagApi.getResourceTagPaths.request({ resourceType: props.resourceType });
|
const tags = await tagApi.getResourceTagPaths.request({ resourceType: props.resourceType });
|
||||||
const tagNodes = [];
|
const tagNodes = [];
|
||||||
for (let tagPath of tags) {
|
for (let tagPath of tags) {
|
||||||
tagNodes.push(new TagTreeNode(tagPath, tagPath, props.tagPathNodeType));
|
let isLeaf = false;
|
||||||
|
if (!props.tagPathNodeType?.hasLoadNodesFunc) {
|
||||||
|
isLeaf = true;
|
||||||
|
}
|
||||||
|
tagNodes.push(new TagTreeNode(tagPath, tagPath, props.tagPathNodeType).withIsLeaf(isLeaf));
|
||||||
}
|
}
|
||||||
return tagNodes;
|
return tagNodes;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
v-model="modelValue"
|
v-model="modelValue"
|
||||||
@change="changeNode"
|
@change="changeNode"
|
||||||
>
|
>
|
||||||
|
<template #prefix="{ node, data }">
|
||||||
|
<slot name="iconPrefix" :node="node" :data="data" />
|
||||||
|
</template>
|
||||||
<template #default="{ node, data }">
|
<template #default="{ node, data }">
|
||||||
<span>
|
<span>
|
||||||
<span v-if="data.type.value == TagTreeNode.TagPath">
|
<span v-if="data.type.value == TagTreeNode.TagPath">
|
||||||
@@ -33,7 +36,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, reactive, ref, watch, toRefs } from 'vue';
|
import { onMounted, reactive, ref, toRefs, watch } from 'vue';
|
||||||
import { NodeType, TagTreeNode } from './tag';
|
import { NodeType, TagTreeNode } from './tag';
|
||||||
import TagInfo from './TagInfo.vue';
|
import TagInfo from './TagInfo.vue';
|
||||||
import { tagApi } from '../tag/api';
|
import { tagApi } from '../tag/api';
|
||||||
|
|||||||
@@ -89,6 +89,8 @@ export class NodeType {
|
|||||||
|
|
||||||
contextMenuItems: ContextmenuItem[];
|
contextMenuItems: ContextmenuItem[];
|
||||||
|
|
||||||
|
hasLoadNodesFunc: boolean;
|
||||||
|
|
||||||
loadNodesFunc: (parentNode: TagTreeNode) => Promise<TagTreeNode[]>;
|
loadNodesFunc: (parentNode: TagTreeNode) => Promise<TagTreeNode[]>;
|
||||||
|
|
||||||
nodeClickFunc: (node: TagTreeNode) => void;
|
nodeClickFunc: (node: TagTreeNode) => void;
|
||||||
@@ -104,6 +106,7 @@ export class NodeType {
|
|||||||
*/
|
*/
|
||||||
withLoadNodesFunc(func: (parentNode: TagTreeNode) => Promise<TagTreeNode[]>) {
|
withLoadNodesFunc(func: (parentNode: TagTreeNode) => Promise<TagTreeNode[]>) {
|
||||||
this.loadNodesFunc = func;
|
this.loadNodesFunc = func;
|
||||||
|
this.hasLoadNodesFunc = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #type="{ data }">
|
<template #type="{ data }">
|
||||||
<el-tooltip :content="data.type" placement="top">
|
<el-tooltip :content="getDbDialect(data.type).getInfo().name" placement="top">
|
||||||
<SvgIcon :name="getDbDialect(data.type).getInfo().icon" :size="20" />
|
<SvgIcon :name="getDbDialect(data.type).getInfo().icon" :size="20" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
<db-select-tree
|
<db-select-tree
|
||||||
placeholder="请选择源数据库"
|
placeholder="请选择源数据库"
|
||||||
v-model:db-id="form.srcDbId"
|
v-model:db-id="form.srcDbId"
|
||||||
|
v-model:inst-name="form.srcInstName"
|
||||||
v-model:db-name="form.srcDbName"
|
v-model:db-name="form.srcDbName"
|
||||||
v-model:tag-path="form.srcTagPath"
|
v-model:tag-path="form.srcTagPath"
|
||||||
v-model:db-type="form.srcDbType"
|
v-model:db-type="form.srcDbType"
|
||||||
@@ -56,8 +57,10 @@
|
|||||||
<db-select-tree
|
<db-select-tree
|
||||||
placeholder="请选择目标数据库"
|
placeholder="请选择目标数据库"
|
||||||
v-model:db-id="form.targetDbId"
|
v-model:db-id="form.targetDbId"
|
||||||
|
v-model:inst-name="form.targetInstName"
|
||||||
v-model:db-name="form.targetDbName"
|
v-model:db-name="form.targetDbName"
|
||||||
v-model:tag-path="form.targetTagPath"
|
v-model:tag-path="form.targetTagPath"
|
||||||
|
v-model:db-type="form.targetDbType"
|
||||||
@select-db="onSelectTargetDb"
|
@select-db="onSelectTargetDb"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -182,7 +185,7 @@ import { ElMessage } from 'element-plus';
|
|||||||
import DbSelectTree from '@/views/ops/db/component/DbSelectTree.vue';
|
import DbSelectTree from '@/views/ops/db/component/DbSelectTree.vue';
|
||||||
import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
|
import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
|
||||||
import { DbInst, registerDbCompletionItemProvider } from '@/views/ops/db/db';
|
import { DbInst, registerDbCompletionItemProvider } from '@/views/ops/db/db';
|
||||||
import {DbType, getDbDialect} from '@/views/ops/db/dialect'
|
import { DbType, getDbDialect } from '@/views/ops/db/dialect';
|
||||||
import CrontabInput from '@/components/crontab/CrontabInput.vue';
|
import CrontabInput from '@/components/crontab/CrontabInput.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -227,13 +230,16 @@ type FormData = {
|
|||||||
taskName?: string;
|
taskName?: string;
|
||||||
taskCron: string;
|
taskCron: string;
|
||||||
srcDbId?: number;
|
srcDbId?: number;
|
||||||
|
srcInstName?: string;
|
||||||
srcDbName?: string;
|
srcDbName?: string;
|
||||||
srcDbType?: string;
|
srcDbType?: string;
|
||||||
srcTagPath?: string;
|
srcTagPath?: string;
|
||||||
targetDbId?: number;
|
targetDbId?: number;
|
||||||
|
targetInstName?: string;
|
||||||
targetDbName?: string;
|
targetDbName?: string;
|
||||||
targetTagPath?: string;
|
targetTagPath?: string;
|
||||||
targetTableName?: string;
|
targetTableName?: string;
|
||||||
|
targetDbType?: string;
|
||||||
dataSql?: string;
|
dataSql?: string;
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
updField?: string;
|
updField?: string;
|
||||||
@@ -304,7 +310,8 @@ watch(dialogVisible, async (newValue: boolean) => {
|
|||||||
// 初始化实例
|
// 初始化实例
|
||||||
db.databases = db.database?.split(' ').sort() || [];
|
db.databases = db.database?.split(' ').sort() || [];
|
||||||
state.srcDbInst = DbInst.getOrNewInst(db);
|
state.srcDbInst = DbInst.getOrNewInst(db);
|
||||||
state.form.srcDbType = state.srcDbInst.type
|
state.form.srcDbType = state.srcDbInst.type;
|
||||||
|
state.form.srcInstName = db.instanceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化target数据源
|
// 初始化target数据源
|
||||||
@@ -315,6 +322,8 @@ watch(dialogVisible, async (newValue: boolean) => {
|
|||||||
// 初始化实例
|
// 初始化实例
|
||||||
db.databases = db.database?.split(' ').sort() || [];
|
db.databases = db.database?.split(' ').sort() || [];
|
||||||
state.targetDbInst = DbInst.getOrNewInst(db);
|
state.targetDbInst = DbInst.getOrNewInst(db);
|
||||||
|
state.form.targetDbType = state.targetDbInst.type;
|
||||||
|
state.form.targetInstName = db.instanceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetDbId && state.form.targetDbName) {
|
if (targetDbId && state.form.targetDbName) {
|
||||||
@@ -414,15 +423,15 @@ const handleGetSrcFields = async () => {
|
|||||||
|
|
||||||
// 执行sql
|
// 执行sql
|
||||||
// oracle的分页关键字不一样
|
// oracle的分页关键字不一样
|
||||||
let limit = ' limit 1'
|
let limit = ' limit 1';
|
||||||
if(state.form.srcDbType === DbType.oracle){
|
if (state.form.srcDbType === DbType.oracle) {
|
||||||
limit = ' where rownum <= 1'
|
limit = ' where rownum <= 1';
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await dbApi.sqlExec.request({
|
const res = await dbApi.sqlExec.request({
|
||||||
id: state.form.srcDbId,
|
id: state.form.srcDbId,
|
||||||
db: state.form.srcDbName,
|
db: state.form.srcDbName,
|
||||||
sql: `select * from (${state.form.dataSql}) t ${limit}`
|
sql: `select * from (${state.form.dataSql}) t ${limit}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.columns) {
|
if (!res.columns) {
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
:resource-type="TagResourceTypeEnum.Db.value"
|
:resource-type="TagResourceTypeEnum.Db.value"
|
||||||
:tag-path-node-type="NodeTypeTagPath"
|
:tag-path-node-type="NodeTypeTagPath"
|
||||||
>
|
>
|
||||||
|
<template #iconPrefix>
|
||||||
|
<SvgIcon v-if="dbType && getDbDialect(dbType)" :name="getDbDialect(dbType).getInfo().icon" :size="18" />
|
||||||
|
</template>
|
||||||
<template #prefix="{ data }">
|
<template #prefix="{ data }">
|
||||||
<SvgIcon v-if="data.type.value == SqlExecNodeType.DbInst" :name="getDbDialect(data.params.type).getInfo().icon" :size="18" />
|
<SvgIcon v-if="data.type.value == SqlExecNodeType.DbInst" :name="getDbDialect(data.params.type).getInfo().icon" :size="18" />
|
||||||
<SvgIcon v-if="data.icon" :name="data.icon.name" :color="data.icon.color" />
|
<SvgIcon v-if="data.icon" :name="data.icon.name" :color="data.icon.color" />
|
||||||
@@ -27,6 +30,9 @@ const props = defineProps({
|
|||||||
dbId: {
|
dbId: {
|
||||||
type: Number,
|
type: Number,
|
||||||
},
|
},
|
||||||
|
instName: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
dbName: {
|
dbName: {
|
||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
@@ -38,7 +44,7 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const emits = defineEmits(['update:dbName', 'update:tagPath', 'update:dbId', 'update:dbType', 'selectDb']);
|
const emits = defineEmits(['update:dbName', 'update:tagPath', 'update:instName', 'update:dbId', 'update:dbType', 'selectDb']);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 树节点类型
|
* 树节点类型
|
||||||
@@ -56,7 +62,7 @@ class SqlExecNodeType {
|
|||||||
|
|
||||||
const selectNode = computed({
|
const selectNode = computed({
|
||||||
get: () => {
|
get: () => {
|
||||||
return props.dbName ? `${props.tagPath} - ${props.dbId} - ${props.dbName}` : '';
|
return props.dbName ? `${props.tagPath} > ${props.instName} > ${props.dbName}` : '';
|
||||||
},
|
},
|
||||||
set: () => {
|
set: () => {
|
||||||
//
|
//
|
||||||
@@ -151,6 +157,7 @@ const changeNode = (nodeData: TagTreeNode) => {
|
|||||||
const params = nodeData.params;
|
const params = nodeData.params;
|
||||||
// postgres
|
// postgres
|
||||||
emits('update:dbName', params.db);
|
emits('update:dbName', params.db);
|
||||||
|
emits('update:instName', params.name);
|
||||||
emits('update:dbId', params.id);
|
emits('update:dbId', params.id);
|
||||||
emits('update:tagPath', params.tagPath);
|
emits('update:tagPath', params.tagPath);
|
||||||
emits('update:dbType', params.type);
|
emits('update:dbType', params.type);
|
||||||
|
|||||||
@@ -272,6 +272,18 @@ watch(props, async (newValue) => {
|
|||||||
dbDialect = getDbDialect(newValue.dbType);
|
dbDialect = getDbDialect(newValue.dbType);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 切换到索引tab时,刷新索引字段下拉选项
|
||||||
|
watch(
|
||||||
|
() => state.activeName,
|
||||||
|
(newValue) => {
|
||||||
|
if (newValue === '2') {
|
||||||
|
state.tableData.indexs.columns = state.tableData.fields.res.map((a) => {
|
||||||
|
return { name: a.name, remark: a.remark };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
emit('update:visible', false);
|
emit('update:visible', false);
|
||||||
reset();
|
reset();
|
||||||
@@ -391,22 +403,22 @@ const genSql = () => {
|
|||||||
let data = state.tableData;
|
let data = state.tableData;
|
||||||
// 创建表
|
// 创建表
|
||||||
if (!props.data?.edit) {
|
if (!props.data?.edit) {
|
||||||
if (state.activeName === '1') {
|
let createTable = dbDialect.getCreateTableSql(data);
|
||||||
return dbDialect.getCreateTableSql(data);
|
let createIndex = '';
|
||||||
} else if (state.activeName === '2' && data.indexs.res.length > 0) {
|
if (data.indexs.res.length > 0) {
|
||||||
return dbDialect.getCreateIndexSql(data);
|
createIndex = dbDialect.getCreateIndexSql(data);
|
||||||
}
|
}
|
||||||
|
return createTable + ';' + createIndex;
|
||||||
} else {
|
} else {
|
||||||
// 修改
|
// 修改列
|
||||||
if (state.activeName === '1') {
|
let changeColData = filterChangedData(state.tableData.fields.oldFields, state.tableData.fields.res, 'name');
|
||||||
// 修改列
|
let colSql = dbDialect.getModifyColumnSql(data, data.tableName, changeColData);
|
||||||
let changeData = filterChangedData(state.tableData.fields.oldFields, state.tableData.fields.res, 'name');
|
// 修改索引
|
||||||
return dbDialect.getModifyColumnSql(data, data.tableName, changeData);
|
let changeIdxData = filterChangedData(state.tableData.indexs.oldIndexs, state.tableData.indexs.res, 'indexName');
|
||||||
} else if (state.activeName === '2') {
|
let idxSql = dbDialect.getModifyIndexSql(data, data.tableName, changeIdxData);
|
||||||
// 修改索引
|
// 修改表名
|
||||||
let changeData = filterChangedData(state.tableData.indexs.oldIndexs, state.tableData.indexs.res, 'indexName');
|
|
||||||
return dbDialect.getModifyIndexSql(data, data.tableName, changeData);
|
return colSql + ';' + idxSql;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import { MariadbDialect } from '@/views/ops/db/dialect/mariadb_dialect';
|
|||||||
import { SqliteDialect } from '@/views/ops/db/dialect/sqlite_dialect';
|
import { SqliteDialect } from '@/views/ops/db/dialect/sqlite_dialect';
|
||||||
import { MssqlDialect } from '@/views/ops/db/dialect/mssql_dialect';
|
import { MssqlDialect } from '@/views/ops/db/dialect/mssql_dialect';
|
||||||
import { GaussDialect } from '@/views/ops/db/dialect/gauss_dialect';
|
import { GaussDialect } from '@/views/ops/db/dialect/gauss_dialect';
|
||||||
|
import { KingbaseEsDialect } from '@/views/ops/db/dialect/kingbaseES_dialect';
|
||||||
|
import { VastbaseDialect } from '@/views/ops/db/dialect/vastbase_dialect';
|
||||||
|
|
||||||
export interface sqlColumnType {
|
export interface sqlColumnType {
|
||||||
udtName: string;
|
udtName: string;
|
||||||
@@ -122,13 +124,15 @@ export const DbType = {
|
|||||||
oracle: 'oracle',
|
oracle: 'oracle',
|
||||||
sqlite: 'sqlite',
|
sqlite: 'sqlite',
|
||||||
mssql: 'mssql', // ms sqlserver
|
mssql: 'mssql', // ms sqlserver
|
||||||
|
kingbaseEs: 'kingbaseEs', // 人大金仓 pgsql模式 https://help.kingbase.com.cn/v8/index.html
|
||||||
|
vastbase: 'vastbase', // https://docs.vastdata.com.cn/zh/docs/VastbaseG100Ver2.2.5/doc/%E5%BC%80%E5%8F%91%E8%80%85%E6%8C%87%E5%8D%97/SQL%E5%8F%82%E8%80%83/SQL%E5%8F%82%E8%80%83.html
|
||||||
};
|
};
|
||||||
|
|
||||||
// mysql兼容的数据库
|
// mysql兼容的数据库
|
||||||
export const noSchemaTypes = [DbType.mysql, DbType.mariadb, DbType.sqlite];
|
export const noSchemaTypes = [DbType.mysql, DbType.mariadb, DbType.sqlite];
|
||||||
|
|
||||||
// 有schema层的数据库
|
// 有schema层的数据库
|
||||||
export const schemaDbTypes = [DbType.postgresql, DbType.gauss, DbType.dm, DbType.oracle, DbType.mssql];
|
export const schemaDbTypes = [DbType.postgresql, DbType.gauss, DbType.dm, DbType.oracle, DbType.mssql, DbType.kingbaseEs, DbType.vastbase];
|
||||||
|
|
||||||
export const editDbTypes = [...noSchemaTypes, ...schemaDbTypes];
|
export const editDbTypes = [...noSchemaTypes, ...schemaDbTypes];
|
||||||
|
|
||||||
@@ -218,8 +222,8 @@ export const getDbDialectMap = () => {
|
|||||||
return dbType2DialectMap;
|
return dbType2DialectMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDbDialect = (dbType: string): DbDialect => {
|
export const getDbDialect = (dbType?: string): DbDialect => {
|
||||||
return dbType2DialectMap.get(dbType) || mysqlDialect;
|
return dbType2DialectMap.get(dbType!) || mysqlDialect;
|
||||||
};
|
};
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
@@ -232,4 +236,6 @@ export const getDbDialect = (dbType: string): DbDialect => {
|
|||||||
registerDbDialect(DbType.oracle, new OracleDialect());
|
registerDbDialect(DbType.oracle, new OracleDialect());
|
||||||
registerDbDialect(DbType.sqlite, new SqliteDialect());
|
registerDbDialect(DbType.sqlite, new SqliteDialect());
|
||||||
registerDbDialect(DbType.mssql, new MssqlDialect());
|
registerDbDialect(DbType.mssql, new MssqlDialect());
|
||||||
|
registerDbDialect(DbType.kingbaseEs, new KingbaseEsDialect());
|
||||||
|
registerDbDialect(DbType.vastbase, new VastbaseDialect());
|
||||||
})();
|
})();
|
||||||
|
|||||||
18
mayfly_go_web/src/views/ops/db/dialect/kingbaseES_dialect.ts
Normal file
18
mayfly_go_web/src/views/ops/db/dialect/kingbaseES_dialect.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { DialectInfo } from './index';
|
||||||
|
import { PostgresqlDialect } from '@/views/ops/db/dialect/postgres_dialect';
|
||||||
|
|
||||||
|
let kbpgDialectInfo: DialectInfo;
|
||||||
|
|
||||||
|
export class KingbaseEsDialect extends PostgresqlDialect {
|
||||||
|
getInfo(): DialectInfo {
|
||||||
|
if (kbpgDialectInfo) {
|
||||||
|
return kbpgDialectInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
kbpgDialectInfo = {} as DialectInfo;
|
||||||
|
Object.assign(kbpgDialectInfo, super.getInfo());
|
||||||
|
kbpgDialectInfo.name = 'KingbaseES';
|
||||||
|
kbpgDialectInfo.icon = 'iconfont icon-kingbase';
|
||||||
|
return kbpgDialectInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -303,11 +303,15 @@ class PostgresqlDialect implements DbDialect {
|
|||||||
// CREATE UNIQUE INDEX idx_column_name ON your_table (column1, column2);
|
// CREATE UNIQUE INDEX idx_column_name ON your_table (column1, column2);
|
||||||
// COMMENT ON INDEX idx_column_name IS 'Your index comment here';
|
// COMMENT ON INDEX idx_column_name IS 'Your index comment here';
|
||||||
// 创建索引
|
// 创建索引
|
||||||
|
let schema = tableData.db.split('/')[1];
|
||||||
|
let dbTable = `${this.quoteIdentifier(schema)}.${this.quoteIdentifier(tableData.tableName)}`;
|
||||||
let sql: string[] = [];
|
let sql: string[] = [];
|
||||||
tableData.indexs.res.forEach((a: any) => {
|
tableData.indexs.res.forEach((a: any) => {
|
||||||
sql.push(` create ${a.unique ? 'UNIQUE' : ''} index ${a.indexName} ("${a.columnNames.join('","')})"`);
|
// 字段名用双引号包裹
|
||||||
|
let colArr = a.columnNames.map((a: string) => `${this.quoteIdentifier(a)}`);
|
||||||
|
sql.push(`CREATE ${a.unique ? 'UNIQUE' : ''} INDEX ${this.quoteIdentifier(a.indexName)} on ${dbTable} (${colArr.join(',')})`);
|
||||||
if (a.indexComment) {
|
if (a.indexComment) {
|
||||||
sql.push(`COMMENT ON INDEX ${a.indexName} IS '${a.indexComment}'`);
|
sql.push(`COMMENT ON INDEX ${schema}.${this.quoteIdentifier(a.indexName)} IS '${a.indexComment}'`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return sql.join(';');
|
return sql.join(';');
|
||||||
@@ -367,6 +371,9 @@ class PostgresqlDialect implements DbDialect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getModifyIndexSql(tableData: any, tableName: string, changeData: { del: any[]; add: any[]; upd: any[] }): string {
|
getModifyIndexSql(tableData: any, tableName: string, changeData: { del: any[]; add: any[]; upd: any[] }): string {
|
||||||
|
let schema = tableData.db.split('/')[1];
|
||||||
|
let dbTable = `${this.quoteIdentifier(schema)}.${this.quoteIdentifier(tableName)}`;
|
||||||
|
|
||||||
// 不能直接修改索引名或字段、需要先删后加
|
// 不能直接修改索引名或字段、需要先删后加
|
||||||
let dropIndexNames: string[] = [];
|
let dropIndexNames: string[] = [];
|
||||||
let addIndexs: any[] = [];
|
let addIndexs: any[] = [];
|
||||||
@@ -400,9 +407,11 @@ class PostgresqlDialect implements DbDialect {
|
|||||||
|
|
||||||
if (addIndexs.length > 0) {
|
if (addIndexs.length > 0) {
|
||||||
addIndexs.forEach((a) => {
|
addIndexs.forEach((a) => {
|
||||||
sql.push(`CREATE ${a.unique ? 'UNIQUE' : ''} INDEX ${a.indexName}(${a.columnNames.join(',')})`);
|
// 字段名用双引号包裹
|
||||||
|
let colArr = a.columnNames.map((a: string) => `${this.quoteIdentifier(a)}`);
|
||||||
|
sql.push(`CREATE ${a.unique ? 'UNIQUE' : ''} INDEX ${this.quoteIdentifier(a.indexName)} on ${dbTable} (${colArr.join(',')})`);
|
||||||
if (a.indexComment) {
|
if (a.indexComment) {
|
||||||
sql.push(`COMMENT ON INDEX ${a.indexName} IS '${a.indexComment}'`);
|
sql.push(`COMMENT ON INDEX ${schema}.${this.quoteIdentifier(a.indexName)} IS '${a.indexComment}'`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
18
mayfly_go_web/src/views/ops/db/dialect/vastbase_dialect.ts
Normal file
18
mayfly_go_web/src/views/ops/db/dialect/vastbase_dialect.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { DialectInfo } from './index';
|
||||||
|
import { PostgresqlDialect } from '@/views/ops/db/dialect/postgres_dialect';
|
||||||
|
|
||||||
|
let vastDialectInfo: DialectInfo;
|
||||||
|
|
||||||
|
export class VastbaseDialect extends PostgresqlDialect {
|
||||||
|
getInfo(): DialectInfo {
|
||||||
|
if (vastDialectInfo) {
|
||||||
|
return vastDialectInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
vastDialectInfo = {} as DialectInfo;
|
||||||
|
Object.assign(vastDialectInfo, super.getInfo());
|
||||||
|
vastDialectInfo.name = 'VastbaseG100';
|
||||||
|
vastDialectInfo.icon = 'iconfont icon-vastbase';
|
||||||
|
return vastDialectInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,191 +1,207 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="flex-all-center">
|
||||||
<page-table
|
<Splitpanes class="default-theme">
|
||||||
ref="pageTableRef"
|
<Pane size="20" max-size="30">
|
||||||
:page-api="machineApi.list"
|
<tag-tree :resource-type="TagResourceTypeEnum.Machine.value" :tag-path-node-type="NodeTypeTagPath" />
|
||||||
:before-query-fn="checkRouteTagPath"
|
</Pane>
|
||||||
:search-items="searchItems"
|
|
||||||
v-model:query-form="params"
|
|
||||||
:show-selection="true"
|
|
||||||
v-model:selection-data="state.selectionData"
|
|
||||||
:columns="columns"
|
|
||||||
>
|
|
||||||
<template #tableHeader>
|
|
||||||
<el-button v-auth="perms.addMachine" type="primary" icon="plus" @click="openFormDialog(false)" plain>添加 </el-button>
|
|
||||||
<el-button v-auth="perms.delMachine" :disabled="selectionData.length < 1" @click="deleteMachine()" type="danger" icon="delete">删除</el-button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #ipPort="{ data }">
|
<Pane>
|
||||||
<el-link :disabled="data.status == -1" @click="showMachineStats(data)" type="primary" :underline="false">
|
<div>
|
||||||
{{ `${data.ip}:${data.port}` }}
|
<page-table :data="state.pageData" :pageable="false" :show-selection="true" v-model:selection-data="state.selectionData" :columns="columns">
|
||||||
</el-link>
|
<template #tableHeader>
|
||||||
</template>
|
<el-button v-auth="perms.addMachine" type="primary" icon="plus" @click="openFormDialog(false)" plain>添加 </el-button>
|
||||||
|
<el-button v-auth="perms.delMachine" :disabled="selectionData.length < 1" @click="deleteMachine()" type="danger" icon="delete"
|
||||||
<template #stat="{ data }">
|
>删除</el-button
|
||||||
<span v-if="!data.stat">-</span>
|
|
||||||
<div v-else>
|
|
||||||
<el-row>
|
|
||||||
<el-text size="small" style="font-size: 10px">
|
|
||||||
内存(可用/总):
|
|
||||||
<span :class="getStatsFontClass(data.stat.memAvailable, data.stat.memTotal)"
|
|
||||||
>{{ formatByteSize(data.stat.memAvailable, 1) }}/{{ formatByteSize(data.stat.memTotal, 1) }}
|
|
||||||
</span>
|
|
||||||
</el-text>
|
|
||||||
</el-row>
|
|
||||||
<el-row>
|
|
||||||
<el-text style="font-size: 10px" size="small">
|
|
||||||
CPU(空闲): <span :class="getStatsFontClass(data.stat.cpuIdle, 100)">{{ data.stat.cpuIdle.toFixed(0) }}%</span>
|
|
||||||
</el-text>
|
|
||||||
</el-row>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #fs="{ data }">
|
|
||||||
<span v-if="!data.stat?.fsInfos">-</span>
|
|
||||||
<div v-else>
|
|
||||||
<el-row v-for="(i, idx) in data.stat.fsInfos.slice(0, 2)" :key="i.mountPoint">
|
|
||||||
<el-text style="font-size: 10px" size="small" :class="getStatsFontClass(i.free, i.used + i.free)">
|
|
||||||
{{ i.mountPoint }} => {{ formatByteSize(i.free, 0) }}/{{ formatByteSize(i.used + i.free, 0) }}
|
|
||||||
</el-text>
|
|
||||||
|
|
||||||
<!-- 展示剩余的磁盘信息 -->
|
|
||||||
<el-popover :show-after="300" v-if="data.stat.fsInfos.length > 2 && idx == 1" placement="top-start" width="230" trigger="hover">
|
|
||||||
<template #reference>
|
|
||||||
<SvgIcon class="mt5 ml5" color="var(--el-color-primary)" name="MoreFilled" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<el-row v-for="i in data.stat.fsInfos.slice(2)" :key="i.mountPoint">
|
|
||||||
<el-text style="font-size: 10px" size="small" :class="getStatsFontClass(i.free, i.used + i.free)">
|
|
||||||
{{ i.mountPoint }} => {{ formatByteSize(i.free, 0) }}/{{ formatByteSize(i.used + i.free, 0) }}
|
|
||||||
</el-text>
|
|
||||||
</el-row>
|
|
||||||
</el-popover>
|
|
||||||
</el-row>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #status="{ data }">
|
|
||||||
<el-switch
|
|
||||||
v-auth:disabled="'machine:update'"
|
|
||||||
:width="52"
|
|
||||||
v-model="data.status"
|
|
||||||
:active-value="1"
|
|
||||||
:inactive-value="-1"
|
|
||||||
inline-prompt
|
|
||||||
active-text="启用"
|
|
||||||
inactive-text="停用"
|
|
||||||
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
|
|
||||||
@change="changeStatus(data)"
|
|
||||||
></el-switch>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #tagPath="{ data }">
|
|
||||||
<resource-tag :resource-code="data.code" :resource-type="TagResourceTypeEnum.Machine.value" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #action="{ data }">
|
|
||||||
<span v-auth="'machine:terminal'">
|
|
||||||
<el-tooltip :show-after="500" content="按住ctrl则为新标签打开" placement="top">
|
|
||||||
<el-button :disabled="data.status == -1" type="primary" @click="showTerminal(data, $event)" link>终端</el-button>
|
|
||||||
</el-tooltip>
|
|
||||||
|
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span v-auth="'machine:file'">
|
|
||||||
<el-button type="success" :disabled="data.status == -1" @click="showFileManage(data)" link>文件</el-button>
|
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<el-button :disabled="data.status == -1" type="warning" @click="serviceManager(data)" link>脚本</el-button>
|
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
|
||||||
|
|
||||||
<el-dropdown @command="handleCommand">
|
|
||||||
<span class="el-dropdown-link-machine-list">
|
|
||||||
更多
|
|
||||||
<el-icon class="el-icon--right">
|
|
||||||
<arrow-down />
|
|
||||||
</el-icon>
|
|
||||||
</span>
|
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<el-dropdown-item :command="{ type: 'detail', data }"> 详情 </el-dropdown-item>
|
|
||||||
|
|
||||||
<el-dropdown-item :command="{ type: 'edit', data }" v-if="actionBtns[perms.updateMachine]"> 编辑 </el-dropdown-item>
|
|
||||||
|
|
||||||
<el-dropdown-item :command="{ type: 'process', data }" :disabled="data.status == -1"> 进程 </el-dropdown-item>
|
|
||||||
|
|
||||||
<el-dropdown-item :command="{ type: 'terminalRec', data }" v-if="actionBtns[perms.updateMachine] && data.enableRecorder == 1">
|
|
||||||
终端回放
|
|
||||||
</el-dropdown-item>
|
|
||||||
|
|
||||||
<el-dropdown-item
|
|
||||||
:command="{ type: 'closeCli', data }"
|
|
||||||
v-if="actionBtns[perms.closeCli]"
|
|
||||||
:disabled="!data.hasCli || data.status == -1"
|
|
||||||
>
|
>
|
||||||
关闭连接
|
</template>
|
||||||
</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</template>
|
|
||||||
</el-dropdown>
|
|
||||||
</template>
|
|
||||||
</page-table>
|
|
||||||
|
|
||||||
<el-dialog v-model="infoDialog.visible">
|
<template #ipPort="{ data }">
|
||||||
<el-descriptions title="详情" :column="3" border>
|
<el-link :disabled="data.status == -1" @click="showMachineStats(data)" type="primary" :underline="false">
|
||||||
<el-descriptions-item :span="1.5" label="机器id">{{ infoDialog.data.id }}</el-descriptions-item>
|
{{ `${data.ip}:${data.port}` }}
|
||||||
<el-descriptions-item :span="1.5" label="名称">{{ infoDialog.data.name }}</el-descriptions-item>
|
</el-link>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-descriptions-item :span="3" label="标签路径">{{ infoDialog.data.tagPath }}</el-descriptions-item>
|
<template #stat="{ data }">
|
||||||
|
<span v-if="!data.stat">-</span>
|
||||||
|
<div v-else>
|
||||||
|
<el-row>
|
||||||
|
<el-text size="small" style="font-size: 10px">
|
||||||
|
内存(可用/总):
|
||||||
|
<span :class="getStatsFontClass(data.stat.memAvailable, data.stat.memTotal)"
|
||||||
|
>{{ formatByteSize(data.stat.memAvailable, 1) }}/{{ formatByteSize(data.stat.memTotal, 1) }}
|
||||||
|
</span>
|
||||||
|
</el-text>
|
||||||
|
</el-row>
|
||||||
|
<el-row>
|
||||||
|
<el-text style="font-size: 10px" size="small">
|
||||||
|
CPU(空闲): <span :class="getStatsFontClass(data.stat.cpuIdle, 100)">{{ data.stat.cpuIdle.toFixed(0) }}%</span>
|
||||||
|
</el-text>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-descriptions-item :span="2" label="IP">{{ infoDialog.data.ip }}</el-descriptions-item>
|
<template #fs="{ data }">
|
||||||
<el-descriptions-item :span="1" label="端口">{{ infoDialog.data.port }}</el-descriptions-item>
|
<span v-if="!data.stat?.fsInfos">-</span>
|
||||||
|
<div v-else>
|
||||||
|
<el-row v-for="(i, idx) in data.stat.fsInfos.slice(0, 2)" :key="i.mountPoint">
|
||||||
|
<el-text style="font-size: 10px" size="small" :class="getStatsFontClass(i.free, i.used + i.free)">
|
||||||
|
{{ i.mountPoint }} => {{ formatByteSize(i.free, 0) }}/{{ formatByteSize(i.used + i.free, 0) }}
|
||||||
|
</el-text>
|
||||||
|
|
||||||
<el-descriptions-item :span="2" label="用户名">{{ infoDialog.data.username }}</el-descriptions-item>
|
<!-- 展示剩余的磁盘信息 -->
|
||||||
<el-descriptions-item :span="1" label="认证方式">
|
<el-popover
|
||||||
{{ infoDialog.data.authCertId > 1 ? '授权凭证' : '密码' }}
|
:show-after="300"
|
||||||
</el-descriptions-item>
|
v-if="data.stat.fsInfos.length > 2 && idx == 1"
|
||||||
|
placement="top-start"
|
||||||
|
width="230"
|
||||||
|
trigger="hover"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<SvgIcon class="mt5 ml5" color="var(--el-color-primary)" name="MoreFilled" />
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-descriptions-item :span="3" label="备注">{{ infoDialog.data.remark }}</el-descriptions-item>
|
<el-row v-for="i in data.stat.fsInfos.slice(2)" :key="i.mountPoint">
|
||||||
|
<el-text style="font-size: 10px" size="small" :class="getStatsFontClass(i.free, i.used + i.free)">
|
||||||
|
{{ i.mountPoint }} => {{ formatByteSize(i.free, 0) }}/{{ formatByteSize(i.used + i.free, 0) }}
|
||||||
|
</el-text>
|
||||||
|
</el-row>
|
||||||
|
</el-popover>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-descriptions-item :span="1.5" label="SSH隧道">{{ infoDialog.data.sshTunnelMachineId > 0 ? '是' : '否' }} </el-descriptions-item>
|
<template #status="{ data }">
|
||||||
<el-descriptions-item :span="1.5" label="终端回放">{{ infoDialog.data.enableRecorder == 1 ? '是' : '否' }} </el-descriptions-item>
|
<el-switch
|
||||||
|
v-auth:disabled="'machine:update'"
|
||||||
|
:width="52"
|
||||||
|
v-model="data.status"
|
||||||
|
:active-value="1"
|
||||||
|
:inactive-value="-1"
|
||||||
|
inline-prompt
|
||||||
|
active-text="启用"
|
||||||
|
inactive-text="停用"
|
||||||
|
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
|
||||||
|
@change="changeStatus(data)"
|
||||||
|
></el-switch>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-descriptions-item :span="2" label="创建时间">{{ dateFormat(infoDialog.data.createTime) }} </el-descriptions-item>
|
<template #action="{ data }">
|
||||||
<el-descriptions-item :span="1" label="创建者">{{ infoDialog.data.creator }}</el-descriptions-item>
|
<span v-auth="'machine:terminal'">
|
||||||
|
<el-tooltip :show-after="500" content="按住ctrl则为新标签打开" placement="top">
|
||||||
|
<el-button :disabled="data.status == -1" type="primary" @click="showTerminal(data, $event)" link>终端</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
|
||||||
<el-descriptions-item :span="2" label="更新时间">{{ dateFormat(infoDialog.data.updateTime) }} </el-descriptions-item>
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
<el-descriptions-item :span="1" label="修改者">{{ infoDialog.data.modifier }}</el-descriptions-item>
|
</span>
|
||||||
</el-descriptions>
|
|
||||||
</el-dialog>
|
|
||||||
|
|
||||||
<terminal-dialog ref="terminalDialogRef" :visibleMinimize="true">
|
<span v-auth="'machine:file'">
|
||||||
<template #headerTitle="{ terminalInfo }">
|
<el-button type="success" :disabled="data.status == -1" @click="showFileManage(data)" link>文件</el-button>
|
||||||
{{ `${(terminalInfo.terminalId + '').slice(-2)}` }}
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
<el-divider direction="vertical" />
|
</span>
|
||||||
{{ `${terminalInfo.meta.username}@${terminalInfo.meta.ip}:${terminalInfo.meta.port}` }}
|
|
||||||
<el-divider direction="vertical" />
|
|
||||||
{{ terminalInfo.meta.name }}
|
|
||||||
</template>
|
|
||||||
</terminal-dialog>
|
|
||||||
|
|
||||||
<machine-edit
|
<el-button :disabled="data.status == -1" type="warning" @click="serviceManager(data)" link>脚本</el-button>
|
||||||
:title="machineEditDialog.title"
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
v-model:visible="machineEditDialog.visible"
|
|
||||||
v-model:machine="machineEditDialog.data"
|
|
||||||
@valChange="submitSuccess"
|
|
||||||
></machine-edit>
|
|
||||||
|
|
||||||
<process-list v-model:visible="processDialog.visible" v-model:machineId="processDialog.machineId" />
|
<el-dropdown @command="handleCommand">
|
||||||
|
<span class="el-dropdown-link-machine-list">
|
||||||
|
更多
|
||||||
|
<el-icon class="el-icon--right">
|
||||||
|
<arrow-down />
|
||||||
|
</el-icon>
|
||||||
|
</span>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item :command="{ type: 'detail', data }"> 详情 </el-dropdown-item>
|
||||||
|
|
||||||
<script-manage :title="serviceDialog.title" v-model:visible="serviceDialog.visible" v-model:machineId="serviceDialog.machineId" />
|
<el-dropdown-item :command="{ type: 'edit', data }" v-if="actionBtns[perms.updateMachine]"> 编辑 </el-dropdown-item>
|
||||||
|
|
||||||
<file-conf-list :title="fileDialog.title" v-model:visible="fileDialog.visible" v-model:machineId="fileDialog.machineId" />
|
<el-dropdown-item :command="{ type: 'process', data }" :disabled="data.status == -1"> 进程 </el-dropdown-item>
|
||||||
|
|
||||||
<machine-stats v-model:visible="machineStatsDialog.visible" :machineId="machineStatsDialog.machineId" :title="machineStatsDialog.title"></machine-stats>
|
<el-dropdown-item
|
||||||
|
:command="{ type: 'terminalRec', data }"
|
||||||
|
v-if="actionBtns[perms.updateMachine] && data.enableRecorder == 1"
|
||||||
|
>
|
||||||
|
终端回放
|
||||||
|
</el-dropdown-item>
|
||||||
|
|
||||||
<machine-rec v-model:visible="machineRecDialog.visible" :machineId="machineRecDialog.machineId" :title="machineRecDialog.title"></machine-rec>
|
<el-dropdown-item
|
||||||
|
:command="{ type: 'closeCli', data }"
|
||||||
|
v-if="actionBtns[perms.closeCli]"
|
||||||
|
:disabled="!data.hasCli || data.status == -1"
|
||||||
|
>
|
||||||
|
关闭连接
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</template>
|
||||||
|
</page-table>
|
||||||
|
|
||||||
|
<el-dialog v-model="infoDialog.visible">
|
||||||
|
<el-descriptions title="详情" :column="3" border>
|
||||||
|
<el-descriptions-item :span="1.5" label="机器id">{{ infoDialog.data.id }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item :span="1.5" label="名称">{{ infoDialog.data.name }}</el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item :span="3" label="标签路径">{{ infoDialog.data.tagPath }}</el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item :span="2" label="IP">{{ infoDialog.data.ip }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item :span="1" label="端口">{{ infoDialog.data.port }}</el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item :span="2" label="用户名">{{ infoDialog.data.username }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item :span="1" label="认证方式">
|
||||||
|
{{ infoDialog.data.authCertId > 1 ? '授权凭证' : '密码' }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item :span="3" label="备注">{{ infoDialog.data.remark }}</el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item :span="1.5" label="SSH隧道">{{ infoDialog.data.sshTunnelMachineId > 0 ? '是' : '否' }} </el-descriptions-item>
|
||||||
|
<el-descriptions-item :span="1.5" label="终端回放">{{ infoDialog.data.enableRecorder == 1 ? '是' : '否' }} </el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item :span="2" label="创建时间">{{ dateFormat(infoDialog.data.createTime) }} </el-descriptions-item>
|
||||||
|
<el-descriptions-item :span="1" label="创建者">{{ infoDialog.data.creator }}</el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item :span="2" label="更新时间">{{ dateFormat(infoDialog.data.updateTime) }} </el-descriptions-item>
|
||||||
|
<el-descriptions-item :span="1" label="修改者">{{ infoDialog.data.modifier }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<terminal-dialog ref="terminalDialogRef" :visibleMinimize="true">
|
||||||
|
<template #headerTitle="{ terminalInfo }">
|
||||||
|
{{ `${(terminalInfo.terminalId + '').slice(-2)}` }}
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
{{ `${terminalInfo.meta.username}@${terminalInfo.meta.ip}:${terminalInfo.meta.port}` }}
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
{{ terminalInfo.meta.name }}
|
||||||
|
</template>
|
||||||
|
</terminal-dialog>
|
||||||
|
|
||||||
|
<machine-edit
|
||||||
|
:title="machineEditDialog.title"
|
||||||
|
v-model:visible="machineEditDialog.visible"
|
||||||
|
v-model:machine="machineEditDialog.data"
|
||||||
|
@valChange="submitSuccess"
|
||||||
|
></machine-edit>
|
||||||
|
|
||||||
|
<process-list v-model:visible="processDialog.visible" v-model:machineId="processDialog.machineId" />
|
||||||
|
|
||||||
|
<script-manage :title="serviceDialog.title" v-model:visible="serviceDialog.visible" v-model:machineId="serviceDialog.machineId" />
|
||||||
|
|
||||||
|
<file-conf-list :title="fileDialog.title" v-model:visible="fileDialog.visible" v-model:machineId="fileDialog.machineId" />
|
||||||
|
|
||||||
|
<machine-stats
|
||||||
|
v-model:visible="machineStatsDialog.visible"
|
||||||
|
:machineId="machineStatsDialog.machineId"
|
||||||
|
:title="machineStatsDialog.title"
|
||||||
|
></machine-stats>
|
||||||
|
|
||||||
|
<machine-rec
|
||||||
|
v-model:visible="machineRecDialog.visible"
|
||||||
|
:machineId="machineRecDialog.machineId"
|
||||||
|
:title="machineRecDialog.title"
|
||||||
|
></machine-rec>
|
||||||
|
</div>
|
||||||
|
</Pane>
|
||||||
|
</Splitpanes>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -202,8 +218,9 @@ import { hasPerms } from '@/components/auth/auth';
|
|||||||
import { formatByteSize } from '@/common/utils/format';
|
import { formatByteSize } from '@/common/utils/format';
|
||||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
||||||
import { SearchItem } from '@/components/SearchForm';
|
import { SearchItem } from '@/components/SearchForm';
|
||||||
import { getTagPathSearchItem } from '../component/tag';
|
import { getTagPathSearchItem, NodeType, TagTreeNode } from '../component/tag';
|
||||||
|
import TagTree from '../component/TagTree.vue';
|
||||||
|
import { Splitpanes, Pane } from 'splitpanes';
|
||||||
// 组件
|
// 组件
|
||||||
const TerminalDialog = defineAsyncComponent(() => import('@/components/terminal/TerminalDialog.vue'));
|
const TerminalDialog = defineAsyncComponent(() => import('@/components/terminal/TerminalDialog.vue'));
|
||||||
const MachineEdit = defineAsyncComponent(() => import('./MachineEdit.vue'));
|
const MachineEdit = defineAsyncComponent(() => import('./MachineEdit.vue'));
|
||||||
@@ -235,7 +252,6 @@ const columns = [
|
|||||||
TableColumn.new('fs', '磁盘(挂载点=>可用/总)').isSlot().setAddWidth(20),
|
TableColumn.new('fs', '磁盘(挂载点=>可用/总)').isSlot().setAddWidth(20),
|
||||||
TableColumn.new('username', '用户名'),
|
TableColumn.new('username', '用户名'),
|
||||||
TableColumn.new('status', '状态').isSlot().setMinWidth(85),
|
TableColumn.new('status', '状态').isSlot().setMinWidth(85),
|
||||||
TableColumn.new('tagPath', '关联标签').isSlot().setAddWidth(10).alignCenter(),
|
|
||||||
TableColumn.new('remark', '备注'),
|
TableColumn.new('remark', '备注'),
|
||||||
TableColumn.new('action', '操作').isSlot().setMinWidth(238).fixedRight().alignCenter(),
|
TableColumn.new('action', '操作').isSlot().setMinWidth(238).fixedRight().alignCenter(),
|
||||||
];
|
];
|
||||||
@@ -243,6 +259,10 @@ const columns = [
|
|||||||
// 该用户拥有的的操作列按钮权限,使用v-if进行判断,v-auth对el-dropdown-item无效
|
// 该用户拥有的的操作列按钮权限,使用v-if进行判断,v-auth对el-dropdown-item无效
|
||||||
const actionBtns = hasPerms([perms.updateMachine, perms.closeCli]);
|
const actionBtns = hasPerms([perms.updateMachine, perms.closeCli]);
|
||||||
|
|
||||||
|
class MachineNodeType {
|
||||||
|
static Machine = 1;
|
||||||
|
}
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
params: {
|
params: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
@@ -251,6 +271,7 @@ const state = reactive({
|
|||||||
name: null,
|
name: null,
|
||||||
tagPath: '',
|
tagPath: '',
|
||||||
},
|
},
|
||||||
|
pageData: [] as any[],
|
||||||
infoDialog: {
|
infoDialog: {
|
||||||
visible: false,
|
visible: false,
|
||||||
data: null as any,
|
data: null as any,
|
||||||
@@ -291,7 +312,21 @@ const state = reactive({
|
|||||||
|
|
||||||
const { params, infoDialog, selectionData, serviceDialog, processDialog, fileDialog, machineStatsDialog, machineEditDialog, machineRecDialog } = toRefs(state);
|
const { params, infoDialog, selectionData, serviceDialog, processDialog, fileDialog, machineStatsDialog, machineEditDialog, machineRecDialog } = toRefs(state);
|
||||||
|
|
||||||
onMounted(async () => {});
|
const NodeTypeTagPath = new NodeType(TagTreeNode.TagPath).withLoadNodesFunc(async (node: any) => {
|
||||||
|
// 加载标签树下的机器列表
|
||||||
|
state.params.tagPath = node.key;
|
||||||
|
state.params.pageNum = 1;
|
||||||
|
state.params.pageSize = 1000;
|
||||||
|
const res = await search();
|
||||||
|
// 把list 根据name字段排序
|
||||||
|
res.list = res.list.sort((a: any, b: any) => a.name.localeCompare(b.name));
|
||||||
|
state.pageData = res.list;
|
||||||
|
return res.list.map((x: any) => new TagTreeNode(x.id, x.name, NodeTypeMachine).withParams(x).withIsLeaf(true));
|
||||||
|
});
|
||||||
|
|
||||||
|
const NodeTypeMachine = new NodeType(MachineNodeType.Machine).withNodeClickFunc((node: any) => {
|
||||||
|
state.pageData = [node.params];
|
||||||
|
});
|
||||||
|
|
||||||
const checkRouteTagPath = (query: any) => {
|
const checkRouteTagPath = (query: any) => {
|
||||||
if (route.query.tagPath) {
|
if (route.query.tagPath) {
|
||||||
@@ -421,7 +456,9 @@ const showMachineStats = async (machine: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const search = async () => {
|
const search = async () => {
|
||||||
pageTableRef.value.search();
|
const res = await machineApi.list.request(state.params);
|
||||||
|
state.pageData = res.list;
|
||||||
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
const submitSuccess = () => {
|
const submitSuccess = () => {
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ func (d *dbAppImpl) GetDbConn(dbId uint64, dbName string) (*dbi.DbConn, error) {
|
|||||||
|
|
||||||
checkDb := dbName
|
checkDb := dbName
|
||||||
// 兼容pgsql/dm db/schema模式
|
// 兼容pgsql/dm db/schema模式
|
||||||
if dbi.DbTypePostgres.Equal(instance.Type) || dbi.DbTypeGauss.Equal(instance.Type) || dbi.DbTypeDM.Equal(instance.Type) || dbi.DbTypeOracle.Equal(instance.Type) || dbi.DbTypeMssql.Equal(instance.Type) {
|
if dbi.DbTypePostgres.Equal(instance.Type) || dbi.DbTypeGauss.Equal(instance.Type) || dbi.DbTypeDM.Equal(instance.Type) || dbi.DbTypeOracle.Equal(instance.Type) || dbi.DbTypeMssql.Equal(instance.Type) || dbi.DbTypeKingbaseEs.Equal(instance.Type) || dbi.DbTypeVastbase.Equal(instance.Type) {
|
||||||
ss := strings.Split(dbName, "/")
|
ss := strings.Split(dbName, "/")
|
||||||
if len(ss) > 1 {
|
if len(ss) > 1 {
|
||||||
checkDb = ss[0]
|
checkDb = ss[0]
|
||||||
|
|||||||
@@ -11,14 +11,16 @@ import (
|
|||||||
type DbType string
|
type DbType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DbTypeMysql DbType = "mysql"
|
DbTypeMysql DbType = "mysql"
|
||||||
DbTypeMariadb DbType = "mariadb"
|
DbTypeMariadb DbType = "mariadb"
|
||||||
DbTypePostgres DbType = "postgres"
|
DbTypePostgres DbType = "postgres"
|
||||||
DbTypeGauss DbType = "gauss"
|
DbTypeGauss DbType = "gauss"
|
||||||
DbTypeDM DbType = "dm"
|
DbTypeDM DbType = "dm"
|
||||||
DbTypeOracle DbType = "oracle"
|
DbTypeOracle DbType = "oracle"
|
||||||
DbTypeSqlite DbType = "sqlite"
|
DbTypeSqlite DbType = "sqlite"
|
||||||
DbTypeMssql DbType = "mssql"
|
DbTypeMssql DbType = "mssql"
|
||||||
|
DbTypeKingbaseEs DbType = "kingbaseEs"
|
||||||
|
DbTypeVastbase DbType = "vastbase"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ToDbType(dbType string) DbType {
|
func ToDbType(dbType string) DbType {
|
||||||
@@ -44,7 +46,7 @@ func (dbType DbType) QuoteIdentifier(name string) string {
|
|||||||
switch dbType {
|
switch dbType {
|
||||||
case DbTypeMysql, DbTypeMariadb:
|
case DbTypeMysql, DbTypeMariadb:
|
||||||
return quoteIdentifier(name, "`")
|
return quoteIdentifier(name, "`")
|
||||||
case DbTypePostgres, DbTypeGauss:
|
case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
|
||||||
return quoteIdentifier(name, `"`)
|
return quoteIdentifier(name, `"`)
|
||||||
case DbTypeMssql:
|
case DbTypeMssql:
|
||||||
return fmt.Sprintf("[%s]", name)
|
return fmt.Sprintf("[%s]", name)
|
||||||
@@ -57,7 +59,7 @@ func (dbType DbType) RemoveQuote(name string) string {
|
|||||||
switch dbType {
|
switch dbType {
|
||||||
case DbTypeMysql, DbTypeMariadb:
|
case DbTypeMysql, DbTypeMariadb:
|
||||||
return removeQuote(name, "`")
|
return removeQuote(name, "`")
|
||||||
case DbTypePostgres, DbTypeGauss:
|
case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
|
||||||
return removeQuote(name, `"`)
|
return removeQuote(name, `"`)
|
||||||
default:
|
default:
|
||||||
return removeQuote(name, `"`)
|
return removeQuote(name, `"`)
|
||||||
@@ -70,7 +72,7 @@ func (dbType DbType) QuoteLiteral(literal string) string {
|
|||||||
literal = strings.ReplaceAll(literal, `\`, `\\`)
|
literal = strings.ReplaceAll(literal, `\`, `\\`)
|
||||||
literal = strings.ReplaceAll(literal, `'`, `''`)
|
literal = strings.ReplaceAll(literal, `'`, `''`)
|
||||||
return "'" + literal + "'"
|
return "'" + literal + "'"
|
||||||
case DbTypePostgres, DbTypeGauss:
|
case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
|
||||||
return pq.QuoteLiteral(literal)
|
return pq.QuoteLiteral(literal)
|
||||||
default:
|
default:
|
||||||
return pq.QuoteLiteral(literal)
|
return pq.QuoteLiteral(literal)
|
||||||
@@ -85,6 +87,10 @@ func (dbType DbType) MetaDbName() string {
|
|||||||
return "postgres"
|
return "postgres"
|
||||||
case DbTypeDM:
|
case DbTypeDM:
|
||||||
return ""
|
return ""
|
||||||
|
case DbTypeKingbaseEs:
|
||||||
|
return "security"
|
||||||
|
case DbTypeVastbase:
|
||||||
|
return "vastbase"
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -94,7 +100,7 @@ func (dbType DbType) Dialect() sqlparser.Dialect {
|
|||||||
switch dbType {
|
switch dbType {
|
||||||
case DbTypeMysql, DbTypeMariadb:
|
case DbTypeMysql, DbTypeMariadb:
|
||||||
return sqlparser.MysqlDialect{}
|
return sqlparser.MysqlDialect{}
|
||||||
case DbTypePostgres, DbTypeGauss:
|
case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
|
||||||
return sqlparser.PostgresDialect{}
|
return sqlparser.PostgresDialect{}
|
||||||
default:
|
default:
|
||||||
return sqlparser.PostgresDialect{}
|
return sqlparser.PostgresDialect{}
|
||||||
@@ -122,7 +128,7 @@ func (dbType DbType) StmtSetForeignKeyChecks(check bool) string {
|
|||||||
} else {
|
} else {
|
||||||
return "SET FOREIGN_KEY_CHECKS = 0;\n"
|
return "SET FOREIGN_KEY_CHECKS = 0;\n"
|
||||||
}
|
}
|
||||||
case DbTypePostgres, DbTypeGauss:
|
case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
|
||||||
// not currently supported postgres
|
// not currently supported postgres
|
||||||
return ""
|
return ""
|
||||||
default:
|
default:
|
||||||
@@ -134,7 +140,7 @@ func (dbType DbType) StmtUseDatabase(dbName string) string {
|
|||||||
switch dbType {
|
switch dbType {
|
||||||
case DbTypeMysql, DbTypeMariadb:
|
case DbTypeMysql, DbTypeMariadb:
|
||||||
return fmt.Sprintf("USE %s;\n", dbType.QuoteIdentifier(dbName))
|
return fmt.Sprintf("USE %s;\n", dbType.QuoteIdentifier(dbName))
|
||||||
case DbTypePostgres, DbTypeGauss:
|
case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
|
||||||
// not currently supported postgres
|
// not currently supported postgres
|
||||||
return ""
|
return ""
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
--MSSQL_DBS 数据库名信息
|
--MSSQL_DBS 数据库名信息
|
||||||
SELECT name AS dbname
|
SELECT name AS dbname
|
||||||
FROM sys.databases
|
FROM sys.databases
|
||||||
WHERE owner_sid = SUSER_SID()
|
|
||||||
and name not in ('master', 'tempdb', 'model', 'msdb')
|
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
--MSSQL_TABLE_DETAIL 查询表名和表注释
|
--MSSQL_TABLE_DETAIL 查询表名和表注释
|
||||||
SELECT t.name AS tableName,
|
SELECT t.name AS tableName,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
--ORACLE_DB_SCHEMAS 库schemas
|
--ORACLE_DB_SCHEMAS 库schemas
|
||||||
select distinct owner as SCHEMA_NAME
|
select USERNAME
|
||||||
from all_objects
|
from sys.all_users
|
||||||
order by owner
|
order by USERNAME
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
--ORACLE_TABLE_INFO 表详细信息
|
--ORACLE_TABLE_INFO 表详细信息
|
||||||
select a.TABLE_NAME,
|
select a.TABLE_NAME,
|
||||||
@@ -10,9 +10,9 @@ select a.TABLE_NAME,
|
|||||||
d.BYTES as DATA_LENGTH,
|
d.BYTES as DATA_LENGTH,
|
||||||
0 as INDEX_LENGTH,
|
0 as INDEX_LENGTH,
|
||||||
a.NUM_ROWS as TABLE_ROWS
|
a.NUM_ROWS as TABLE_ROWS
|
||||||
from all_tables a
|
from ALL_TABLES a
|
||||||
left join ALL_TAB_COMMENTS b on b.TABLE_NAME = a.TABLE_NAME AND b.OWNER = a.OWNER
|
left join ALL_TAB_COMMENTS b on b.TABLE_NAME = a.TABLE_NAME AND b.OWNER = a.OWNER
|
||||||
left join all_objects c on c.OBJECT_TYPE = 'TABLE' AND c.OWNER = a.OWNER AND c.OBJECT_NAME = a.TABLE_NAME
|
left join ALL_OBJECTS c on c.OBJECT_TYPE = 'TABLE' AND c.OWNER = a.OWNER AND c.OBJECT_NAME = a.TABLE_NAME
|
||||||
left join dba_segments d on d.SEGMENT_TYPE = 'TABLE' AND d.OWNER = a.OWNER AND d.SEGMENT_NAME = a.TABLE_NAME
|
left join dba_segments d on d.SEGMENT_TYPE = 'TABLE' AND d.OWNER = a.OWNER AND d.SEGMENT_NAME = a.TABLE_NAME
|
||||||
where a.owner = (SELECT sys_context('USERENV', 'CURRENT_SCHEMA') FROM dual)
|
where a.owner = (SELECT sys_context('USERENV', 'CURRENT_SCHEMA') FROM dual)
|
||||||
ORDER BY a.TABLE_NAME
|
ORDER BY a.TABLE_NAME
|
||||||
@@ -55,12 +55,12 @@ SELECT a.TABLE_NAME as TABLE_NAME,
|
|||||||
a.DATA_SCALE as NUM_SCALE,
|
a.DATA_SCALE as NUM_SCALE,
|
||||||
CASE WHEN d.pri IS NOT NULL THEN 1 ELSE 0 END as IS_PRIMARY_KEY,
|
CASE WHEN d.pri IS NOT NULL THEN 1 ELSE 0 END as IS_PRIMARY_KEY,
|
||||||
CASE WHEN a.IDENTITY_COLUMN = 'YES' THEN 1 ELSE 0 END as IS_IDENTITY
|
CASE WHEN a.IDENTITY_COLUMN = 'YES' THEN 1 ELSE 0 END as IS_IDENTITY
|
||||||
FROM all_tab_columns a
|
FROM ALL_TAB_COLUMNS a
|
||||||
LEFT JOIN all_col_comments b
|
LEFT JOIN ALL_COL_COMMENTS b
|
||||||
on a.OWNER = b.OWNER AND a.TABLE_NAME = b.TABLE_NAME AND a.COLUMN_NAME = b.COLUMN_NAME
|
on a.OWNER = b.OWNER AND a.TABLE_NAME = b.TABLE_NAME AND a.COLUMN_NAME = b.COLUMN_NAME
|
||||||
LEFT JOIN (select ac.TABLE_NAME, ac.OWNER, cc.COLUMN_NAME, 1 as pri
|
LEFT JOIN (select ac.TABLE_NAME, ac.OWNER, cc.COLUMN_NAME, 1 as pri
|
||||||
from all_constraints ac
|
from ALL_CONSTRAINTS ac
|
||||||
join all_cons_columns cc on cc.CONSTRAINT_NAME = ac.CONSTRAINT_NAME AND cc.OWNER = ac.OWNER
|
join ALL_CONS_COLUMNS cc on cc.CONSTRAINT_NAME = ac.CONSTRAINT_NAME AND cc.OWNER = ac.OWNER
|
||||||
where cc.CONSTRAINT_NAME IS NOT NULL
|
where cc.CONSTRAINT_NAME IS NOT NULL
|
||||||
AND ac.CONSTRAINT_TYPE = 'P') d
|
AND ac.CONSTRAINT_TYPE = 'P') d
|
||||||
on d.OWNER = a.OWNER AND d.TABLE_NAME = a.TABLE_NAME AND d.COLUMN_NAME = a.COLUMN_NAME
|
on d.OWNER = a.OWNER AND d.TABLE_NAME = a.TABLE_NAME AND d.COLUMN_NAME = a.COLUMN_NAME
|
||||||
|
|||||||
@@ -38,8 +38,17 @@ func (md *Meta) GetSqlDb(d *dbi.DbInfo) (*sql.DB, error) {
|
|||||||
query.Add("database", d.Database)
|
query.Add("database", d.Database)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
params := query.Encode()
|
||||||
|
if d.Params != "" {
|
||||||
|
if !strings.HasPrefix(d.Params, "&") {
|
||||||
|
params = params + "&" + d.Params
|
||||||
|
} else {
|
||||||
|
params = params + d.Params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const driverName = "mssql"
|
const driverName = "mssql"
|
||||||
dsn := fmt.Sprintf("sqlserver://%s:%s@%s:%d?%s", url.PathEscape(d.Username), url.PathEscape(d.Password), d.Host, d.Port, query.Encode())
|
dsn := fmt.Sprintf("sqlserver://%s:%s@%s:%d?%s", url.PathEscape(d.Username), url.PathEscape(d.Password), d.Host, d.Port, params)
|
||||||
return sql.Open(driverName, dsn)
|
return sql.Open(driverName, dsn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ func (od *OracleDialect) GetSchemas() ([]string, error) {
|
|||||||
}
|
}
|
||||||
schemaNames := make([]string, 0)
|
schemaNames := make([]string, 0)
|
||||||
for _, re := range res {
|
for _, re := range res {
|
||||||
schemaNames = append(schemaNames, anyx.ConvString(re["SCHEMA_NAME"]))
|
schemaNames = append(schemaNames, anyx.ConvString(re["USERNAME"]))
|
||||||
}
|
}
|
||||||
return schemaNames, nil
|
return schemaNames, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ type PgsqlDialect struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (md *PgsqlDialect) GetDbServer() (*dbi.DbServer, error) {
|
func (md *PgsqlDialect) GetDbServer() (*dbi.DbServer, error) {
|
||||||
_, res, err := md.dc.Query("SHOW server_version")
|
_, res, err := md.dc.Query("SELECT version() as server_version")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
dbi.Register(dbi.DbTypePostgres, new(PostgresMeta))
|
meta := new(PostgresMeta)
|
||||||
|
dbi.Register(dbi.DbTypePostgres, meta)
|
||||||
|
dbi.Register(dbi.DbTypeKingbaseEs, meta)
|
||||||
|
dbi.Register(dbi.DbTypeVastbase, meta)
|
||||||
|
|
||||||
gauss := new(PostgresMeta)
|
gauss := new(PostgresMeta)
|
||||||
gauss.Param = "dbtype=gauss"
|
gauss.Param = "dbtype=gauss"
|
||||||
@@ -40,16 +43,17 @@ func (md *PostgresMeta) GetSqlDb(d *dbi.DbInfo) (*sql.DB, error) {
|
|||||||
|
|
||||||
db := d.Database
|
db := d.Database
|
||||||
var dbParam string
|
var dbParam string
|
||||||
exsitSchema := false
|
existSchema := false
|
||||||
if db != "" {
|
if db == "" {
|
||||||
// postgres database可以使用db/schema表示,方便连接指定schema, 若不存在schema则使用默认schema
|
db = d.Type.MetaDbName()
|
||||||
ss := strings.Split(db, "/")
|
}
|
||||||
if len(ss) > 1 {
|
// postgres database可以使用db/schema表示,方便连接指定schema, 若不存在schema则使用默认schema
|
||||||
exsitSchema = true
|
ss := strings.Split(db, "/")
|
||||||
dbParam = fmt.Sprintf("dbname=%s search_path=%s", ss[0], ss[len(ss)-1])
|
if len(ss) > 1 {
|
||||||
} else {
|
existSchema = true
|
||||||
dbParam = "dbname=" + db
|
dbParam = fmt.Sprintf("dbname=%s search_path=%s", ss[0], ss[len(ss)-1])
|
||||||
}
|
} else {
|
||||||
|
dbParam = "dbname=" + db
|
||||||
}
|
}
|
||||||
|
|
||||||
dsn := fmt.Sprintf("host=%s port=%d user=%s password=%s %s sslmode=disable connect_timeout=8", d.Host, d.Port, d.Username, d.Password, dbParam)
|
dsn := fmt.Sprintf("host=%s port=%d user=%s password=%s %s sslmode=disable connect_timeout=8", d.Host, d.Port, d.Username, d.Password, dbParam)
|
||||||
@@ -62,7 +66,7 @@ func (md *PostgresMeta) GetSqlDb(d *dbi.DbInfo) (*sql.DB, error) {
|
|||||||
if strings.HasPrefix(param, "dbname=") {
|
if strings.HasPrefix(param, "dbname=") {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if exsitSchema && strings.HasPrefix(param, "search_path") {
|
if existSchema && strings.HasPrefix(param, "search_path") {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
Reference in New Issue
Block a user