mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-02 15:30:25 +08:00
!97 一些优化
* refactor: 重构表格分页组件,适配大数据量分页 * fix:定时任务修复 * feat: gaussdb单独提出来
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -81,6 +81,13 @@
|
||||
"font_class": "MSSQLNATIVE",
|
||||
"unicode": "e600",
|
||||
"unicode_decimal": 58880
|
||||
},
|
||||
{
|
||||
"icon_id": "7699332",
|
||||
"name": "gaussdb",
|
||||
"font_class": "gauss",
|
||||
"unicode": "e683",
|
||||
"unicode_decimal": 59011
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,13 +9,18 @@
|
||||
</el-form-item>
|
||||
<el-form-item prop="type" label="类型" required>
|
||||
<el-select @change="changeDbType" style="width: 100%" v-model="form.type" placeholder="请选择数据库类型">
|
||||
<el-option v-for="(dbTypeAndDialect, key) in getDbDialectMap()" :key="key" :value="dbTypeAndDialect[0]">
|
||||
<SvgIcon :name="dbTypeAndDialect[1].getInfo().icon" :size="18" />
|
||||
<el-option
|
||||
v-for="(dbTypeAndDialect, key) in getDbDialectMap()"
|
||||
:key="key"
|
||||
:value="dbTypeAndDialect[0]"
|
||||
:label="dbTypeAndDialect[1].getInfo().name"
|
||||
>
|
||||
<SvgIcon :name="dbTypeAndDialect[1].getInfo().icon" :size="20" />
|
||||
{{ dbTypeAndDialect[1].getInfo().name }}
|
||||
</el-option>
|
||||
|
||||
<template #prefix>
|
||||
<SvgIcon :name="getDbDialect(form.type).getInfo().icon" :size="18" />
|
||||
<SvgIcon :name="getDbDialect(form.type).getInfo().icon" :size="20" />
|
||||
</template>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
@@ -443,7 +443,7 @@ onBeforeUnmount(() => {
|
||||
* 设置editor高度和数据表高度
|
||||
*/
|
||||
const setHeight = () => {
|
||||
state.dataTabsTableHeight = window.innerHeight - 270 + 'px';
|
||||
state.dataTabsTableHeight = window.innerHeight - 253 + 'px';
|
||||
state.tablesOpHeight = window.innerHeight - 225 + 'px';
|
||||
};
|
||||
|
||||
|
||||
@@ -158,21 +158,62 @@
|
||||
@data-delete="onRefresh"
|
||||
></db-table-data>
|
||||
|
||||
<el-row type="flex" class="mt5" justify="center">
|
||||
<el-pagination
|
||||
small
|
||||
:total="count"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="pageChange()"
|
||||
layout="prev, pager, next, total, sizes, jumper"
|
||||
v-model:current-page="pageNum"
|
||||
v-model:page-size="pageSize"
|
||||
:page-sizes="pageSizes"
|
||||
></el-pagination>
|
||||
<el-row type="flex" class="mt5" :gutter="10" justify="end" style="user-select: none">
|
||||
<el-col :span="12">
|
||||
<el-text
|
||||
style="color: var(--el-color-info-light-3); font-size: 12px; margin-top: 5px"
|
||||
class="is-truncated"
|
||||
@click="handleCopySql(sql)"
|
||||
:title="sql"
|
||||
>{{ sql }}</el-text
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-row :gutter="10" justify="center">
|
||||
<el-link class="op-page" :underline="false" @click="pageNum = 1" :disabled="pageNum == 1" icon="DArrowLeft" title="首页" />
|
||||
<el-link class="op-page" :underline="false" @click="pageNum = --pageNum || 1" :disabled="pageNum == 1" icon="Back" title="上一页" />
|
||||
<div class="op-page">
|
||||
<el-input-number
|
||||
style="width: 50px"
|
||||
:controls="false"
|
||||
:min="1"
|
||||
v-model="state.setPageNum"
|
||||
size="small"
|
||||
@blur="handleSetPageNum"
|
||||
@keydown.enter="handleSetPageNum"
|
||||
/>
|
||||
</div>
|
||||
<el-link class="op-page" :underline="false" @click="++pageNum" icon="Right" />
|
||||
<el-link class="op-page" :underline="false" @click="handleEndPage" icon="DArrowRight" />
|
||||
<div style="width: 90px; margin-left: 20px" class="op-page">
|
||||
<el-select size="small" :default-first-option="true" v-model="pageSize" @change="handleSizeChange">
|
||||
<el-option
|
||||
style="font-size: 12px; height: 24px; line-height: 24px"
|
||||
v-for="(op, i) in pageSizes"
|
||||
:key="i"
|
||||
:label="op + '条/页'"
|
||||
:value="op"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
<el-link
|
||||
class="op-page"
|
||||
style="margin-left: 20px"
|
||||
v-if="!state.counting"
|
||||
:underline="false"
|
||||
@click="handleCount"
|
||||
icon="Stopwatch"
|
||||
title="计数"
|
||||
/>
|
||||
<el-link class="op-page" style="margin-left: 20px" v-if="state.counting" :underline="false" title="计数中...">
|
||||
<el-icon class="is-loading">
|
||||
<Loading />
|
||||
</el-icon>
|
||||
</el-link>
|
||||
<el-text class="op-page" style="font-size: 12px" v-if="state.showTotal">总 {{ state.total }} 条</el-text>
|
||||
</el-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div style="padding: 0 10px">
|
||||
<span style="color: var(--el-color-info-light-3)" class="font10 el-text el-text--small is-truncated">{{ state.sql }}</span>
|
||||
</div>
|
||||
|
||||
<el-dialog v-model="conditionDialog.visible" :title="conditionDialog.title" width="420px">
|
||||
<el-row>
|
||||
@@ -242,6 +283,7 @@ import { DbDialect, getDbDialect } from '@/views/ops/db/dialect';
|
||||
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||
import ColumnFormItem from './ColumnFormItem.vue';
|
||||
import { useEventListener, useStorage } from '@vueuse/core';
|
||||
import { copyToClipboard } from '@/common/utils/string';
|
||||
|
||||
const props = defineProps({
|
||||
dbId: {
|
||||
@@ -290,7 +332,10 @@ const state = reactive({
|
||||
defaultPageSize * 40,
|
||||
defaultPageSize * 80,
|
||||
],
|
||||
count: 0,
|
||||
setPageNum: 0,
|
||||
total: 0,
|
||||
showTotal: 0,
|
||||
counting: false,
|
||||
selectionDatas: [] as any,
|
||||
condPopVisible: false,
|
||||
columnNameSearch: '',
|
||||
@@ -314,7 +359,7 @@ const state = reactive({
|
||||
dbDialect: {} as DbDialect,
|
||||
});
|
||||
|
||||
const { datas, condition, loading, columns, pageNum, pageSize, pageSizes, count, hasUpdatedFileds, conditionDialog, addDataDialog, dbDialect } = toRefs(state);
|
||||
const { datas, condition, loading, columns, pageNum, pageSize, pageSizes, sql, hasUpdatedFileds, conditionDialog, addDataDialog, dbDialect } = toRefs(state);
|
||||
|
||||
watch(
|
||||
() => props.tableHeight,
|
||||
@@ -347,18 +392,19 @@ const onRefresh = async () => {
|
||||
await selectData();
|
||||
};
|
||||
|
||||
/**
|
||||
* 数据tab修改页数
|
||||
*/
|
||||
const pageChange = async () => {
|
||||
await selectData();
|
||||
};
|
||||
watch(
|
||||
() => state.pageNum,
|
||||
async () => {
|
||||
await selectData();
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 单表数据信息查询数据
|
||||
*/
|
||||
const selectData = async () => {
|
||||
state.loading = true;
|
||||
state.setPageNum = state.pageNum;
|
||||
const dbInst = getNowDbInst();
|
||||
const db = props.dbName;
|
||||
const table = props.tableName;
|
||||
@@ -371,16 +417,10 @@ const selectData = async () => {
|
||||
state.columns = columns;
|
||||
}
|
||||
|
||||
const countRes = await dbInst.runSql(db, dbInst.getDefaultCountSql(table, state.condition));
|
||||
state.count = parseInt(countRes.res[0].count || countRes.res[0].COUNT || 0);
|
||||
let sql = dbInst.getDefaultSelectSql(db, table, state.condition, state.orderBy, state.pageNum, state.pageSize);
|
||||
state.sql = sql;
|
||||
if (state.count > 0) {
|
||||
const colAndData: any = await dbInst.runSql(db, sql);
|
||||
state.datas = colAndData.res;
|
||||
} else {
|
||||
state.datas = [];
|
||||
}
|
||||
const colAndData: any = await dbInst.runSql(db, sql);
|
||||
state.datas = colAndData.res;
|
||||
} finally {
|
||||
state.loading = false;
|
||||
}
|
||||
@@ -392,6 +432,38 @@ const handleSizeChange = async (size: any) => {
|
||||
await selectData();
|
||||
};
|
||||
|
||||
const handleEndPage = async () => {
|
||||
await handleCount();
|
||||
state.pageNum = Math.ceil(state.total / state.pageSize);
|
||||
await selectData();
|
||||
};
|
||||
|
||||
const handleSetPageNum = async () => {
|
||||
state.pageNum = state.setPageNum;
|
||||
await selectData();
|
||||
};
|
||||
const handleCount = async () => {
|
||||
state.counting = true;
|
||||
|
||||
try {
|
||||
const db = props.dbName;
|
||||
const table = props.tableName;
|
||||
const dbInst = getNowDbInst();
|
||||
const countRes = await dbInst.runSql(db, dbInst.getDefaultCountSql(table, state.condition));
|
||||
state.total = parseInt(countRes.res[0].count || countRes.res[0].COUNT || 0);
|
||||
state.showTotal = true;
|
||||
} catch (e) {
|
||||
/* empty */
|
||||
}
|
||||
|
||||
state.counting = false;
|
||||
};
|
||||
|
||||
const handleCopySql = async (sql: string) => {
|
||||
await copyToClipboard(sql);
|
||||
ElMessage.success('复制成功');
|
||||
};
|
||||
|
||||
// 完整的条件,每次选中后会重置条件框内容,故需要这个变量在获取建议时将文本框内容保存
|
||||
let completeCond = '';
|
||||
// 是否存在列建议
|
||||
@@ -586,4 +658,8 @@ const addRow = async () => {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
<style lang="scss">
|
||||
.op-page {
|
||||
margin-left: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
17
mayfly_go_web/src/views/ops/db/dialect/gauss_dialect.ts
Normal file
17
mayfly_go_web/src/views/ops/db/dialect/gauss_dialect.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { PostgresqlDialect } from '@/views/ops/db/dialect/postgres_dialect';
|
||||
import { DialectInfo } from '@/views/ops/db/dialect/index';
|
||||
|
||||
let gsDialectInfo: DialectInfo;
|
||||
export class GaussDialect extends PostgresqlDialect {
|
||||
getInfo(): DialectInfo {
|
||||
if (gsDialectInfo) {
|
||||
return gsDialectInfo;
|
||||
}
|
||||
|
||||
gsDialectInfo = {} as DialectInfo;
|
||||
Object.assign(gsDialectInfo, super.getInfo());
|
||||
gsDialectInfo.icon = 'iconfont icon-gauss';
|
||||
gsDialectInfo.name = 'GaussDB';
|
||||
return gsDialectInfo;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import { OracleDialect } from '@/views/ops/db/dialect/oracle_dialect';
|
||||
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';
|
||||
|
||||
export interface sqlColumnType {
|
||||
udtName: string;
|
||||
@@ -116,6 +117,7 @@ export const DbType = {
|
||||
mysql: 'mysql',
|
||||
mariadb: 'mariadb',
|
||||
postgresql: 'postgres',
|
||||
gauss: 'gauss',
|
||||
dm: 'dm', // 达梦
|
||||
oracle: 'oracle',
|
||||
sqlite: 'sqlite',
|
||||
@@ -126,7 +128,7 @@ export const DbType = {
|
||||
export const noSchemaTypes = [DbType.mysql, DbType.mariadb, DbType.sqlite];
|
||||
|
||||
// 有schema层的数据库
|
||||
export const schemaDbTypes = [DbType.postgresql, DbType.dm, DbType.oracle, DbType.mssql];
|
||||
export const schemaDbTypes = [DbType.postgresql, DbType.gauss, DbType.dm, DbType.oracle, DbType.mssql];
|
||||
|
||||
export const editDbTypes = [...noSchemaTypes, ...schemaDbTypes];
|
||||
|
||||
@@ -225,6 +227,7 @@ export const getDbDialect = (dbType: string): DbDialect => {
|
||||
registerDbDialect(DbType.mysql, mysqlDialect);
|
||||
registerDbDialect(DbType.mariadb, new MariadbDialect());
|
||||
registerDbDialect(DbType.postgresql, new PostgresqlDialect());
|
||||
registerDbDialect(DbType.gauss, new GaussDialect());
|
||||
registerDbDialect(DbType.dm, new DMDialect());
|
||||
registerDbDialect(DbType.oracle, new OracleDialect());
|
||||
registerDbDialect(DbType.sqlite, new SqliteDialect());
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type DataSyncTask struct {
|
||||
@@ -46,13 +45,6 @@ func (d *DataSyncTask) SaveTask(rc *req.Ctx) {
|
||||
task.DataSql = sql
|
||||
form.DataSql = sql
|
||||
|
||||
key := task.TaskKey
|
||||
// 判断key为空就生成随机key
|
||||
if key == "" {
|
||||
key = uuid.New().String()
|
||||
task.TaskKey = key
|
||||
}
|
||||
|
||||
rc.ReqParam = form
|
||||
biz.ErrIsNil(d.DataSyncTaskApp.Save(rc.MetaCtx, task))
|
||||
}
|
||||
@@ -88,7 +80,7 @@ func (d *DataSyncTask) ChangeStatus(rc *req.Ctx) {
|
||||
func (d *DataSyncTask) Run(rc *req.Ctx) {
|
||||
taskId := getTaskId(rc.GinCtx)
|
||||
rc.ReqParam = taskId
|
||||
d.DataSyncTaskApp.RunCronJob(taskId)
|
||||
_ = d.DataSyncTaskApp.RunCronJob(taskId)
|
||||
}
|
||||
|
||||
func (d *DataSyncTask) Stop(rc *req.Ctx) {
|
||||
|
||||
@@ -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.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) {
|
||||
ss := strings.Split(dbName, "/")
|
||||
if len(ss) > 1 {
|
||||
checkDb = ss[0]
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
"mayfly-go/internal/db/dbm/dbi"
|
||||
"mayfly-go/internal/db/domain/entity"
|
||||
"mayfly-go/internal/db/domain/repository"
|
||||
@@ -53,8 +54,8 @@ var (
|
||||
dateTimeReg = regexp.MustCompile(`^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$`)
|
||||
)
|
||||
|
||||
func (d *dataSyncAppImpl) InjectDbDataSyncTaskRepo(repo repository.DataSyncTask) {
|
||||
d.Repo = repo
|
||||
func (app *dataSyncAppImpl) InjectDbDataSyncTaskRepo(repo repository.DataSyncTask) {
|
||||
app.Repo = repo
|
||||
}
|
||||
|
||||
func (app *dataSyncAppImpl) GetPageList(condition *entity.DataSyncTaskQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
|
||||
@@ -64,15 +65,22 @@ func (app *dataSyncAppImpl) GetPageList(condition *entity.DataSyncTaskQuery, pag
|
||||
func (app *dataSyncAppImpl) Save(ctx context.Context, taskEntity *entity.DataSyncTask) error {
|
||||
var err error
|
||||
if taskEntity.Id == 0 {
|
||||
// 新建时生成key
|
||||
taskEntity.TaskKey = uuid.New().String()
|
||||
err = app.Insert(ctx, taskEntity)
|
||||
} else {
|
||||
err = app.UpdateById(ctx, taskEntity)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
app.AddCronJob(taskEntity)
|
||||
task, err := app.GetById(new(entity.DataSyncTask), taskEntity.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
app.AddCronJob(task)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -92,9 +100,13 @@ func (app *dataSyncAppImpl) AddCronJob(taskEntity *entity.DataSyncTask) {
|
||||
// 根据状态添加新的任务
|
||||
if taskEntity.Status == entity.DataSyncTaskStatusEnable {
|
||||
scheduler.AddFunByKey(key, taskEntity.TaskCron, func() {
|
||||
if err := app.RunCronJob(taskEntity.Id); err != nil {
|
||||
logx.Errorf("定时执行数据同步任务失败: %s", err.Error())
|
||||
}
|
||||
go func() {
|
||||
taskId := taskEntity.Id
|
||||
logx.Infof("开始执行同步任务: %d", taskId)
|
||||
if err := app.RunCronJob(taskId); err != nil {
|
||||
logx.Errorf("定时执行数据同步任务失败: %s", err.Error())
|
||||
}
|
||||
}()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ const (
|
||||
DbTypeMysql DbType = "mysql"
|
||||
DbTypeMariadb DbType = "mariadb"
|
||||
DbTypePostgres DbType = "postgres"
|
||||
DbTypeGauss DbType = "gauss"
|
||||
DbTypeDM DbType = "dm"
|
||||
DbTypeOracle DbType = "oracle"
|
||||
DbTypeSqlite DbType = "sqlite"
|
||||
@@ -43,7 +44,7 @@ func (dbType DbType) QuoteIdentifier(name string) string {
|
||||
switch dbType {
|
||||
case DbTypeMysql, DbTypeMariadb:
|
||||
return quoteIdentifier(name, "`")
|
||||
case DbTypePostgres:
|
||||
case DbTypePostgres, DbTypeGauss:
|
||||
return quoteIdentifier(name, `"`)
|
||||
case DbTypeMssql:
|
||||
return fmt.Sprintf("[%s]", name)
|
||||
@@ -56,7 +57,7 @@ func (dbType DbType) RemoveQuote(name string) string {
|
||||
switch dbType {
|
||||
case DbTypeMysql, DbTypeMariadb:
|
||||
return removeQuote(name, "`")
|
||||
case DbTypePostgres:
|
||||
case DbTypePostgres, DbTypeGauss:
|
||||
return removeQuote(name, `"`)
|
||||
default:
|
||||
return removeQuote(name, `"`)
|
||||
@@ -69,7 +70,7 @@ func (dbType DbType) QuoteLiteral(literal string) string {
|
||||
literal = strings.ReplaceAll(literal, `\`, `\\`)
|
||||
literal = strings.ReplaceAll(literal, `'`, `''`)
|
||||
return "'" + literal + "'"
|
||||
case DbTypePostgres:
|
||||
case DbTypePostgres, DbTypeGauss:
|
||||
return pq.QuoteLiteral(literal)
|
||||
default:
|
||||
return pq.QuoteLiteral(literal)
|
||||
@@ -80,7 +81,7 @@ func (dbType DbType) MetaDbName() string {
|
||||
switch dbType {
|
||||
case DbTypeMysql, DbTypeMariadb:
|
||||
return ""
|
||||
case DbTypePostgres:
|
||||
case DbTypePostgres, DbTypeGauss:
|
||||
return "postgres"
|
||||
case DbTypeDM:
|
||||
return ""
|
||||
@@ -93,7 +94,7 @@ func (dbType DbType) Dialect() sqlparser.Dialect {
|
||||
switch dbType {
|
||||
case DbTypeMysql, DbTypeMariadb:
|
||||
return sqlparser.MysqlDialect{}
|
||||
case DbTypePostgres:
|
||||
case DbTypePostgres, DbTypeGauss:
|
||||
return sqlparser.PostgresDialect{}
|
||||
default:
|
||||
return sqlparser.PostgresDialect{}
|
||||
@@ -121,7 +122,7 @@ func (dbType DbType) StmtSetForeignKeyChecks(check bool) string {
|
||||
} else {
|
||||
return "SET FOREIGN_KEY_CHECKS = 0;\n"
|
||||
}
|
||||
case DbTypePostgres:
|
||||
case DbTypePostgres, DbTypeGauss:
|
||||
// not currently supported postgres
|
||||
return ""
|
||||
default:
|
||||
@@ -133,7 +134,7 @@ func (dbType DbType) StmtUseDatabase(dbName string) string {
|
||||
switch dbType {
|
||||
case DbTypeMysql, DbTypeMariadb:
|
||||
return fmt.Sprintf("USE %s;\n", dbType.QuoteIdentifier(dbName))
|
||||
case DbTypePostgres:
|
||||
case DbTypePostgres, DbTypeGauss:
|
||||
// not currently supported postgres
|
||||
return ""
|
||||
default:
|
||||
|
||||
@@ -16,13 +16,18 @@ import (
|
||||
|
||||
func init() {
|
||||
dbi.Register(dbi.DbTypePostgres, new(PostgresMeta))
|
||||
|
||||
gauss := new(PostgresMeta)
|
||||
gauss.Param = "dbtype=gauss"
|
||||
dbi.Register(dbi.DbTypeGauss, gauss)
|
||||
}
|
||||
|
||||
type PostgresMeta struct {
|
||||
Param string
|
||||
}
|
||||
|
||||
func (md *PostgresMeta) GetSqlDb(d *dbi.DbInfo) (*sql.DB, error) {
|
||||
driverName := string(d.Type)
|
||||
driverName := "postgres"
|
||||
// SSH Conect
|
||||
if d.SshTunnelMachineId > 0 {
|
||||
// 如果使用了隧道,则使用`postgres:ssh:隧道机器id`注册名
|
||||
@@ -67,6 +72,10 @@ func (md *PostgresMeta) GetSqlDb(d *dbi.DbInfo) (*sql.DB, error) {
|
||||
dsn = fmt.Sprintf("%s %s", dsn, strings.Join(strings.Split(d.Params, "&"), " "))
|
||||
}
|
||||
|
||||
if md.Param != "" && !strings.Contains(dsn, "dbtype") {
|
||||
dsn = fmt.Sprintf("%s %s", dsn, md.Param)
|
||||
}
|
||||
|
||||
return sql.Open(driverName, dsn)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user