mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 16: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",
 | 
			
		||||
      "unicode": "e683",
 | 
			
		||||
      "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 {
 | 
			
		||||
    size?: string;
 | 
			
		||||
    pageApi: Api; // 请求表格数据的 api
 | 
			
		||||
    pageApi?: Api; // 请求表格数据的 api
 | 
			
		||||
    columns: TableColumn[]; // 列配置项  ==> 必传
 | 
			
		||||
    showSelection?: boolean;
 | 
			
		||||
    selectable?: (row: any) => boolean; // 是否可选
 | 
			
		||||
@@ -257,7 +257,7 @@ const changeSimpleFormItem = (searchItem: 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.pageApi,
 | 
			
		||||
    queryForm,
 | 
			
		||||
@@ -288,6 +288,13 @@ watch(isShowSearch, () => {
 | 
			
		||||
    calcuTableHeight();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
watch(
 | 
			
		||||
    () => props.data,
 | 
			
		||||
    (newValue: any) => {
 | 
			
		||||
        tableData = newValue;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
onMounted(async () => {
 | 
			
		||||
    calcuTableHeight();
 | 
			
		||||
    useEventListener(window, 'resize', calcuTableHeight);
 | 
			
		||||
 
 | 
			
		||||
@@ -104,7 +104,11 @@ const loadTags = async () => {
 | 
			
		||||
    const tags = await tagApi.getResourceTagPaths.request({ resourceType: props.resourceType });
 | 
			
		||||
    const tagNodes = [];
 | 
			
		||||
    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;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,9 @@
 | 
			
		||||
        v-model="modelValue"
 | 
			
		||||
        @change="changeNode"
 | 
			
		||||
    >
 | 
			
		||||
        <template #prefix="{ node, data }">
 | 
			
		||||
            <slot name="iconPrefix" :node="node" :data="data" />
 | 
			
		||||
        </template>
 | 
			
		||||
        <template #default="{ node, data }">
 | 
			
		||||
            <span>
 | 
			
		||||
                <span v-if="data.type.value == TagTreeNode.TagPath">
 | 
			
		||||
@@ -33,7 +36,7 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<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 TagInfo from './TagInfo.vue';
 | 
			
		||||
import { tagApi } from '../tag/api';
 | 
			
		||||
 
 | 
			
		||||
@@ -89,6 +89,8 @@ export class NodeType {
 | 
			
		||||
 | 
			
		||||
    contextMenuItems: ContextmenuItem[];
 | 
			
		||||
 | 
			
		||||
    hasLoadNodesFunc: boolean;
 | 
			
		||||
 | 
			
		||||
    loadNodesFunc: (parentNode: TagTreeNode) => Promise<TagTreeNode[]>;
 | 
			
		||||
 | 
			
		||||
    nodeClickFunc: (node: TagTreeNode) => void;
 | 
			
		||||
@@ -104,6 +106,7 @@ export class NodeType {
 | 
			
		||||
     */
 | 
			
		||||
    withLoadNodesFunc(func: (parentNode: TagTreeNode) => Promise<TagTreeNode[]>) {
 | 
			
		||||
        this.loadNodesFunc = func;
 | 
			
		||||
        this.hasLoadNodesFunc = true;
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <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" />
 | 
			
		||||
                </el-tooltip>
 | 
			
		||||
            </template>
 | 
			
		||||
 
 | 
			
		||||
@@ -45,6 +45,7 @@
 | 
			
		||||
                            <db-select-tree
 | 
			
		||||
                                placeholder="请选择源数据库"
 | 
			
		||||
                                v-model:db-id="form.srcDbId"
 | 
			
		||||
                                v-model:inst-name="form.srcInstName"
 | 
			
		||||
                                v-model:db-name="form.srcDbName"
 | 
			
		||||
                                v-model:tag-path="form.srcTagPath"
 | 
			
		||||
                                v-model:db-type="form.srcDbType"
 | 
			
		||||
@@ -56,8 +57,10 @@
 | 
			
		||||
                            <db-select-tree
 | 
			
		||||
                                placeholder="请选择目标数据库"
 | 
			
		||||
                                v-model:db-id="form.targetDbId"
 | 
			
		||||
                                v-model:inst-name="form.targetInstName"
 | 
			
		||||
                                v-model:db-name="form.targetDbName"
 | 
			
		||||
                                v-model:tag-path="form.targetTagPath"
 | 
			
		||||
                                v-model:db-type="form.targetDbType"
 | 
			
		||||
                                @select-db="onSelectTargetDb"
 | 
			
		||||
                            />
 | 
			
		||||
                        </el-form-item>
 | 
			
		||||
@@ -182,7 +185,7 @@ import { ElMessage } from 'element-plus';
 | 
			
		||||
import DbSelectTree from '@/views/ops/db/component/DbSelectTree.vue';
 | 
			
		||||
import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
 | 
			
		||||
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';
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
@@ -227,13 +230,16 @@ type FormData = {
 | 
			
		||||
    taskName?: string;
 | 
			
		||||
    taskCron: string;
 | 
			
		||||
    srcDbId?: number;
 | 
			
		||||
    srcInstName?: string;
 | 
			
		||||
    srcDbName?: string;
 | 
			
		||||
    srcDbType?: string;
 | 
			
		||||
    srcTagPath?: string;
 | 
			
		||||
    targetDbId?: number;
 | 
			
		||||
    targetInstName?: string;
 | 
			
		||||
    targetDbName?: string;
 | 
			
		||||
    targetTagPath?: string;
 | 
			
		||||
    targetTableName?: string;
 | 
			
		||||
    targetDbType?: string;
 | 
			
		||||
    dataSql?: string;
 | 
			
		||||
    pageSize?: number;
 | 
			
		||||
    updField?: string;
 | 
			
		||||
@@ -304,7 +310,8 @@ watch(dialogVisible, async (newValue: boolean) => {
 | 
			
		||||
        // 初始化实例
 | 
			
		||||
        db.databases = db.database?.split(' ').sort() || [];
 | 
			
		||||
        state.srcDbInst = DbInst.getOrNewInst(db);
 | 
			
		||||
        state.form.srcDbType = state.srcDbInst.type
 | 
			
		||||
        state.form.srcDbType = state.srcDbInst.type;
 | 
			
		||||
        state.form.srcInstName = db.instanceName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //  初始化target数据源
 | 
			
		||||
@@ -315,6 +322,8 @@ watch(dialogVisible, async (newValue: boolean) => {
 | 
			
		||||
        // 初始化实例
 | 
			
		||||
        db.databases = db.database?.split(' ').sort() || [];
 | 
			
		||||
        state.targetDbInst = DbInst.getOrNewInst(db);
 | 
			
		||||
        state.form.targetDbType = state.targetDbInst.type;
 | 
			
		||||
        state.form.targetInstName = db.instanceName;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (targetDbId && state.form.targetDbName) {
 | 
			
		||||
@@ -414,15 +423,15 @@ const handleGetSrcFields = async () => {
 | 
			
		||||
 | 
			
		||||
    // 执行sql
 | 
			
		||||
    // oracle的分页关键字不一样
 | 
			
		||||
    let limit = ' limit 1'
 | 
			
		||||
    let limit = ' limit 1';
 | 
			
		||||
    if (state.form.srcDbType === DbType.oracle) {
 | 
			
		||||
      limit = ' where rownum <= 1'
 | 
			
		||||
        limit = ' where rownum <= 1';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const res = await dbApi.sqlExec.request({
 | 
			
		||||
        id: state.form.srcDbId,
 | 
			
		||||
        db: state.form.srcDbName,
 | 
			
		||||
        sql: `select * from (${state.form.dataSql}) t ${limit}`
 | 
			
		||||
        sql: `select * from (${state.form.dataSql}) t ${limit}`,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (!res.columns) {
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,9 @@
 | 
			
		||||
        :resource-type="TagResourceTypeEnum.Db.value"
 | 
			
		||||
        :tag-path-node-type="NodeTypeTagPath"
 | 
			
		||||
    >
 | 
			
		||||
        <template #iconPrefix>
 | 
			
		||||
            <SvgIcon v-if="dbType && getDbDialect(dbType)" :name="getDbDialect(dbType).getInfo().icon" :size="18" />
 | 
			
		||||
        </template>
 | 
			
		||||
        <template #prefix="{ data }">
 | 
			
		||||
            <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" />
 | 
			
		||||
@@ -27,6 +30,9 @@ const props = defineProps({
 | 
			
		||||
    dbId: {
 | 
			
		||||
        type: Number,
 | 
			
		||||
    },
 | 
			
		||||
    instName: {
 | 
			
		||||
        type: String,
 | 
			
		||||
    },
 | 
			
		||||
    dbName: {
 | 
			
		||||
        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({
 | 
			
		||||
    get: () => {
 | 
			
		||||
        return props.dbName ? `${props.tagPath} - ${props.dbId} - ${props.dbName}` : '';
 | 
			
		||||
        return props.dbName ? `${props.tagPath} > ${props.instName} > ${props.dbName}` : '';
 | 
			
		||||
    },
 | 
			
		||||
    set: () => {
 | 
			
		||||
        //
 | 
			
		||||
@@ -151,6 +157,7 @@ const changeNode = (nodeData: TagTreeNode) => {
 | 
			
		||||
    const params = nodeData.params;
 | 
			
		||||
    // postgres
 | 
			
		||||
    emits('update:dbName', params.db);
 | 
			
		||||
    emits('update:instName', params.name);
 | 
			
		||||
    emits('update:dbId', params.id);
 | 
			
		||||
    emits('update:tagPath', params.tagPath);
 | 
			
		||||
    emits('update:dbType', params.type);
 | 
			
		||||
 
 | 
			
		||||
@@ -272,6 +272,18 @@ watch(props, async (newValue) => {
 | 
			
		||||
    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 = () => {
 | 
			
		||||
    emit('update:visible', false);
 | 
			
		||||
    reset();
 | 
			
		||||
@@ -391,22 +403,22 @@ const genSql = () => {
 | 
			
		||||
    let data = state.tableData;
 | 
			
		||||
    // 创建表
 | 
			
		||||
    if (!props.data?.edit) {
 | 
			
		||||
        if (state.activeName === '1') {
 | 
			
		||||
            return dbDialect.getCreateTableSql(data);
 | 
			
		||||
        } else if (state.activeName === '2' && data.indexs.res.length > 0) {
 | 
			
		||||
            return dbDialect.getCreateIndexSql(data);
 | 
			
		||||
        let createTable = dbDialect.getCreateTableSql(data);
 | 
			
		||||
        let createIndex = '';
 | 
			
		||||
        if (data.indexs.res.length > 0) {
 | 
			
		||||
            createIndex = dbDialect.getCreateIndexSql(data);
 | 
			
		||||
        }
 | 
			
		||||
        return createTable + ';' + createIndex;
 | 
			
		||||
    } else {
 | 
			
		||||
        // 修改
 | 
			
		||||
        if (state.activeName === '1') {
 | 
			
		||||
        // 修改列
 | 
			
		||||
            let changeData = filterChangedData(state.tableData.fields.oldFields, state.tableData.fields.res, 'name');
 | 
			
		||||
            return dbDialect.getModifyColumnSql(data, data.tableName, changeData);
 | 
			
		||||
        } else if (state.activeName === '2') {
 | 
			
		||||
        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.indexs.oldIndexs, state.tableData.indexs.res, 'indexName');
 | 
			
		||||
            return dbDialect.getModifyIndexSql(data, data.tableName, changeData);
 | 
			
		||||
        }
 | 
			
		||||
        let changeIdxData = filterChangedData(state.tableData.indexs.oldIndexs, state.tableData.indexs.res, 'indexName');
 | 
			
		||||
        let idxSql = dbDialect.getModifyIndexSql(data, data.tableName, changeIdxData);
 | 
			
		||||
        // 修改表名
 | 
			
		||||
 | 
			
		||||
        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 { MssqlDialect } from '@/views/ops/db/dialect/mssql_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 {
 | 
			
		||||
    udtName: string;
 | 
			
		||||
@@ -122,13 +124,15 @@ export const DbType = {
 | 
			
		||||
    oracle: 'oracle',
 | 
			
		||||
    sqlite: 'sqlite',
 | 
			
		||||
    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兼容的数据库
 | 
			
		||||
export const noSchemaTypes = [DbType.mysql, DbType.mariadb, DbType.sqlite];
 | 
			
		||||
 | 
			
		||||
// 有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];
 | 
			
		||||
 | 
			
		||||
@@ -218,8 +222,8 @@ export const getDbDialectMap = () => {
 | 
			
		||||
    return dbType2DialectMap;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getDbDialect = (dbType: string): DbDialect => {
 | 
			
		||||
    return dbType2DialectMap.get(dbType) || mysqlDialect;
 | 
			
		||||
export const getDbDialect = (dbType?: string): DbDialect => {
 | 
			
		||||
    return dbType2DialectMap.get(dbType!) || mysqlDialect;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
(function () {
 | 
			
		||||
@@ -232,4 +236,6 @@ export const getDbDialect = (dbType: string): DbDialect => {
 | 
			
		||||
    registerDbDialect(DbType.oracle, new OracleDialect());
 | 
			
		||||
    registerDbDialect(DbType.sqlite, new SqliteDialect());
 | 
			
		||||
    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);
 | 
			
		||||
        // 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[] = [];
 | 
			
		||||
        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) {
 | 
			
		||||
                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(';');
 | 
			
		||||
@@ -367,6 +371,9 @@ class PostgresqlDialect implements DbDialect {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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 addIndexs: any[] = [];
 | 
			
		||||
@@ -400,9 +407,11 @@ class PostgresqlDialect implements DbDialect {
 | 
			
		||||
 | 
			
		||||
            if (addIndexs.length > 0) {
 | 
			
		||||
                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) {
 | 
			
		||||
                        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,18 +1,18 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div class="flex-all-center">
 | 
			
		||||
        <Splitpanes class="default-theme">
 | 
			
		||||
            <Pane size="20" max-size="30">
 | 
			
		||||
                <tag-tree :resource-type="TagResourceTypeEnum.Machine.value" :tag-path-node-type="NodeTypeTagPath" />
 | 
			
		||||
            </Pane>
 | 
			
		||||
 | 
			
		||||
            <Pane>
 | 
			
		||||
                <div>
 | 
			
		||||
        <page-table
 | 
			
		||||
            ref="pageTableRef"
 | 
			
		||||
            :page-api="machineApi.list"
 | 
			
		||||
            :before-query-fn="checkRouteTagPath"
 | 
			
		||||
            :search-items="searchItems"
 | 
			
		||||
            v-model:query-form="params"
 | 
			
		||||
            :show-selection="true"
 | 
			
		||||
            v-model:selection-data="state.selectionData"
 | 
			
		||||
            :columns="columns"
 | 
			
		||||
        >
 | 
			
		||||
                    <page-table :data="state.pageData" :pageable="false" :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>
 | 
			
		||||
                            <el-button v-auth="perms.delMachine" :disabled="selectionData.length < 1" @click="deleteMachine()" type="danger" icon="delete"
 | 
			
		||||
                                >删除</el-button
 | 
			
		||||
                            >
 | 
			
		||||
                        </template>
 | 
			
		||||
 | 
			
		||||
                        <template #ipPort="{ data }">
 | 
			
		||||
@@ -49,7 +49,13 @@
 | 
			
		||||
                                    </el-text>
 | 
			
		||||
 | 
			
		||||
                                    <!-- 展示剩余的磁盘信息 -->
 | 
			
		||||
                        <el-popover :show-after="300" v-if="data.stat.fsInfos.length > 2 && idx == 1" placement="top-start" width="230" trigger="hover">
 | 
			
		||||
                                    <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>
 | 
			
		||||
@@ -79,10 +85,6 @@
 | 
			
		||||
                            ></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">
 | 
			
		||||
@@ -115,7 +117,10 @@
 | 
			
		||||
 | 
			
		||||
                                        <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
 | 
			
		||||
                                            :command="{ type: 'terminalRec', data }"
 | 
			
		||||
                                            v-if="actionBtns[perms.updateMachine] && data.enableRecorder == 1"
 | 
			
		||||
                                        >
 | 
			
		||||
                                            终端回放
 | 
			
		||||
                                        </el-dropdown-item>
 | 
			
		||||
 | 
			
		||||
@@ -183,9 +188,20 @@
 | 
			
		||||
 | 
			
		||||
                    <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-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>
 | 
			
		||||
                    <machine-rec
 | 
			
		||||
                        v-model:visible="machineRecDialog.visible"
 | 
			
		||||
                        :machineId="machineRecDialog.machineId"
 | 
			
		||||
                        :title="machineRecDialog.title"
 | 
			
		||||
                    ></machine-rec>
 | 
			
		||||
                </div>
 | 
			
		||||
            </Pane>
 | 
			
		||||
        </Splitpanes>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
@@ -202,8 +218,9 @@ import { hasPerms } from '@/components/auth/auth';
 | 
			
		||||
import { formatByteSize } from '@/common/utils/format';
 | 
			
		||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
 | 
			
		||||
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 MachineEdit = defineAsyncComponent(() => import('./MachineEdit.vue'));
 | 
			
		||||
@@ -235,7 +252,6 @@ const columns = [
 | 
			
		||||
    TableColumn.new('fs', '磁盘(挂载点=>可用/总)').isSlot().setAddWidth(20),
 | 
			
		||||
    TableColumn.new('username', '用户名'),
 | 
			
		||||
    TableColumn.new('status', '状态').isSlot().setMinWidth(85),
 | 
			
		||||
    TableColumn.new('tagPath', '关联标签').isSlot().setAddWidth(10).alignCenter(),
 | 
			
		||||
    TableColumn.new('remark', '备注'),
 | 
			
		||||
    TableColumn.new('action', '操作').isSlot().setMinWidth(238).fixedRight().alignCenter(),
 | 
			
		||||
];
 | 
			
		||||
@@ -243,6 +259,10 @@ const columns = [
 | 
			
		||||
// 该用户拥有的的操作列按钮权限,使用v-if进行判断,v-auth对el-dropdown-item无效
 | 
			
		||||
const actionBtns = hasPerms([perms.updateMachine, perms.closeCli]);
 | 
			
		||||
 | 
			
		||||
class MachineNodeType {
 | 
			
		||||
    static Machine = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const state = reactive({
 | 
			
		||||
    params: {
 | 
			
		||||
        pageNum: 1,
 | 
			
		||||
@@ -251,6 +271,7 @@ const state = reactive({
 | 
			
		||||
        name: null,
 | 
			
		||||
        tagPath: '',
 | 
			
		||||
    },
 | 
			
		||||
    pageData: [] as any[],
 | 
			
		||||
    infoDialog: {
 | 
			
		||||
        visible: false,
 | 
			
		||||
        data: null as any,
 | 
			
		||||
@@ -291,7 +312,21 @@ const state = reactive({
 | 
			
		||||
 | 
			
		||||
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) => {
 | 
			
		||||
    if (route.query.tagPath) {
 | 
			
		||||
@@ -421,7 +456,9 @@ const showMachineStats = async (machine: any) => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const search = async () => {
 | 
			
		||||
    pageTableRef.value.search();
 | 
			
		||||
    const res = await machineApi.list.request(state.params);
 | 
			
		||||
    state.pageData = res.list;
 | 
			
		||||
    return res;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const submitSuccess = () => {
 | 
			
		||||
 
 | 
			
		||||
@@ -154,7 +154,7 @@ func (d *dbAppImpl) GetDbConn(dbId uint64, dbName string) (*dbi.DbConn, error) {
 | 
			
		||||
 | 
			
		||||
		checkDb := dbName
 | 
			
		||||
		// 兼容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, "/")
 | 
			
		||||
			if len(ss) > 1 {
 | 
			
		||||
				checkDb = ss[0]
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,8 @@ const (
 | 
			
		||||
	DbTypeOracle     DbType = "oracle"
 | 
			
		||||
	DbTypeSqlite     DbType = "sqlite"
 | 
			
		||||
	DbTypeMssql      DbType = "mssql"
 | 
			
		||||
	DbTypeKingbaseEs DbType = "kingbaseEs"
 | 
			
		||||
	DbTypeVastbase   DbType = "vastbase"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func ToDbType(dbType string) DbType {
 | 
			
		||||
@@ -44,7 +46,7 @@ func (dbType DbType) QuoteIdentifier(name string) string {
 | 
			
		||||
	switch dbType {
 | 
			
		||||
	case DbTypeMysql, DbTypeMariadb:
 | 
			
		||||
		return quoteIdentifier(name, "`")
 | 
			
		||||
	case DbTypePostgres, DbTypeGauss:
 | 
			
		||||
	case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
 | 
			
		||||
		return quoteIdentifier(name, `"`)
 | 
			
		||||
	case DbTypeMssql:
 | 
			
		||||
		return fmt.Sprintf("[%s]", name)
 | 
			
		||||
@@ -57,7 +59,7 @@ func (dbType DbType) RemoveQuote(name string) string {
 | 
			
		||||
	switch dbType {
 | 
			
		||||
	case DbTypeMysql, DbTypeMariadb:
 | 
			
		||||
		return removeQuote(name, "`")
 | 
			
		||||
	case DbTypePostgres, DbTypeGauss:
 | 
			
		||||
	case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
 | 
			
		||||
		return removeQuote(name, `"`)
 | 
			
		||||
	default:
 | 
			
		||||
		return removeQuote(name, `"`)
 | 
			
		||||
@@ -70,7 +72,7 @@ func (dbType DbType) QuoteLiteral(literal string) string {
 | 
			
		||||
		literal = strings.ReplaceAll(literal, `\`, `\\`)
 | 
			
		||||
		literal = strings.ReplaceAll(literal, `'`, `''`)
 | 
			
		||||
		return "'" + literal + "'"
 | 
			
		||||
	case DbTypePostgres, DbTypeGauss:
 | 
			
		||||
	case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
 | 
			
		||||
		return pq.QuoteLiteral(literal)
 | 
			
		||||
	default:
 | 
			
		||||
		return pq.QuoteLiteral(literal)
 | 
			
		||||
@@ -85,6 +87,10 @@ func (dbType DbType) MetaDbName() string {
 | 
			
		||||
		return "postgres"
 | 
			
		||||
	case DbTypeDM:
 | 
			
		||||
		return ""
 | 
			
		||||
	case DbTypeKingbaseEs:
 | 
			
		||||
		return "security"
 | 
			
		||||
	case DbTypeVastbase:
 | 
			
		||||
		return "vastbase"
 | 
			
		||||
	default:
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
@@ -94,7 +100,7 @@ func (dbType DbType) Dialect() sqlparser.Dialect {
 | 
			
		||||
	switch dbType {
 | 
			
		||||
	case DbTypeMysql, DbTypeMariadb:
 | 
			
		||||
		return sqlparser.MysqlDialect{}
 | 
			
		||||
	case DbTypePostgres, DbTypeGauss:
 | 
			
		||||
	case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
 | 
			
		||||
		return sqlparser.PostgresDialect{}
 | 
			
		||||
	default:
 | 
			
		||||
		return sqlparser.PostgresDialect{}
 | 
			
		||||
@@ -122,7 +128,7 @@ func (dbType DbType) StmtSetForeignKeyChecks(check bool) string {
 | 
			
		||||
		} else {
 | 
			
		||||
			return "SET FOREIGN_KEY_CHECKS = 0;\n"
 | 
			
		||||
		}
 | 
			
		||||
	case DbTypePostgres, DbTypeGauss:
 | 
			
		||||
	case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
 | 
			
		||||
		// not currently supported postgres
 | 
			
		||||
		return ""
 | 
			
		||||
	default:
 | 
			
		||||
@@ -134,7 +140,7 @@ func (dbType DbType) StmtUseDatabase(dbName string) string {
 | 
			
		||||
	switch dbType {
 | 
			
		||||
	case DbTypeMysql, DbTypeMariadb:
 | 
			
		||||
		return fmt.Sprintf("USE %s;\n", dbType.QuoteIdentifier(dbName))
 | 
			
		||||
	case DbTypePostgres, DbTypeGauss:
 | 
			
		||||
	case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
 | 
			
		||||
		// not currently supported postgres
 | 
			
		||||
		return ""
 | 
			
		||||
	default:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,6 @@
 | 
			
		||||
--MSSQL_DBS 数据库名信息
 | 
			
		||||
SELECT name AS dbname
 | 
			
		||||
FROM sys.databases
 | 
			
		||||
WHERE owner_sid = SUSER_SID()
 | 
			
		||||
  and name not in ('master', 'tempdb', 'model', 'msdb')
 | 
			
		||||
---------------------------------------
 | 
			
		||||
--MSSQL_TABLE_DETAIL 查询表名和表注释
 | 
			
		||||
SELECT t.name   AS tableName,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
--ORACLE_DB_SCHEMAS 库schemas
 | 
			
		||||
select distinct owner as SCHEMA_NAME
 | 
			
		||||
from all_objects
 | 
			
		||||
order by owner
 | 
			
		||||
select USERNAME
 | 
			
		||||
from sys.all_users
 | 
			
		||||
order by USERNAME
 | 
			
		||||
---------------------------------------
 | 
			
		||||
--ORACLE_TABLE_INFO 表详细信息
 | 
			
		||||
select a.TABLE_NAME,
 | 
			
		||||
@@ -10,9 +10,9 @@ select a.TABLE_NAME,
 | 
			
		||||
       d.BYTES    as DATA_LENGTH,
 | 
			
		||||
       0          as INDEX_LENGTH,
 | 
			
		||||
       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_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
 | 
			
		||||
where a.owner = (SELECT sys_context('USERENV', 'CURRENT_SCHEMA') FROM dual)
 | 
			
		||||
ORDER BY a.TABLE_NAME
 | 
			
		||||
@@ -55,12 +55,12 @@ SELECT a.TABLE_NAME                                              as TABLE_NAME,
 | 
			
		||||
       a.DATA_SCALE                                              as NUM_SCALE,
 | 
			
		||||
       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
 | 
			
		||||
FROM all_tab_columns a
 | 
			
		||||
         LEFT JOIN all_col_comments b
 | 
			
		||||
FROM ALL_TAB_COLUMNS a
 | 
			
		||||
         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
 | 
			
		||||
         LEFT JOIN (select ac.TABLE_NAME, ac.OWNER, cc.COLUMN_NAME, 1 as pri
 | 
			
		||||
                    from all_constraints ac
 | 
			
		||||
                             join all_cons_columns cc on cc.CONSTRAINT_NAME = ac.CONSTRAINT_NAME AND cc.OWNER = ac.OWNER
 | 
			
		||||
                    from ALL_CONSTRAINTS ac
 | 
			
		||||
                             join ALL_CONS_COLUMNS cc on cc.CONSTRAINT_NAME = ac.CONSTRAINT_NAME AND cc.OWNER = ac.OWNER
 | 
			
		||||
                    where cc.CONSTRAINT_NAME IS NOT NULL
 | 
			
		||||
                      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
 | 
			
		||||
 
 | 
			
		||||
@@ -38,8 +38,17 @@ func (md *Meta) GetSqlDb(d *dbi.DbInfo) (*sql.DB, error) {
 | 
			
		||||
			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"
 | 
			
		||||
	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)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -242,7 +242,7 @@ func (od *OracleDialect) GetSchemas() ([]string, error) {
 | 
			
		||||
	}
 | 
			
		||||
	schemaNames := make([]string, 0)
 | 
			
		||||
	for _, re := range res {
 | 
			
		||||
		schemaNames = append(schemaNames, anyx.ConvString(re["SCHEMA_NAME"]))
 | 
			
		||||
		schemaNames = append(schemaNames, anyx.ConvString(re["USERNAME"]))
 | 
			
		||||
	}
 | 
			
		||||
	return schemaNames, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ type PgsqlDialect struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,10 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
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.Param = "dbtype=gauss"
 | 
			
		||||
@@ -40,17 +43,18 @@ func (md *PostgresMeta) GetSqlDb(d *dbi.DbInfo) (*sql.DB, error) {
 | 
			
		||||
 | 
			
		||||
	db := d.Database
 | 
			
		||||
	var dbParam string
 | 
			
		||||
	exsitSchema := false
 | 
			
		||||
	if db != "" {
 | 
			
		||||
	existSchema := false
 | 
			
		||||
	if db == "" {
 | 
			
		||||
		db = d.Type.MetaDbName()
 | 
			
		||||
	}
 | 
			
		||||
	// postgres database可以使用db/schema表示,方便连接指定schema, 若不存在schema则使用默认schema
 | 
			
		||||
	ss := strings.Split(db, "/")
 | 
			
		||||
	if len(ss) > 1 {
 | 
			
		||||
			exsitSchema = true
 | 
			
		||||
		existSchema = true
 | 
			
		||||
		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)
 | 
			
		||||
	// 存在额外指定参数,则拼接该连接参数
 | 
			
		||||
@@ -62,7 +66,7 @@ func (md *PostgresMeta) GetSqlDb(d *dbi.DbInfo) (*sql.DB, error) {
 | 
			
		||||
				if strings.HasPrefix(param, "dbname=") {
 | 
			
		||||
					return true
 | 
			
		||||
				}
 | 
			
		||||
				if exsitSchema && strings.HasPrefix(param, "search_path") {
 | 
			
		||||
				if existSchema && strings.HasPrefix(param, "search_path") {
 | 
			
		||||
					return true
 | 
			
		||||
				}
 | 
			
		||||
				return false
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user