mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 16:00:25 +08:00
!109 refactor:ddl生成方式重构,数据类型和长度重构,所有数据库迁移调试
* feat:同步sqlite全量sql * refactor:ddl生成方式重构,数据类型和长度重构,所有数据库迁移调试
This commit is contained in:
@@ -115,7 +115,7 @@
|
||||
<el-option
|
||||
v-for="item in state.targetColumnList"
|
||||
:key="item.columnName"
|
||||
:label="item.columnName + ` ${item.columnType}` + (item.columnComment && ' - ' + item.columnComment)"
|
||||
:label="item.columnName + ` ${item.showDataType}` + (item.columnComment && ' - ' + item.columnComment)"
|
||||
:value="item.columnName"
|
||||
/>
|
||||
</el-select>
|
||||
|
||||
@@ -461,7 +461,7 @@ const formatDataValues = (datas: any) => {
|
||||
|
||||
for (let data of datas) {
|
||||
for (let column of props.columns!) {
|
||||
data[column.columnName] = getFormatTimeValue(dbDialect.getDataType(column.columnType), data[column.columnName]);
|
||||
data[column.columnName] = getFormatTimeValue(dbDialect.getDataType(column.dataType), data[column.columnName]);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -479,9 +479,9 @@ const setTableColumns = (columns: any) => {
|
||||
state.columns = columns.map((x: any) => {
|
||||
const columnName = x.columnName;
|
||||
// 数据类型
|
||||
x.dataType = dbDialect.getDataType(x.columnType);
|
||||
x.dataType = dbDialect.getDataType(x.dataType);
|
||||
x.dataTypeSubscript = ColumnTypeSubscript[x.dataType];
|
||||
x.remark = `${x.columnType} ${x.columnComment ? ' | ' + x.columnComment : ''}`;
|
||||
x.remark = `${x.showDataType} ${x.columnComment ? ' | ' + x.columnComment : ''}`;
|
||||
|
||||
return {
|
||||
...x,
|
||||
|
||||
@@ -9,15 +9,15 @@
|
||||
:required="column.nullable != 'YES' && !column.isPrimaryKey && !column.isIdentity"
|
||||
>
|
||||
<template #label>
|
||||
<span class="pointer" :title="`${column.columnType} | ${column.columnComment}`">
|
||||
<span class="pointer" :title="`${column.showDataType} | ${column.columnComment}`">
|
||||
{{ column.columnName }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<ColumnFormItem
|
||||
v-model="modelValue[`${column.columnName}`]"
|
||||
:data-type="dbInst.getDialect().getDataType(column.columnType)"
|
||||
:placeholder="`${column.columnType} ${column.columnComment}`"
|
||||
:data-type="dbInst.getDialect().getDataType(column.dataType)"
|
||||
:placeholder="`${column.showDataType} ${column.columnComment}`"
|
||||
:column-name="column.columnName"
|
||||
:disabled="column.isIdentity"
|
||||
/>
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
<el-divider direction="vertical" />
|
||||
|
||||
<span style="color: var(--el-color-info-light-3)">
|
||||
{{ item.columnType }}
|
||||
{{ item.showDataType }}
|
||||
|
||||
<template v-if="item.columnComment">
|
||||
<el-divider direction="vertical" />
|
||||
@@ -463,7 +463,7 @@ const handlerColumnSelect = (column: any) => {
|
||||
// 默认拼接上 columnName =
|
||||
let value = column.columnName + ' = ';
|
||||
// 不是数字类型默认拼接上''
|
||||
if (!DbInst.isNumber(column.columnType)) {
|
||||
if (!DbInst.isNumber(column.dataType)) {
|
||||
value = `${value} ''`;
|
||||
}
|
||||
|
||||
@@ -507,7 +507,7 @@ const filterCondColumns = computed(() => {
|
||||
const onConditionRowClick = (event: any) => {
|
||||
const row = event[0];
|
||||
state.conditionDialog.title = `请输入 [${row.columnName}] 的值`;
|
||||
state.conditionDialog.placeholder = `${row.columnType} ${row.columnComment}`;
|
||||
state.conditionDialog.placeholder = `${row.showDataType} ${row.columnComment}`;
|
||||
state.conditionDialog.columnRow = row;
|
||||
state.conditionDialog.visible = true;
|
||||
setTimeout(() => {
|
||||
@@ -524,7 +524,7 @@ const onConfirmCondition = () => {
|
||||
}
|
||||
const row = conditionDialog.columnRow as any;
|
||||
condition += `${row.columnName} ${conditionDialog.condition} `;
|
||||
state.condition = condition + state.dbDialect.wrapValue(row.columnType, conditionDialog.value!);
|
||||
state.condition = condition + state.dbDialect.wrapValue(row.dataType, conditionDialog.value!);
|
||||
onCancelCondition();
|
||||
condInputRef.value.focus();
|
||||
};
|
||||
|
||||
@@ -192,7 +192,7 @@ const state = reactive({
|
||||
},
|
||||
{
|
||||
prop: 'numScale',
|
||||
label: '小数点',
|
||||
label: '小数精度',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
@@ -412,7 +412,6 @@ const filterChangedData = (oldArr: object[], nowArr: object[], key: string): { d
|
||||
|
||||
const genSql = () => {
|
||||
let data = state.tableData;
|
||||
console.log(data);
|
||||
// 创建表
|
||||
if (!props.data?.edit) {
|
||||
let createTable = dbDialect.getCreateTableSql(data);
|
||||
@@ -504,9 +503,6 @@ watch(
|
||||
// 回显列
|
||||
if (columns && Array.isArray(columns) && columns.length > 0) {
|
||||
columns.forEach((a) => {
|
||||
let typeObj = a.columnType.replace(')', '').split('(');
|
||||
let type = typeObj[0];
|
||||
let length = (typeObj.length > 1 && typeObj[1]) || '';
|
||||
let defaultValue = '';
|
||||
if (a.columnDefault) {
|
||||
defaultValue = a.columnDefault.trim().replace(/^'|'$/g, '');
|
||||
@@ -516,10 +512,10 @@ watch(
|
||||
let data = {
|
||||
name: a.columnName,
|
||||
oldName: a.columnName,
|
||||
type,
|
||||
type: a.dataType,
|
||||
value: defaultValue,
|
||||
length,
|
||||
numScale: a.numScale,
|
||||
length: a.showLength,
|
||||
numScale: a.showScale,
|
||||
notNull: a.nullable !== 'YES',
|
||||
pri: a.isPrimaryKey,
|
||||
auto_increment: a.isIdentity /*a.extra?.indexOf('auto_increment') > -1*/,
|
||||
|
||||
@@ -317,7 +317,7 @@ export class DbInst {
|
||||
let sql = `UPDATE ${schema}${this.wrapName(table)} SET `;
|
||||
// 主键列信息
|
||||
const primaryKey = await this.loadTableColumn(dbName, table);
|
||||
let primaryKeyType = primaryKey.columnType;
|
||||
let primaryKeyType = primaryKey.dataType;
|
||||
let primaryKeyName = primaryKey.columnName;
|
||||
let primaryKeyValue = rowData[primaryKeyName];
|
||||
const dialect = this.getDialect();
|
||||
@@ -325,7 +325,7 @@ export class DbInst {
|
||||
const v = columnValue[k];
|
||||
// 更新字段列信息
|
||||
const updateColumn = await this.loadTableColumn(dbName, table, k);
|
||||
sql += ` ${this.wrapName(k)} = ${dialect.wrapValue(updateColumn.columnType, v)},`;
|
||||
sql += ` ${this.wrapName(k)} = ${dialect.wrapValue(updateColumn.dataType, v)},`;
|
||||
}
|
||||
sql = sql.substring(0, sql.length - 1);
|
||||
|
||||
@@ -341,7 +341,7 @@ export class DbInst {
|
||||
async genDeleteByPrimaryKeysSql(db: string, table: string, datas: any[]) {
|
||||
const primaryKey = await this.loadTableColumn(db, table);
|
||||
const primaryKeyColumnName = primaryKey.columnName;
|
||||
const ids = datas.map((d: any) => `${this.getDialect().wrapValue(primaryKey.columnType, d[primaryKeyColumnName])}`).join(',');
|
||||
const ids = datas.map((d: any) => `${this.getDialect().wrapValue(primaryKey.dataType, d[primaryKeyColumnName])}`).join(',');
|
||||
return `DELETE FROM ${this.wrapName(table)} WHERE ${this.wrapName(primaryKeyColumnName)} IN (${ids})`;
|
||||
}
|
||||
|
||||
|
||||
@@ -303,7 +303,7 @@ class MssqlDialect implements DbDialect {
|
||||
}
|
||||
if (changeData.add.length > 0) {
|
||||
changeData.add.forEach((a) => {
|
||||
addArr.push(` ALTER TABLE ${baseTable} ADD COLUMN ${this.genColumnBasicSql(a)}`);
|
||||
addArr.push(` ALTER TABLE ${baseTable} ADD ${this.genColumnBasicSql(a)}`);
|
||||
if (a.remark) {
|
||||
addCommentArr.push(
|
||||
`EXECUTE sp_addextendedproperty N'MS_Description', N'${a.remark}', N'SCHEMA', N'${schema}', N'TABLE', N'${tableName}', N'COLUMN', N'${a.name}'`
|
||||
|
||||
@@ -435,7 +435,7 @@ func (d *Db) HintTables(rc *req.Ctx) {
|
||||
res[tName] = make([]string, 0)
|
||||
}
|
||||
|
||||
columnName := fmt.Sprintf("%s [%s]", v.ColumnName, v.ColumnType)
|
||||
columnName := fmt.Sprintf("%s [%s]", v.ColumnName, v.ShowDataType)
|
||||
comment := v.ColumnComment
|
||||
// 如果字段备注不为空,则加上备注信息
|
||||
if comment != "" {
|
||||
|
||||
@@ -169,6 +169,8 @@ func (app *dbTransferAppImpl) transferTables(task *entity.DbTransferTask, srcCon
|
||||
srcDialect.ToCommonColumn(colPtr)
|
||||
// 公共列转为目标库列
|
||||
targetDialect.ToColumn(colPtr)
|
||||
// 初始化列显示类型
|
||||
colPtr.InitShowNum()
|
||||
targetCols = append(targetCols, *colPtr)
|
||||
}
|
||||
|
||||
@@ -222,6 +224,8 @@ func (app *dbTransferAppImpl) transferData(ctx context.Context, tableName string
|
||||
batchSize := 1000 // 每次查询并迁移1000条数据
|
||||
var queryColumns []*dbi.QueryColumn
|
||||
var err error
|
||||
srcMeta := srcConn.GetMetaData()
|
||||
srcConverter := srcMeta.GetDataConverter()
|
||||
|
||||
// 游标查询源表数据,并批量插入目标表
|
||||
err = srcConn.WalkTableRows(ctx, tableName, func(row map[string]any, columns []*dbi.QueryColumn) error {
|
||||
@@ -236,7 +240,13 @@ func (app *dbTransferAppImpl) transferData(ctx context.Context, tableName string
|
||||
|
||||
}
|
||||
total++
|
||||
result = append(result, row)
|
||||
rawValue := map[string]any{}
|
||||
for _, column := range columns {
|
||||
// 某些情况,如oracle,需要转换时间类型的字符串为time类型
|
||||
res := srcConverter.ParseData(row[column.Name], srcConverter.GetDataType(column.Type))
|
||||
rawValue[column.Name] = res
|
||||
}
|
||||
result = append(result, rawValue)
|
||||
if total%batchSize == 0 {
|
||||
err = app.transfer2Target(targetConn, queryColumns, result, targetDialect, tableName)
|
||||
if err != nil {
|
||||
|
||||
@@ -34,6 +34,10 @@ type MetaData interface {
|
||||
// 获取建表ddl
|
||||
GetTableDDL(tableName string) (string, error)
|
||||
|
||||
GenerateTableDDL(columns []Column, tableInfo Table, dropBeforeCreate bool) []string
|
||||
|
||||
GenerateIndexDDL(indexs []Index, tableInfo Table) []string
|
||||
|
||||
GetSchemas() ([]string, error)
|
||||
|
||||
// 获取数据转换器用于解析格式化列数据等
|
||||
@@ -49,6 +53,7 @@ type DbServer struct {
|
||||
// 表信息
|
||||
type Table struct {
|
||||
TableName string `json:"tableName"` // 表名
|
||||
TableNewName string `json:"tableNewName"` // 新表名,复制表生成ddl时,需要传入新表名
|
||||
TableComment string `json:"tableComment"` // 表备注
|
||||
CreateTime string `json:"createTime"` // 创建时间
|
||||
TableRows int `json:"tableRows"`
|
||||
@@ -60,7 +65,6 @@ type Table struct {
|
||||
type Column struct {
|
||||
TableName string `json:"tableName"` // 表名
|
||||
ColumnName string `json:"columnName"` // 列名
|
||||
ColumnType string `json:"columnType"` // 列类型,包含类型等描述(后续移除)
|
||||
DataType ColumnDataType `json:"dataType"` // 数据类型
|
||||
ColumnComment string `json:"columnComment"` // 列备注
|
||||
IsPrimaryKey bool `json:"isPrimaryKey"` // 是否为主键
|
||||
@@ -71,17 +75,38 @@ type Column struct {
|
||||
NumPrecision int `json:"numPrecision"` // 精度(总数字位数)
|
||||
NumScale int `json:"numScale"` // 小数点位数
|
||||
Extra collx.M `json:"extra"` // 其他额外信息
|
||||
|
||||
ShowLength int `json:"showLength"`
|
||||
ShowScale int `json:"showScale"`
|
||||
ShowDataType string `json:"showDataType"` // 显示数据类型
|
||||
}
|
||||
|
||||
// 获取列类型,拼接数据类型与长度等。如varchar(2000),decimal(20,2)
|
||||
func (c *Column) GetColumnType() string {
|
||||
// 初始化列显示类型,拼接数据类型与长度等。如varchar(2000),decimal(20,2)
|
||||
func (c *Column) InitShowNum() string {
|
||||
if c.CharMaxLength > 0 {
|
||||
return fmt.Sprintf("%s(%d)", c.DataType, c.CharMaxLength)
|
||||
c.ShowDataType = fmt.Sprintf("%s(%d)", c.DataType, c.CharMaxLength)
|
||||
c.ShowLength = c.CharMaxLength
|
||||
c.ShowScale = 0
|
||||
return c.ShowDataType
|
||||
}
|
||||
if c.NumPrecision > 0 {
|
||||
return fmt.Sprintf("%s(%d,%d)", c.DataType, c.NumPrecision, c.NumScale)
|
||||
if c.NumScale > 0 {
|
||||
c.ShowDataType = fmt.Sprintf("%s(%d,%d)", c.DataType, c.NumPrecision, c.NumScale)
|
||||
c.ShowScale = c.NumScale
|
||||
} else {
|
||||
c.ShowDataType = fmt.Sprintf("%s(%d)", c.DataType, c.NumPrecision)
|
||||
c.ShowScale = 0
|
||||
}
|
||||
c.ShowLength = c.NumPrecision
|
||||
|
||||
return c.ShowDataType
|
||||
}
|
||||
return string(c.DataType)
|
||||
|
||||
c.ShowDataType = string(c.DataType)
|
||||
c.ShowLength = 0
|
||||
c.ShowScale = 0
|
||||
|
||||
return c.ShowDataType
|
||||
}
|
||||
|
||||
// 表索引信息
|
||||
|
||||
@@ -34,39 +34,35 @@ WHERE a.owner = (SELECT SF_GET_SCHEMA_NAME_BY_ID(CURRENT_SCHID))
|
||||
ORDER BY a.object_name
|
||||
---------------------------------------
|
||||
--DM_INDEX_INFO 表索引信息
|
||||
select
|
||||
a.index_name as INDEX_NAME,
|
||||
a.index_type as INDEX_TYPE,
|
||||
case when a.uniqueness = 'UNIQUE' then 1 else 0 end as IS_UNIQUE,
|
||||
indexdef(b.object_id,1) as INDEX_DEF,
|
||||
c.column_name as COLUMN_NAME,
|
||||
c.column_position as SEQ_IN_INDEX,
|
||||
'无' as INDEX_COMMENT
|
||||
select a.index_name as INDEX_NAME,
|
||||
a.index_type as INDEX_TYPE,
|
||||
case when a.uniqueness = 'UNIQUE' then 1 else 0 end as IS_UNIQUE,
|
||||
indexdef(b.object_id, 1) as INDEX_DEF,
|
||||
c.column_name as COLUMN_NAME,
|
||||
c.column_position as SEQ_IN_INDEX,
|
||||
'无' as INDEX_COMMENT
|
||||
FROM ALL_INDEXES a
|
||||
LEFT JOIN all_objects b on a.owner = b.owner and b.object_name = a.index_name and b.object_type = 'INDEX'
|
||||
LEFT JOIN ALL_IND_COLUMNS c
|
||||
on a.owner = c.table_owner and a.index_name = c.index_name and a.TABLE_NAME = c.table_name
|
||||
|
||||
WHERE a.owner = (SELECT SF_GET_SCHEMA_NAME_BY_ID(CURRENT_SCHID))
|
||||
and a.TABLE_NAME = '%s'
|
||||
and indexdef(b.object_id,1) != '禁止查看系统定义的索引信息'
|
||||
order by a.TABLE_NAME, a.index_name, c.column_position asc
|
||||
and a.TABLE_NAME = '%s'
|
||||
and indexdef(b.object_id, 1) != '禁止查看系统定义的索引信息'
|
||||
order by a.TABLE_NAME, a.index_name, c.column_position asc
|
||||
---------------------------------------
|
||||
--DM_COLUMN_MA 表列信息
|
||||
select a.table_name as TABLE_NAME,
|
||||
a.column_name as COLUMN_NAME,
|
||||
case when a.NULLABLE = 'Y' then 'YES' when a.NULLABLE = 'N' then 'NO' else 'NO' end as NULLABLE,
|
||||
case
|
||||
when a.char_col_decl_length > 0 then concat(a.data_type, '(', a.char_col_decl_length, ')')
|
||||
when a.data_precision > 0 and a.data_scale > 0
|
||||
then concat(a.data_type, '(', a.data_precision, ',', a.data_scale, ')')
|
||||
else a.data_type end
|
||||
as COLUMN_TYPE,
|
||||
a.data_type as DATA_TYPE,
|
||||
a.char_col_decl_length as CHAR_MAX_LENGTH,
|
||||
a.data_precision as NUM_PRECISION,
|
||||
a.data_scale as NUM_SCALE,
|
||||
b.comments as COLUMN_COMMENT,
|
||||
a.data_default as COLUMN_DEFAULT,
|
||||
a.data_scale as NUM_SCALE,
|
||||
case when t.COL_NAME = a.column_name then 1 else 0 end as IS_IDENTITY,
|
||||
case when t2.constraint_type = 'P' then 1 else 0 end as IS_PRIMARY_KEY
|
||||
case when t.COL_NAME = a.column_name then 1 else 0 end as IS_IDENTITY,
|
||||
case when t2.constraint_type = 'P' then 1 else 0 end as IS_PRIMARY_KEY
|
||||
from all_tab_columns a
|
||||
left join user_col_comments b
|
||||
on b.owner = (SELECT SF_GET_SCHEMA_NAME_BY_ID(CURRENT_SCHID))
|
||||
|
||||
@@ -61,28 +61,16 @@ WHERE ss.name = ?
|
||||
and t.name = ?
|
||||
---------------------------------------
|
||||
--MSSQL_COLUMN_MA 列信息元数据
|
||||
SELECT t.name AS TABLE_NAME,
|
||||
c.name AS COLUMN_NAME,
|
||||
CASE
|
||||
WHEN c.is_nullable = 1 THEN 'YES'
|
||||
ELSE 'NO'
|
||||
END AS NULLABLE,
|
||||
tp.name +
|
||||
CASE
|
||||
WHEN tp.name IN ('char', 'varchar', 'nchar', 'nvarchar') THEN '(' + CASE
|
||||
WHEN c.max_length = -1 THEN 'max'
|
||||
ELSE CAST(c.max_length AS NVARCHAR(255)) END +
|
||||
')'
|
||||
WHEN tp.name IN ('numeric', 'decimal') THEN '(' + CAST(c.precision AS NVARCHAR(255)) + ',' +
|
||||
CAST(c.scale AS NVARCHAR(255)) + ')'
|
||||
ELSE ''
|
||||
END AS COLUMN_TYPE,
|
||||
ep.value AS COLUMN_COMMENT,
|
||||
COLUMN_DEFAULT = CASE
|
||||
WHEN c.default_object_id IS NOT NULL THEN object_definition(c.default_object_id)
|
||||
ELSE ''
|
||||
END,
|
||||
c.scale AS NUM_SCALE,
|
||||
SELECT t.name AS TABLE_NAME,
|
||||
c.name AS COLUMN_NAME,
|
||||
CASE WHEN c.is_nullable = 1 THEN 'YES' ELSE 'NO' END AS NULLABLE,
|
||||
tp.name AS DATA_TYPE,
|
||||
c.max_length AS CHAR_MAX_LENGTH,
|
||||
c.precision AS NUM_PRECISION,
|
||||
c.scale AS NUM_SCALE,
|
||||
ep.value AS COLUMN_COMMENT,
|
||||
COLUMN_DEFAULT =
|
||||
CASE WHEN c.default_object_id IS NOT NULL THEN object_definition(c.default_object_id) ELSE '' END,
|
||||
IS_IDENTITY = COLUMNPROPERTY(c.object_id, c.name, 'IsIdentity'),
|
||||
IS_PRIMARY_KEY = CASE
|
||||
WHEN (SELECT COUNT(*)
|
||||
@@ -105,106 +93,3 @@ FROM sys.tables t
|
||||
WHERE ss.name = ?
|
||||
and t.name in (%s)
|
||||
ORDER BY t.name, c.column_id
|
||||
---------------------------------------
|
||||
--MSSQL_TABLE_DDL 建表ddl
|
||||
declare
|
||||
@tabname varchar(50)
|
||||
set @tabname= ? --表名
|
||||
if ( object_id('tempdb.dbo.#t') is not null)
|
||||
begin
|
||||
DROP TABLE #t
|
||||
end
|
||||
select 'create table [' + so.name + '] (' + o.list + ')'
|
||||
+ CASE
|
||||
WHEN tc.Constraint_Name IS NULL THEN ''
|
||||
ELSE 'ALTER TABLE ' + so.Name + ' ADD CONSTRAINT ' + tc.Constraint_Name + ' PRIMARY KEY ' +
|
||||
' (' + LEFT(j.List, Len(j.List)-1) + ')' END
|
||||
TABLE_DDL
|
||||
into #t
|
||||
from sysobjects so
|
||||
cross apply
|
||||
(SELECT
|
||||
' \n ['+ column_name +'] ' +
|
||||
data_type + case data_type
|
||||
when 'sql_variant' then ''
|
||||
when 'text' then ''
|
||||
when 'ntext' then ''
|
||||
when 'xml' then ''
|
||||
when 'decimal' then '(' + cast (numeric_precision as varchar) + ', ' + cast (numeric_scale as varchar) + ')'
|
||||
else coalesce ('('+ case when character_maximum_length = -1 then 'MAX' else cast (character_maximum_length as varchar) end +')', '') end + ' ' +
|
||||
case when exists (
|
||||
select id from syscolumns
|
||||
where object_name(id)=so.name
|
||||
and name = column_name
|
||||
and columnproperty(id, name, 'IsIdentity') = 1
|
||||
) then
|
||||
'IDENTITY(' +
|
||||
cast (ident_seed(so.name) as varchar) + ',' +
|
||||
cast (ident_incr(so.name) as varchar) + ')'
|
||||
else ''
|
||||
end + ' ' +
|
||||
(case when IS_NULLABLE = 'No' then 'NOT ' else '' end ) + 'NULL ' +
|
||||
case when information_schema.columns.COLUMN_DEFAULT IS NOT NULL THEN 'DEFAULT '+ information_schema.columns.COLUMN_DEFAULT ELSE '' END + ', '
|
||||
from information_schema.columns where table_name = so.name
|
||||
order by ordinal_position
|
||||
FOR XML PATH ('')) o (list)
|
||||
left join
|
||||
information_schema.table_constraints tc
|
||||
on tc.Table_name = so.Name
|
||||
AND tc.Constraint_Type = 'PRIMARY KEY'
|
||||
cross apply
|
||||
(select '[' + Column_Name + '], '
|
||||
FROM information_schema.key_column_usage kcu
|
||||
WHERE kcu.Constraint_Name = tc.Constraint_Name
|
||||
ORDER BY
|
||||
ORDINAL_POSITION
|
||||
FOR XML PATH ('')) j (list)
|
||||
where xtype = 'U'
|
||||
AND name =@tabname
|
||||
|
||||
select (
|
||||
case
|
||||
when (select count(a.constraint_type)
|
||||
from information_schema.table_constraints a
|
||||
inner join information_schema.constraint_column_usage b
|
||||
on a.constraint_name = b.constraint_name
|
||||
where a.constraint_type = 'PRIMARY KEY'--主键
|
||||
and a.table_name = @tabname) = 1 then replace(table_ddl
|
||||
, ', )ALTER TABLE'
|
||||
, ')' + CHAR (13)+'ALTER TABLE')
|
||||
else SUBSTRING(table_ddl
|
||||
, 1
|
||||
, len(table_ddl) - 3) + ')' end
|
||||
) as TableDDL
|
||||
from #t
|
||||
|
||||
drop table #t
|
||||
---------------------------------------
|
||||
--MSSQL_TABLE_INDEX_DDL 建索引ddl
|
||||
DECLARE
|
||||
@TableName NVARCHAR(255)
|
||||
SET @TableName = ?;
|
||||
|
||||
SELECT 'CREATE ' +
|
||||
CASE
|
||||
WHEN i.is_primary_key = 1 THEN 'CLUSTERED '
|
||||
WHEN i.type_desc = 'HEAP' THEN ''
|
||||
ELSE 'NONCLUSTERED '
|
||||
END +
|
||||
'INDEX ' + i.name + ' ON ' + t.name + ' (' +
|
||||
STUFF((SELECT ',' + c.name +
|
||||
CASE
|
||||
WHEN ic.is_descending_key = 1 THEN ' DESC'
|
||||
ELSE ' ASC'
|
||||
END
|
||||
FROM sys.index_columns ic
|
||||
INNER JOIN
|
||||
sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
||||
WHERE ic.object_id = i.object_id
|
||||
AND ic.index_id = i.index_id
|
||||
ORDER BY ic.key_ordinal
|
||||
FOR XML PATH (''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '') + ');' AS IndexDDL
|
||||
FROM sys.tables t
|
||||
INNER JOIN
|
||||
sys.indexes i ON t.object_id = i.object_id
|
||||
WHERE t.name = @TableName;
|
||||
|
||||
@@ -50,122 +50,21 @@ WHERE a.schemaname = (select current_schema())
|
||||
AND a.tablename = '%s';
|
||||
---------------------------------------
|
||||
--PGSQL_COLUMN_MA 表列信息
|
||||
SELECT a.table_name AS "tableName",
|
||||
a.column_name AS "columnName",
|
||||
a.is_nullable AS "nullable",
|
||||
case when character_maximum_length > 0 then concat(udt_name, '(',character_maximum_length,')') else udt_name end AS "columnType",
|
||||
a.column_default as "columnDefault",
|
||||
a.numeric_scale AS "numScale",
|
||||
case when a.column_default like 'nextval%%' then 1 else 0 end "isIdentity",
|
||||
case when b.column_name is not null then 1 else 0 end "isPrimaryKey",
|
||||
col_description((a.table_schema || '.' || a.table_name)::regclass, a.ordinal_position) AS "columnComment"
|
||||
SELECT a.*,
|
||||
a.table_name AS "tableName",
|
||||
a.column_name AS "columnName",
|
||||
a.is_nullable AS "nullable",
|
||||
a.udt_name AS "dataType",
|
||||
a.character_maximum_length AS "charMaxLength",
|
||||
a.numeric_precision AS "numPrecision",
|
||||
a.column_default AS "columnDefault",
|
||||
a.numeric_scale AS "numScale",
|
||||
case when a.column_default like 'nextval%%' then 1 else 0 end AS "isIdentity",
|
||||
case when b.column_name is not null then 1 else 0 end AS "isPrimaryKey",
|
||||
col_description((a.table_schema || '.' || a.table_name) ::regclass, a.ordinal_position) AS "columnComment"
|
||||
FROM information_schema.columns a
|
||||
left join information_schema.key_column_usage b
|
||||
on a.table_schema = b.table_schema and b.table_name = a.table_name and b.column_name = a.column_name
|
||||
WHERE a.table_schema = (select current_schema())
|
||||
and a.table_name in (%s)
|
||||
order by a.table_name, a.ordinal_position
|
||||
---------------------------------------
|
||||
--PGSQL_TABLE_DDL_FUNC 表ddl函数
|
||||
CREATE OR REPLACE FUNCTION showcreatetable(namespace character varying, tablename character varying)
|
||||
RETURNS character varying AS
|
||||
$BODY$
|
||||
declare
|
||||
tableScript character varying default '';
|
||||
begin
|
||||
-- columns
|
||||
tableScript:=tableScript || ' CREATE TABLE '|| tablename|| ' ( '|| chr(13)||chr(10) || array_to_string(
|
||||
array(
|
||||
select ' ' || concat_ws(' ',fieldName, fieldType, isNullStr ) as column_line
|
||||
from (
|
||||
select a.attname as fieldName,format_type(a.atttypid,a.atttypmod) as fieldType,(case when atttypmod-4>0 then
|
||||
atttypmod-4 else 0 end) as fieldLen,
|
||||
(case when (select count(*) from pg_constraint where conrelid = a.attrelid and conkey[1]=attnum and
|
||||
contype='p')>0 then 'PRI'
|
||||
when (select count(*) from pg_constraint where conrelid = a.attrelid and conkey[1]=attnum and contype='u')>0
|
||||
then 'UNI'
|
||||
when (select count(*) from pg_constraint where conrelid = a.attrelid and conkey[1]=attnum and contype='f')>0
|
||||
then 'FRI'
|
||||
else '' end) as indexType,
|
||||
(case when a.attnotnull=true then 'not null' else 'null' end) as isNullStr,
|
||||
' comment ' || col_description(a.attrelid,a.attnum) as fieldComment
|
||||
from pg_attribute a where attstattarget=-1 and attrelid = (select c.oid from pg_class c,pg_namespace n where
|
||||
c.relnamespace=n.oid and n.nspname =namespace and relname =tablename)
|
||||
) as string_columns
|
||||
),','||chr(13)||chr(10));
|
||||
-- 约束
|
||||
tableScript:= tableScript || array_to_string(
|
||||
array(
|
||||
select '' union all
|
||||
select concat(' CONSTRAINT ',conname ,c ,u,p,f) from (
|
||||
select conname,
|
||||
case when contype='c' then ' CHECK('|| ( select findattname(namespace,tablename,'c') ) ||')' end as c ,
|
||||
case when contype='u' then ' UNIQUE('|| ( select findattname(namespace,tablename,'u') ) ||')' end as u ,
|
||||
case when contype='p' then ' PRIMARY KEY ('|| ( select findattname(namespace,tablename,'p') ) ||')' end as p ,
|
||||
case when contype='f' then ' FOREIGN KEY('|| ( select findattname(namespace,tablename,'u') ) ||') REFERENCES '||
|
||||
(select p.relname from pg_class p where p.oid=c.confrelid ) || '('|| ( select
|
||||
findattname(namespace,tablename,'u') ) ||')' end as f
|
||||
from pg_constraint c
|
||||
where contype in('u','c','f','p') and conrelid=(
|
||||
select oid from pg_class where relname=tablename and relnamespace =(
|
||||
select oid from pg_namespace where nspname = namespace
|
||||
)
|
||||
)
|
||||
) as t
|
||||
) ,',' || chr(13)||chr(10) ) || chr(13)||chr(10) ||' ); ';
|
||||
-- indexs
|
||||
-- CREATE UNIQUE INDEX pg_language_oid_index ON pg_language USING btree (oid); -- table pg_language
|
||||
--
|
||||
/** **/
|
||||
--- 获取非约束索引 column
|
||||
-- CREATE UNIQUE INDEX pg_language_oid_index ON pg_language USING btree (oid); -- table pg_language
|
||||
tableScript:= tableScript || chr(13)||chr(10) || array_to_string(
|
||||
array(
|
||||
select 'CREATE INDEX ' || indexrelname || ' ON ' || tablename || ' USING btree '|| '(' || attname || ');' from (
|
||||
SELECT
|
||||
i.relname AS indexrelname , x.indkey,
|
||||
( select array_to_string (
|
||||
array(
|
||||
select a.attname from pg_attribute a where attrelid=c.oid and a.attnum in ( select unnest(x.indkey) )
|
||||
)
|
||||
,',' ) )as attname
|
||||
FROM pg_class c
|
||||
JOIN pg_index x ON c.oid = x.indrelid
|
||||
JOIN pg_class i ON i.oid = x.indexrelid
|
||||
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE c.relname=tablename and i.relname not in
|
||||
( select constraint_name from information_schema.key_column_usage where table_name=tablename )
|
||||
)as t
|
||||
) , chr(13)||chr(10));
|
||||
-- COMMENT ON COLUMN sys_activity.id IS '主键';
|
||||
tableScript:= tableScript || chr(13)||chr(10) || array_to_string(
|
||||
array(
|
||||
SELECT 'COMMENT ON COLUMN ' || tablename || '.' || a.attname ||' IS '|| ''''|| d.description ||''';'
|
||||
FROM pg_class c
|
||||
JOIN pg_description d ON c.oid=d.objoid
|
||||
JOIN pg_attribute a ON c.oid = a.attrelid
|
||||
WHERE c.relname=tablename
|
||||
AND a.attnum = d.objsubid), chr(13)||chr(10)) ;
|
||||
return tableScript;
|
||||
end
|
||||
$BODY$ LANGUAGE plpgsql;
|
||||
CREATE OR REPLACE FUNCTION findattname(namespace character varying, tablename character varying, ctype character
|
||||
varying)
|
||||
RETURNS character varying as $BODY$
|
||||
declare
|
||||
tt oid ;
|
||||
aname character varying default '';
|
||||
begin
|
||||
tt := oid from pg_class where relname= tablename and relnamespace =(select oid from pg_namespace where
|
||||
nspname=namespace) ;
|
||||
aname:= array_to_string(
|
||||
array(
|
||||
select a.attname from pg_attribute a
|
||||
where a.attrelid=tt and a.attnum in (
|
||||
select unnest(conkey) from pg_constraint c where contype=ctype
|
||||
and conrelid=tt and array_to_string(conkey,',') is not null
|
||||
)
|
||||
),',');
|
||||
return aname;
|
||||
end
|
||||
$BODY$ LANGUAGE plpgsql
|
||||
@@ -165,157 +165,56 @@ func (dd *DMDialect) CopyTable(copy *dbi.DbCopyTable) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// func (dd *DMDialect) TransColumns(columns []dbi.Column) []dbi.Column {
|
||||
// var commonColumns []dbi.Column
|
||||
// for _, column := range columns {
|
||||
// // 取出当前数据库类型
|
||||
// arr := strings.Split(column.ColumnType, "(")
|
||||
// ctype := arr[0]
|
||||
|
||||
// // 翻译为通用数据库类型
|
||||
// t1 := commonColumnMap[ctype]
|
||||
// if t1 == "" {
|
||||
// ctype = "VARCHAR(2000)"
|
||||
// } else {
|
||||
// // 回写到列信息
|
||||
// if len(arr) > 1 {
|
||||
// ctype = t1 + "(" + arr[1]
|
||||
// }
|
||||
// }
|
||||
// column.ColumnType = ctype
|
||||
// commonColumns = append(commonColumns, column)
|
||||
// }
|
||||
// return commonColumns
|
||||
// }
|
||||
|
||||
func (dd *DMDialect) CreateTable(commonColumns []dbi.Column, tableInfo dbi.Table, dropOldTable bool) (int, error) {
|
||||
meta := dd.dc.GetMetaData()
|
||||
replacer := strings.NewReplacer(";", "", "'", "")
|
||||
tbName := meta.QuoteIdentifier(tableInfo.TableName)
|
||||
|
||||
if dropOldTable {
|
||||
_, _ = dd.dc.Exec(fmt.Sprintf("drop table if exists %s", tbName))
|
||||
func (dd *DMDialect) ToCommonColumn(dialectColumn *dbi.Column) {
|
||||
// 翻译为通用数据库类型
|
||||
dataType := dialectColumn.DataType
|
||||
t1 := commonColumnTypeMap[string(dataType)]
|
||||
if t1 == "" {
|
||||
dialectColumn.DataType = dbi.CommonTypeVarchar
|
||||
dialectColumn.CharMaxLength = 2000
|
||||
} else {
|
||||
dialectColumn.DataType = t1
|
||||
}
|
||||
// 组装建表语句
|
||||
createSql := fmt.Sprintf("create table %s (", tbName)
|
||||
fields := make([]string, 0)
|
||||
pks := make([]string, 0)
|
||||
columnComments := make([]string, 0)
|
||||
// 把通用类型转换为达梦类型
|
||||
for _, column := range commonColumns {
|
||||
// 取出当前数据库类型
|
||||
arr := strings.Split(column.ColumnType, "(")
|
||||
ctype := arr[0]
|
||||
// 翻译为通用数据库类型
|
||||
t1 := dmColumnMap[dbi.ColumnDataType(ctype)]
|
||||
if t1 == "" {
|
||||
ctype = "VARCHAR(2000)"
|
||||
} else {
|
||||
// 回写到列信息
|
||||
if len(arr) > 1 {
|
||||
ctype = t1 + "(" + arr[1]
|
||||
} else {
|
||||
ctype = t1
|
||||
}
|
||||
}
|
||||
column.ColumnType = ctype
|
||||
|
||||
if column.IsPrimaryKey {
|
||||
pks = append(pks, meta.QuoteIdentifier(column.ColumnName))
|
||||
}
|
||||
fields = append(fields, dd.genColumnBasicSql(column))
|
||||
// 防止注释内含有特殊字符串导致sql出错
|
||||
comment := replacer.Replace(column.ColumnComment)
|
||||
columnComments = append(columnComments, fmt.Sprintf("comment on column %s.%s is '%s'", tbName, meta.QuoteIdentifier(column.ColumnName), comment))
|
||||
}
|
||||
createSql += strings.Join(fields, ",")
|
||||
if len(pks) > 0 {
|
||||
createSql += fmt.Sprintf(", PRIMARY KEY (%s)", strings.Join(pks, ","))
|
||||
}
|
||||
createSql += ")"
|
||||
|
||||
tableCommentSql := ""
|
||||
if tableInfo.TableComment != "" {
|
||||
// 防止注释内含有特殊字符串导致sql出错
|
||||
comment := replacer.Replace(tableInfo.TableComment)
|
||||
tableCommentSql = fmt.Sprintf(" comment on table %s is '%s'", tbName, comment)
|
||||
}
|
||||
|
||||
// 达梦需要分开执行sql
|
||||
var err error
|
||||
if createSql != "" {
|
||||
_, err = dd.dc.Exec(createSql)
|
||||
}
|
||||
if tableCommentSql != "" {
|
||||
_, err = dd.dc.Exec(tableCommentSql)
|
||||
}
|
||||
if len(columnComments) > 0 {
|
||||
for _, commentSql := range columnComments {
|
||||
_, err = dd.dc.Exec(commentSql)
|
||||
}
|
||||
}
|
||||
|
||||
return 1, err
|
||||
}
|
||||
|
||||
func (dd *DMDialect) genColumnBasicSql(column dbi.Column) string {
|
||||
meta := dd.dc.GetMetaData()
|
||||
colName := meta.QuoteIdentifier(column.ColumnName)
|
||||
func (dd *DMDialect) ToColumn(commonColumn *dbi.Column) {
|
||||
ctype := dmColumnTypeMap[commonColumn.DataType]
|
||||
|
||||
incr := ""
|
||||
if column.IsIdentity {
|
||||
incr = " IDENTITY"
|
||||
if ctype == "" {
|
||||
commonColumn.DataType = "VARCHAR"
|
||||
commonColumn.CharMaxLength = 2000
|
||||
} else {
|
||||
commonColumn.DataType = dbi.ColumnDataType(ctype)
|
||||
// 如果是date,不设长度
|
||||
if collx.ArrayAnyMatches([]string{"date", "time"}, strings.ToLower(ctype)) {
|
||||
commonColumn.CharMaxLength = 0
|
||||
commonColumn.NumPrecision = 0
|
||||
} else
|
||||
// 如果是char且长度未设置,则默认长度2000
|
||||
if collx.ArrayAnyMatches([]string{"char"}, strings.ToLower(ctype)) && commonColumn.CharMaxLength == 0 {
|
||||
commonColumn.CharMaxLength = 2000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nullAble := ""
|
||||
if column.Nullable == "NO" {
|
||||
nullAble = " NOT NULL"
|
||||
}
|
||||
func (dd *DMDialect) CreateTable(columns []dbi.Column, tableInfo dbi.Table, dropOldTable bool) (int, error) {
|
||||
|
||||
defVal := "" // 默认值需要判断引号,如函数是不需要引号的 // 为了防止跨源函数不支持 当默认值是函数时,不需要设置默认值
|
||||
if column.ColumnDefault != "" && !strings.Contains(column.ColumnDefault, "(") {
|
||||
// 哪些字段类型默认值需要加引号
|
||||
mark := false
|
||||
if collx.ArrayAnyMatches([]string{"char", "text", "date", "time", "lob"}, strings.ToLower(column.ColumnType)) {
|
||||
// 当数据类型是日期时间,默认值是日期时间函数时,默认值不需要引号
|
||||
if collx.ArrayAnyMatches([]string{"date", "time"}, strings.ToLower(column.ColumnType)) &&
|
||||
collx.ArrayAnyMatches([]string{"DATE", "TIME"}, strings.ToUpper(column.ColumnDefault)) {
|
||||
mark = false
|
||||
} else {
|
||||
mark = true
|
||||
sqlArr := dd.dc.GetMetaData().GenerateTableDDL(columns, tableInfo, dropOldTable)
|
||||
// 达梦需要分开执行sql
|
||||
if len(sqlArr) > 0 {
|
||||
for _, sqlStr := range sqlArr {
|
||||
_, err := dd.dc.Exec(sqlStr)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
if mark {
|
||||
defVal = fmt.Sprintf(" DEFAULT '%s'", column.ColumnDefault)
|
||||
} else {
|
||||
defVal = fmt.Sprintf(" DEFAULT %s", column.ColumnDefault)
|
||||
}
|
||||
}
|
||||
|
||||
columnSql := fmt.Sprintf(" %s %s %s %s %s", colName, column.ColumnType, incr, nullAble, defVal)
|
||||
return columnSql
|
||||
|
||||
return len(sqlArr), nil
|
||||
}
|
||||
|
||||
func (dd *DMDialect) CreateIndex(tableInfo dbi.Table, indexs []dbi.Index) error {
|
||||
meta := dd.dc.GetMetaData()
|
||||
sqls := make([]string, 0)
|
||||
for _, index := range indexs {
|
||||
// 通过字段、表名拼接索引名
|
||||
columnName := strings.ReplaceAll(index.ColumnName, "-", "")
|
||||
columnName = strings.ReplaceAll(columnName, "_", "")
|
||||
colName := strings.ReplaceAll(columnName, ",", "_")
|
||||
|
||||
keyType := "normal"
|
||||
unique := ""
|
||||
if index.IsUnique {
|
||||
keyType = "unique"
|
||||
unique = "unique"
|
||||
}
|
||||
indexName := fmt.Sprintf("%s_key_%s_%s", keyType, tableInfo.TableName, colName)
|
||||
|
||||
sqls = append(sqls, fmt.Sprintf("create %s index %s on %s(%s)", unique, indexName, meta.QuoteIdentifier(tableInfo.TableName), index.ColumnName))
|
||||
}
|
||||
sqls := dd.dc.GetMetaData().GenerateIndexDDL(indexs, tableInfo)
|
||||
_, err := dd.dc.Exec(strings.Join(sqls, ";"))
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"mayfly-go/internal/db/dbm/dbi"
|
||||
"mayfly-go/pkg/errorx"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/utils/anyx"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"mayfly-go/pkg/utils/stringx"
|
||||
@@ -96,17 +97,23 @@ func (dd *DMMetaData) GetColumns(tableNames ...string) ([]dbi.Column, error) {
|
||||
|
||||
columns := make([]dbi.Column, 0)
|
||||
for _, re := range res {
|
||||
columns = append(columns, dbi.Column{
|
||||
column := dbi.Column{
|
||||
TableName: anyx.ConvString(re["TABLE_NAME"]),
|
||||
ColumnName: anyx.ConvString(re["COLUMN_NAME"]),
|
||||
ColumnType: anyx.ConvString(re["COLUMN_TYPE"]),
|
||||
DataType: dbi.ColumnDataType(anyx.ToString(re["DATA_TYPE"])),
|
||||
CharMaxLength: anyx.ConvInt(re["CHAR_MAX_LENGTH"]),
|
||||
ColumnComment: anyx.ConvString(re["COLUMN_COMMENT"]),
|
||||
Nullable: anyx.ConvString(re["NULLABLE"]),
|
||||
IsPrimaryKey: anyx.ConvInt(re["IS_PRIMARY_KEY"]) == 1,
|
||||
IsIdentity: anyx.ConvInt(re["IS_IDENTITY"]) == 1,
|
||||
ColumnDefault: anyx.ConvString(re["COLUMN_DEFAULT"]),
|
||||
NumPrecision: anyx.ConvInt(re["NUM_PRECISION"]),
|
||||
NumScale: anyx.ConvInt(re["NUM_SCALE"]),
|
||||
})
|
||||
}
|
||||
|
||||
// 初始化列展示的长度,精度
|
||||
column.InitShowNum()
|
||||
columns = append(columns, column)
|
||||
}
|
||||
return columns, nil
|
||||
}
|
||||
@@ -165,73 +172,151 @@ func (dd *DMMetaData) GetTableIndex(tableName string) ([]dbi.Index, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (dd *DMMetaData) genColumnBasicSql(column dbi.Column) string {
|
||||
meta := dd.dc.GetMetaData()
|
||||
colName := meta.QuoteIdentifier(column.ColumnName)
|
||||
dataType := string(column.DataType)
|
||||
|
||||
incr := ""
|
||||
if column.IsIdentity {
|
||||
incr = " IDENTITY"
|
||||
}
|
||||
|
||||
nullAble := ""
|
||||
if column.Nullable == "NO" {
|
||||
nullAble = " NOT NULL"
|
||||
}
|
||||
|
||||
defVal := "" // 默认值需要判断引号,如函数是不需要引号的 // 为了防止跨源函数不支持 当默认值是函数时,不需要设置默认值
|
||||
if column.ColumnDefault != "" && !strings.Contains(column.ColumnDefault, "(") {
|
||||
// 哪些字段类型默认值需要加引号
|
||||
mark := false
|
||||
if collx.ArrayAnyMatches([]string{"char", "text", "date", "time", "lob"}, strings.ToLower(dataType)) {
|
||||
// 当数据类型是日期时间,默认值是日期时间函数时,默认值不需要引号
|
||||
if collx.ArrayAnyMatches([]string{"date", "time"}, strings.ToLower(dataType)) &&
|
||||
collx.ArrayAnyMatches([]string{"DATE", "TIME"}, strings.ToUpper(column.ColumnDefault)) {
|
||||
mark = false
|
||||
} else {
|
||||
mark = true
|
||||
}
|
||||
}
|
||||
if mark {
|
||||
defVal = fmt.Sprintf(" DEFAULT '%s'", column.ColumnDefault)
|
||||
} else {
|
||||
defVal = fmt.Sprintf(" DEFAULT %s", column.ColumnDefault)
|
||||
}
|
||||
}
|
||||
|
||||
columnSql := fmt.Sprintf(" %s %s %s %s %s", colName, column.ShowDataType, incr, nullAble, defVal)
|
||||
return columnSql
|
||||
|
||||
}
|
||||
|
||||
func (dd *DMMetaData) GenerateIndexDDL(indexs []dbi.Index, tableInfo dbi.Table) []string {
|
||||
meta := dd.dc.GetMetaData()
|
||||
sqls := make([]string, 0)
|
||||
for _, index := range indexs {
|
||||
// 通过字段、表名拼接索引名
|
||||
columnName := strings.ReplaceAll(index.ColumnName, "-", "")
|
||||
columnName = strings.ReplaceAll(columnName, "_", "")
|
||||
colName := strings.ReplaceAll(columnName, ",", "_")
|
||||
|
||||
keyType := "normal"
|
||||
unique := ""
|
||||
if index.IsUnique {
|
||||
keyType = "unique"
|
||||
unique = "unique"
|
||||
}
|
||||
indexName := fmt.Sprintf("%s_key_%s_%s", keyType, tableInfo.TableName, colName)
|
||||
|
||||
sqls = append(sqls, fmt.Sprintf("create %s index %s on %s(%s)", unique, indexName, meta.QuoteIdentifier(tableInfo.TableName), index.ColumnName))
|
||||
}
|
||||
return sqls
|
||||
}
|
||||
|
||||
func (dd *DMMetaData) GenerateTableDDL(columns []dbi.Column, tableInfo dbi.Table, dropBeforeCreate bool) []string {
|
||||
meta := dd.dc.GetMetaData()
|
||||
replacer := strings.NewReplacer(";", "", "'", "")
|
||||
tbName := meta.QuoteIdentifier(tableInfo.TableName)
|
||||
sqlArr := make([]string, 0)
|
||||
|
||||
if dropBeforeCreate {
|
||||
sqlArr = append(sqlArr, fmt.Sprintf("drop table if exists %s", tbName))
|
||||
}
|
||||
// 组装建表语句
|
||||
createSql := fmt.Sprintf("create table %s (", tbName)
|
||||
fields := make([]string, 0)
|
||||
pks := make([]string, 0)
|
||||
columnComments := make([]string, 0)
|
||||
|
||||
for _, column := range columns {
|
||||
if column.IsPrimaryKey {
|
||||
pks = append(pks, meta.QuoteIdentifier(column.ColumnName))
|
||||
}
|
||||
fields = append(fields, dd.genColumnBasicSql(column))
|
||||
// 防止注释内含有特殊字符串导致sql出错
|
||||
if column.ColumnComment != "" {
|
||||
comment := replacer.Replace(column.ColumnComment)
|
||||
columnComments = append(columnComments, fmt.Sprintf("comment on column %s.%s is '%s'", tbName, meta.QuoteIdentifier(column.ColumnName), comment))
|
||||
}
|
||||
}
|
||||
createSql += strings.Join(fields, ",")
|
||||
if len(pks) > 0 {
|
||||
createSql += fmt.Sprintf(", PRIMARY KEY (%s)", strings.Join(pks, ","))
|
||||
}
|
||||
createSql += ")"
|
||||
|
||||
tableCommentSql := ""
|
||||
if tableInfo.TableComment != "" {
|
||||
// 防止注释内含有特殊字符串导致sql出错
|
||||
comment := replacer.Replace(tableInfo.TableComment)
|
||||
if comment != "" {
|
||||
tableCommentSql = fmt.Sprintf(" comment on table %s is '%s'", tbName, comment)
|
||||
}
|
||||
}
|
||||
|
||||
sqlArr = append(sqlArr, createSql)
|
||||
if tableCommentSql != "" {
|
||||
sqlArr = append(sqlArr, tableCommentSql)
|
||||
}
|
||||
|
||||
if len(columnComments) > 0 {
|
||||
sqlArr = append(sqlArr, columnComments...)
|
||||
}
|
||||
|
||||
return sqlArr
|
||||
}
|
||||
|
||||
// 获取建表ddl
|
||||
func (dd *DMMetaData) GetTableDDL(tableName string) (string, error) {
|
||||
ddlSql := fmt.Sprintf("CALL SP_TABLEDEF((SELECT SF_GET_SCHEMA_NAME_BY_ID(CURRENT_SCHID)), '%s')", tableName)
|
||||
_, res, err := dd.dc.Query(ddlSql)
|
||||
if err != nil {
|
||||
|
||||
// 1.获取表信息
|
||||
tbs, err := dd.GetTables(tableName)
|
||||
tableInfo := &dbi.Table{}
|
||||
if err != nil && len(tbs) > 0 {
|
||||
|
||||
logx.Errorf("获取表信息失败, %s", tableName)
|
||||
return "", err
|
||||
}
|
||||
// 建表ddl
|
||||
var builder strings.Builder
|
||||
for _, re := range res {
|
||||
builder.WriteString(re["COLUMN_VALUE"].(string))
|
||||
}
|
||||
tableInfo.TableName = tbs[0].TableName
|
||||
tableInfo.TableComment = tbs[0].TableComment
|
||||
|
||||
// 表注释
|
||||
_, res, err = dd.dc.Query(fmt.Sprintf(`
|
||||
select OWNER, COMMENTS from ALL_TAB_COMMENTS where TABLE_TYPE='TABLE' and TABLE_NAME = '%s'
|
||||
and owner = (SELECT SF_GET_SCHEMA_NAME_BY_ID(CURRENT_SCHID))
|
||||
`, tableName))
|
||||
// 2.获取列信息
|
||||
columns, err := dd.GetColumns(tableName)
|
||||
if err != nil {
|
||||
logx.Errorf("获取列信息失败, %s", tableName)
|
||||
return "", err
|
||||
}
|
||||
for _, re := range res {
|
||||
// COMMENT ON TABLE "SYS_MENU" IS '菜单表';
|
||||
if re["COMMENTS"] != nil {
|
||||
tableComment := fmt.Sprintf("\n\nCOMMENT ON TABLE \"%s\".\"%s\" IS '%s';", re["OWNER"].(string), tableName, re["COMMENTS"].(string))
|
||||
builder.WriteString(tableComment)
|
||||
}
|
||||
}
|
||||
|
||||
// 字段注释
|
||||
fieldSql := fmt.Sprintf(`
|
||||
SELECT OWNER, COLUMN_NAME, COMMENTS
|
||||
FROM USER_COL_COMMENTS
|
||||
WHERE OWNER = (SELECT SF_GET_SCHEMA_NAME_BY_ID(CURRENT_SCHID))
|
||||
AND TABLE_NAME = '%s'
|
||||
`, tableName)
|
||||
_, res, err = dd.dc.Query(fieldSql)
|
||||
tableDDLArr := dd.GenerateTableDDL(columns, *tableInfo, false)
|
||||
// 3.获取索引信息
|
||||
indexs, err := dd.GetTableIndex(tableName)
|
||||
if err != nil {
|
||||
logx.Errorf("获取索引信息失败, %s", tableName)
|
||||
return "", err
|
||||
}
|
||||
|
||||
builder.WriteString("\n")
|
||||
for _, re := range res {
|
||||
// COMMENT ON COLUMN "SYS_MENU"."BIZ_CODE" IS '业务编码,应用编码1';
|
||||
if re["COMMENTS"] != nil {
|
||||
fieldComment := fmt.Sprintf("\nCOMMENT ON COLUMN \"%s\".\"%s\".\"%s\" IS '%s';", re["OWNER"].(string), tableName, re["COLUMN_NAME"].(string), re["COMMENTS"].(string))
|
||||
builder.WriteString(fieldComment)
|
||||
}
|
||||
}
|
||||
|
||||
// 索引信息
|
||||
indexSql := fmt.Sprintf(`
|
||||
select indexdef(b.object_id,1) as INDEX_DEF from ALL_INDEXES a
|
||||
join ALL_objects b on a.owner = b.owner and b.object_name = a.index_name and b.object_type = 'INDEX'
|
||||
where a.owner = (SELECT SF_GET_SCHEMA_NAME_BY_ID(CURRENT_SCHID))
|
||||
and a.table_name = '%s'
|
||||
and indexdef(b.object_id,1) != '禁止查看系统定义的索引信息'
|
||||
`, tableName)
|
||||
_, res, err = dd.dc.Query(indexSql)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, re := range res {
|
||||
builder.WriteString("\n\n" + re["INDEX_DEF"].(string))
|
||||
}
|
||||
|
||||
return builder.String(), nil
|
||||
// 组装返回
|
||||
tableDDLArr = append(tableDDLArr, dd.GenerateIndexDDL(indexs, *tableInfo)...)
|
||||
return strings.Join(tableDDLArr, ";"), nil
|
||||
}
|
||||
|
||||
// 获取DM当前连接的库可访问的schemaNames
|
||||
@@ -267,7 +352,7 @@ var (
|
||||
converter = new(DataConverter)
|
||||
|
||||
// 达梦数据类型 对应 公共数据类型
|
||||
commonColumnMap = map[string]dbi.ColumnDataType{
|
||||
commonColumnTypeMap = map[string]dbi.ColumnDataType{
|
||||
|
||||
"CHAR": dbi.CommonTypeChar, // 字符数据类型
|
||||
"VARCHAR": dbi.CommonTypeVarchar,
|
||||
@@ -296,7 +381,7 @@ var (
|
||||
}
|
||||
|
||||
// 公共数据类型 对应 达梦数据类型
|
||||
dmColumnMap = map[dbi.ColumnDataType]string{
|
||||
dmColumnTypeMap = map[dbi.ColumnDataType]string{
|
||||
dbi.CommonTypeVarchar: "VARCHAR",
|
||||
dbi.CommonTypeChar: "CHAR",
|
||||
dbi.CommonTypeText: "TEXT",
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"mayfly-go/internal/db/dbm/dbi"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/utils/anyx"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -253,200 +252,61 @@ func (md *MssqlDialect) CopyTable(copy *dbi.DbCopyTable) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// func (md *MssqlDialect) TransColumns(columns []dbi.Column) []dbi.Column {
|
||||
// var commonColumns []dbi.Column
|
||||
// for _, column := range columns {
|
||||
// // 取出当前数据库类型
|
||||
// arr := strings.Split(column.ColumnType, "(")
|
||||
// ctype := arr[0]
|
||||
// // 翻译为通用数据库类型
|
||||
// t1 := commonColumnTypeMap[ctype]
|
||||
// if t1 == "" {
|
||||
// ctype = "nvarchar(2000)"
|
||||
// } else {
|
||||
// // 回写到列信息
|
||||
// if len(arr) > 1 {
|
||||
// ctype = t1 + "(" + arr[1]
|
||||
// } else {
|
||||
// ctype = t1
|
||||
// }
|
||||
// }
|
||||
// column.ColumnType = ctype
|
||||
// commonColumns = append(commonColumns, column)
|
||||
// }
|
||||
// return commonColumns
|
||||
// }
|
||||
|
||||
func (md *MssqlDialect) CreateTable(commonColumns []dbi.Column, tableInfo dbi.Table, dropOldTable bool) (int, error) {
|
||||
meta := md.dc.GetMetaData()
|
||||
replacer := strings.NewReplacer(";", "", "'", "")
|
||||
if dropOldTable {
|
||||
_, _ = md.dc.Exec(fmt.Sprintf("DROP TABLE IF EXISTS %s", meta.QuoteIdentifier(tableInfo.TableName)))
|
||||
func (md *MssqlDialect) ToCommonColumn(dialectColumn *dbi.Column) {
|
||||
// 翻译为通用数据库类型
|
||||
dataType := dialectColumn.DataType
|
||||
t1 := commonColumnTypeMap[string(dataType)]
|
||||
if t1 == "" {
|
||||
dialectColumn.DataType = dbi.CommonTypeVarchar
|
||||
dialectColumn.CharMaxLength = 2000
|
||||
} else {
|
||||
dialectColumn.DataType = t1
|
||||
}
|
||||
// 组装建表语句
|
||||
createSql := fmt.Sprintf("CREATE TABLE %s (\n", meta.QuoteIdentifier(tableInfo.TableName))
|
||||
fields := make([]string, 0)
|
||||
pks := make([]string, 0)
|
||||
columnComments := make([]string, 0)
|
||||
// 把通用类型转换为达梦类型
|
||||
for _, column := range commonColumns {
|
||||
// 取出当前数据库类型
|
||||
arr := strings.Split(column.ColumnType, "(")
|
||||
ctype := arr[0]
|
||||
// 翻译为通用数据库类型
|
||||
t1 := mssqlColumnTypeMap[dbi.ColumnDataType(ctype)]
|
||||
if t1 == "" {
|
||||
ctype = "nvarchar(2000)"
|
||||
} else {
|
||||
// 回写到列信息
|
||||
if len(arr) > 1 {
|
||||
// 如果是int类型不需要指定长度
|
||||
if strings.Contains(strings.ToLower(t1), "int") {
|
||||
ctype = t1
|
||||
} else if collx.ArrayAnyMatches([]string{"float", "number", "decimal"}, strings.ToLower(t1)) {
|
||||
// 如果是float,最大长度为38
|
||||
match := bracketsRegexp.FindStringSubmatch(column.ColumnType)
|
||||
if len(match) > 1 {
|
||||
// size翻倍, 防止数据超长报错
|
||||
size := anyx.ConvInt(match[1])
|
||||
if size >= 38 { // 如果长度超过38
|
||||
ctype = t1 + "(38)"
|
||||
} else {
|
||||
ctype = fmt.Sprintf("%s(%d)", t1, size)
|
||||
}
|
||||
} else {
|
||||
ctype = t1 + "(38)"
|
||||
}
|
||||
} else if strings.Contains(strings.ToLower(t1), "char") {
|
||||
// 如果是字符串类型,长度最大4000,否则修改字段类型为text
|
||||
match := bracketsRegexp.FindStringSubmatch(column.ColumnType)
|
||||
if len(match) > 1 {
|
||||
// size翻倍, 防止数据超长报错
|
||||
size := anyx.ConvInt(match[1]) * 2
|
||||
|
||||
if size >= 4000 { // 如果长度超过4000,则替换为text类型
|
||||
ctype = "text"
|
||||
} else {
|
||||
ctype = fmt.Sprintf("%s(%d)", t1, size)
|
||||
}
|
||||
} else {
|
||||
ctype = t1 + "(1000)"
|
||||
}
|
||||
} else {
|
||||
ctype = t1 + "(" + arr[1]
|
||||
}
|
||||
} else {
|
||||
ctype = t1
|
||||
}
|
||||
}
|
||||
column.ColumnType = ctype
|
||||
|
||||
if column.IsPrimaryKey {
|
||||
pks = append(pks, meta.QuoteIdentifier(column.ColumnName))
|
||||
}
|
||||
fields = append(fields, md.genColumnBasicSql(column))
|
||||
commentTmp := "EXECUTE sp_addextendedproperty N'MS_Description', N'%s', N'SCHEMA', N'%s', N'TABLE', N'%s', N'COLUMN', N'%s'"
|
||||
|
||||
// 防止注释内含有特殊字符串导致sql出错
|
||||
comment := replacer.Replace(column.ColumnComment)
|
||||
columnComments = append(columnComments, fmt.Sprintf(commentTmp, comment, md.currentSchema(), column.TableName, column.ColumnName))
|
||||
}
|
||||
createSql += strings.Join(fields, ",")
|
||||
if len(pks) > 0 {
|
||||
createSql += fmt.Sprintf(", PRIMARY KEY CLUSTERED (%s)", strings.Join(pks, ","))
|
||||
}
|
||||
createSql += ")"
|
||||
tableCommentSql := ""
|
||||
if tableInfo.TableComment != "" {
|
||||
commentTmp := "EXECUTE sp_addextendedproperty N'MS_Description', N'%s', N'SCHEMA', N'%s', N'TABLE', N'%s'"
|
||||
tableCommentSql = fmt.Sprintf(commentTmp, replacer.Replace(tableInfo.TableComment), md.currentSchema(), tableInfo.TableName)
|
||||
}
|
||||
|
||||
columnCommentSql := strings.Join(columnComments, ";")
|
||||
|
||||
sqls := make([]string, 0)
|
||||
|
||||
if createSql != "" {
|
||||
sqls = append(sqls, createSql)
|
||||
}
|
||||
if tableCommentSql != "" {
|
||||
sqls = append(sqls, tableCommentSql)
|
||||
}
|
||||
if columnCommentSql != "" {
|
||||
sqls = append(sqls, columnCommentSql)
|
||||
}
|
||||
|
||||
_, err := md.dc.Exec(strings.Join(sqls, ";"))
|
||||
|
||||
return 1, err
|
||||
}
|
||||
|
||||
func (md *MssqlDialect) genColumnBasicSql(column dbi.Column) string {
|
||||
meta := md.dc.GetMetaData()
|
||||
colName := meta.QuoteIdentifier(column.ColumnName)
|
||||
func (md *MssqlDialect) ToColumn(commonColumn *dbi.Column) {
|
||||
ctype := mssqlColumnTypeMap[commonColumn.DataType]
|
||||
|
||||
incr := ""
|
||||
if column.IsIdentity {
|
||||
incr = " IDENTITY(1,1)"
|
||||
}
|
||||
if ctype == "" {
|
||||
commonColumn.DataType = "varchar"
|
||||
commonColumn.CharMaxLength = 2000
|
||||
} else {
|
||||
commonColumn.DataType = dbi.ColumnDataType(ctype)
|
||||
|
||||
nullAble := ""
|
||||
if column.Nullable == "NO" {
|
||||
nullAble = " NOT NULL"
|
||||
}
|
||||
|
||||
defVal := "" // 默认值需要判断引号,如函数是不需要引号的 // 为了防止跨源函数不支持 当默认值是函数时,不需要设置默认值
|
||||
if column.ColumnDefault != "" && !strings.Contains(column.ColumnDefault, "(") {
|
||||
// 哪些字段类型默认值需要加引号
|
||||
mark := false
|
||||
if collx.ArrayAnyMatches([]string{"char", "text", "date", "time", "lob"}, strings.ToLower(column.ColumnType)) {
|
||||
// 当数据类型是日期时间,默认值是日期时间函数时,默认值不需要引号
|
||||
if collx.ArrayAnyMatches([]string{"date", "time"}, strings.ToLower(column.ColumnType)) &&
|
||||
collx.ArrayAnyMatches([]string{"DATE", "TIME"}, strings.ToUpper(column.ColumnDefault)) {
|
||||
mark = false
|
||||
} else {
|
||||
mark = true
|
||||
if strings.Contains(strings.ToLower(ctype), "int") {
|
||||
// 如果类型是数字,类型后不需要带长度
|
||||
commonColumn.CharMaxLength = 0
|
||||
commonColumn.NumPrecision = 0
|
||||
} else if collx.ArrayAnyMatches([]string{"float", "number", "decimal"}, strings.ToLower(ctype)) {
|
||||
// 如果是float,最大长度为38
|
||||
if commonColumn.CharMaxLength > 38 {
|
||||
commonColumn.CharMaxLength = 38
|
||||
}
|
||||
}
|
||||
|
||||
if mark {
|
||||
defVal = fmt.Sprintf(" DEFAULT '%s'", column.ColumnDefault)
|
||||
} else {
|
||||
defVal = fmt.Sprintf(" DEFAULT %s", column.ColumnDefault)
|
||||
if commonColumn.NumPrecision > 38 {
|
||||
commonColumn.NumPrecision = 38
|
||||
}
|
||||
} else if strings.Contains(strings.ToLower(ctype), "char") {
|
||||
// 如果是字符串类型,长度最大4000,否则修改字段类型为text
|
||||
if commonColumn.CharMaxLength > 4000 {
|
||||
commonColumn.DataType = "text"
|
||||
commonColumn.CharMaxLength = 0
|
||||
}
|
||||
} else if strings.Contains(strings.ToLower(ctype), "text") {
|
||||
// 如果是text,取消长度
|
||||
commonColumn.CharMaxLength = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
columnSql := fmt.Sprintf(" %s %s %s %s %s", colName, column.ColumnType, incr, nullAble, defVal)
|
||||
return columnSql
|
||||
func (md *MssqlDialect) CreateTable(columns []dbi.Column, tableInfo dbi.Table, dropOldTable bool) (int, error) {
|
||||
sqlArr := md.dc.GetMetaData().GenerateTableDDL(columns, tableInfo, dropOldTable)
|
||||
_, err := md.dc.Exec(strings.Join(sqlArr, ";"))
|
||||
return len(sqlArr), err
|
||||
}
|
||||
|
||||
func (md *MssqlDialect) CreateIndex(tableInfo dbi.Table, indexs []dbi.Index) error {
|
||||
sqls := make([]string, 0)
|
||||
comments := make([]string, 0)
|
||||
for _, index := range indexs {
|
||||
// 通过字段、表名拼接索引名
|
||||
columnName := strings.ReplaceAll(index.ColumnName, "-", "")
|
||||
columnName = strings.ReplaceAll(columnName, "_", "")
|
||||
colName := strings.ReplaceAll(columnName, ",", "_")
|
||||
|
||||
keyType := "normal"
|
||||
unique := ""
|
||||
if index.IsUnique {
|
||||
keyType = "unique"
|
||||
unique = "unique"
|
||||
}
|
||||
indexName := fmt.Sprintf("%s_key_%s_%s", keyType, tableInfo.TableName, colName)
|
||||
|
||||
sqls = append(sqls, fmt.Sprintf("create %s NONCLUSTERED index %s on %s.%s(%s)", unique, indexName, md.currentSchema(), tableInfo.TableName, index.ColumnName))
|
||||
if index.IndexComment != "" {
|
||||
comments = append(comments, fmt.Sprintf("EXECUTE sp_addextendedproperty N'MS_Description', N'%s', N'SCHEMA', N'%s', N'TABLE', N'%s', N'INDEX', N'%s'", index.IndexComment, md.currentSchema(), tableInfo.TableName, indexName))
|
||||
}
|
||||
}
|
||||
_, err := md.dc.Exec(strings.Join(sqls, ";"))
|
||||
// 添加注释
|
||||
if len(comments) > 0 {
|
||||
_, err = md.dc.Exec(strings.Join(comments, ";"))
|
||||
}
|
||||
sqlArr := md.dc.GetMetaData().GenerateIndexDDL(indexs, tableInfo)
|
||||
_, err := md.dc.Exec(strings.Join(sqlArr, ";"))
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"mayfly-go/internal/db/dbm/dbi"
|
||||
"mayfly-go/pkg/errorx"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/utils/anyx"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"mayfly-go/pkg/utils/stringx"
|
||||
@@ -13,14 +14,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
MSSQL_META_FILE = "metasql/mssql_meta.sql"
|
||||
MSSQL_DBS_KEY = "MSSQL_DBS"
|
||||
MSSQL_DB_SCHEMAS_KEY = "MSSQL_DB_SCHEMAS"
|
||||
MSSQL_TABLE_INFO_KEY = "MSSQL_TABLE_INFO"
|
||||
MSSQL_INDEX_INFO_KEY = "MSSQL_INDEX_INFO"
|
||||
MSSQL_COLUMN_MA_KEY = "MSSQL_COLUMN_MA"
|
||||
MSSQL_TABLE_DETAIL_KEY = "MSSQL_TABLE_DETAIL"
|
||||
MSSQL_TABLE_INDEX_DDL_KEY = "MSSQL_TABLE_INDEX_DDL"
|
||||
MSSQL_META_FILE = "metasql/mssql_meta.sql"
|
||||
MSSQL_DBS_KEY = "MSSQL_DBS"
|
||||
MSSQL_DB_SCHEMAS_KEY = "MSSQL_DB_SCHEMAS"
|
||||
MSSQL_TABLE_INFO_KEY = "MSSQL_TABLE_INFO"
|
||||
MSSQL_INDEX_INFO_KEY = "MSSQL_INDEX_INFO"
|
||||
MSSQL_COLUMN_MA_KEY = "MSSQL_COLUMN_MA"
|
||||
)
|
||||
|
||||
type MssqlMetaData struct {
|
||||
@@ -106,17 +105,41 @@ func (md *MssqlMetaData) GetColumns(tableNames ...string) ([]dbi.Column, error)
|
||||
|
||||
columns := make([]dbi.Column, 0)
|
||||
for _, re := range res {
|
||||
columns = append(columns, dbi.Column{
|
||||
|
||||
column := dbi.Column{
|
||||
TableName: anyx.ToString(re["TABLE_NAME"]),
|
||||
ColumnName: anyx.ToString(re["COLUMN_NAME"]),
|
||||
ColumnType: anyx.ToString(re["COLUMN_TYPE"]),
|
||||
DataType: dbi.ColumnDataType(anyx.ToString(re["DATA_TYPE"])),
|
||||
CharMaxLength: anyx.ConvInt(re["CHAR_MAX_LENGTH"]),
|
||||
ColumnComment: anyx.ToString(re["COLUMN_COMMENT"]),
|
||||
Nullable: anyx.ToString(re["NULLABLE"]),
|
||||
IsPrimaryKey: anyx.ConvInt(re["IS_PRIMARY_KEY"]) == 1,
|
||||
IsIdentity: anyx.ConvInt(re["IS_IDENTITY"]) == 1,
|
||||
ColumnDefault: anyx.ToString(re["COLUMN_DEFAULT"]),
|
||||
ColumnDefault: anyx.ConvString(re["COLUMN_DEFAULT"]),
|
||||
NumPrecision: anyx.ConvInt(re["NUM_PRECISION"]),
|
||||
NumScale: anyx.ConvInt(re["NUM_SCALE"]),
|
||||
})
|
||||
}
|
||||
|
||||
dataType := strings.ToLower(string(column.DataType))
|
||||
|
||||
if collx.ArrayAnyMatches([]string{"date", "time"}, dataType) {
|
||||
// 如果是datetime,精度取NumScale字段
|
||||
column.CharMaxLength = column.NumScale
|
||||
} else if collx.ArrayAnyMatches([]string{"int", "bit", "real", "text", "xml"}, dataType) {
|
||||
// 不显示长度的类型
|
||||
column.NumPrecision = 0
|
||||
column.CharMaxLength = 0
|
||||
} else if collx.ArrayAnyMatches([]string{"numeric", "decimal", "float"}, dataType) {
|
||||
// 如果是num,长度取精度和小数位数
|
||||
column.CharMaxLength = 0
|
||||
} else if collx.ArrayAnyMatches([]string{"nvarchar", "nchar"}, dataType) {
|
||||
// 如果是nvarchar,可视长度减半
|
||||
column.CharMaxLength = column.CharMaxLength / 2
|
||||
}
|
||||
|
||||
// 初始化列展示的长度,精度
|
||||
column.InitShowNum()
|
||||
columns = append(columns, column)
|
||||
}
|
||||
return columns, nil
|
||||
}
|
||||
@@ -193,93 +216,204 @@ func (md *MssqlMetaData) CopyTableDDL(tableName string, newTableName string) (st
|
||||
if newTableName == "" {
|
||||
newTableName = tableName
|
||||
}
|
||||
|
||||
meta := md.dc.GetMetaData()
|
||||
|
||||
// 根据列信息生成建表语句
|
||||
var builder strings.Builder
|
||||
var commentBuilder strings.Builder
|
||||
|
||||
// 查询表名和表注释, 设置表注释
|
||||
_, res, err := md.dc.Query(dbi.GetLocalSql(MSSQL_META_FILE, MSSQL_TABLE_DETAIL_KEY), md.dc.Info.CurrentSchema(), tableName)
|
||||
if err != nil {
|
||||
tbs, err := md.GetTables(tableName)
|
||||
if err != nil || len(tbs) < 1 {
|
||||
logx.Errorf("获取表信息失败, %s", tableName)
|
||||
return "", err
|
||||
}
|
||||
tableComment := ""
|
||||
if len(res) > 0 {
|
||||
tableComment = anyx.ToString(res[0]["tableComment"])
|
||||
if tableComment != "" {
|
||||
// 注释转义单引号
|
||||
tableComment = strings.ReplaceAll(tableComment, "'", "\\'")
|
||||
commentBuilder.WriteString(fmt.Sprintf("\nEXEC sp_addextendedproperty N'MS_Description', N'%s', N'SCHEMA', N'%s', N'TABLE',N'%s';\n", tableComment, md.dc.Info.CurrentSchema(), newTableName))
|
||||
}
|
||||
tabInfo := &dbi.Table{
|
||||
TableName: tableName,
|
||||
TableComment: tbs[0].TableComment,
|
||||
TableNewName: newTableName,
|
||||
}
|
||||
|
||||
baseTable := fmt.Sprintf("%s.%s", meta.QuoteIdentifier(md.dc.Info.CurrentSchema()), meta.QuoteIdentifier(newTableName))
|
||||
|
||||
// 查询列信息
|
||||
columns, err := md.GetColumns(tableName)
|
||||
if err != nil {
|
||||
logx.Errorf("获取列信息失败, %s", tableName)
|
||||
return "", err
|
||||
}
|
||||
|
||||
builder.WriteString(fmt.Sprintf("CREATE TABLE %s (\n", baseTable))
|
||||
pks := make([]string, 0)
|
||||
for i, v := range columns {
|
||||
nullAble := "NULL"
|
||||
if v.Nullable == "NO" {
|
||||
nullAble = "NOT NULL"
|
||||
}
|
||||
builder.WriteString(fmt.Sprintf("\t[%s] %s %s", v.ColumnName, v.ColumnType, nullAble))
|
||||
if v.IsIdentity {
|
||||
builder.WriteString(" IDENTITY(1,11)")
|
||||
}
|
||||
if v.ColumnDefault != "" {
|
||||
builder.WriteString(fmt.Sprintf(" DEFAULT %s", v.ColumnDefault))
|
||||
}
|
||||
if v.IsPrimaryKey {
|
||||
pks = append(pks, fmt.Sprintf("[%s]", v.ColumnName))
|
||||
}
|
||||
if i < len(columns)-1 {
|
||||
builder.WriteString(",")
|
||||
}
|
||||
builder.WriteString("\n")
|
||||
}
|
||||
// 设置主键
|
||||
if len(pks) > 0 {
|
||||
builder.WriteString(fmt.Sprintf("\tCONSTRAINT PK_%s PRIMARY KEY ( %s )", newTableName, strings.Join(pks, ",")))
|
||||
}
|
||||
builder.WriteString("\n);\n")
|
||||
|
||||
// 设置字段注释
|
||||
for _, v := range columns {
|
||||
if v.ColumnComment != "" {
|
||||
// 注释转义单引号
|
||||
v.ColumnComment = strings.ReplaceAll(v.ColumnComment, "'", "\\'")
|
||||
commentBuilder.WriteString(fmt.Sprintf("\nEXEC sp_addextendedproperty N'MS_Description', N'%s', N'SCHEMA', N'%s', N'TABLE',N'%s', N'COLUMN', N'%s';\n", v.ColumnComment, md.dc.Info.CurrentSchema(), newTableName, v.ColumnName))
|
||||
}
|
||||
}
|
||||
sqlArr := meta.GenerateTableDDL(columns, *tabInfo, true)
|
||||
|
||||
// 设置索引
|
||||
indexs, err := md.GetTableIndex(tableName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
logx.Errorf("获取索引信息失败, %s", tableName)
|
||||
return strings.Join(sqlArr, ";"), err
|
||||
}
|
||||
for _, v := range indexs {
|
||||
builder.WriteString(fmt.Sprintf("\nCREATE NONCLUSTERED INDEX [%s] ON %s (%s);\n", v.IndexName, baseTable, v.ColumnName))
|
||||
// 设置索引注释
|
||||
if v.IndexComment != "" {
|
||||
// 注释转义单引号
|
||||
v.IndexComment = strings.ReplaceAll(v.IndexComment, "'", "\\'")
|
||||
commentBuilder.WriteString(fmt.Sprintf("\nEXEC sp_addextendedproperty N'MS_Description', N'%s', N'SCHEMA', N'%s', N'TABLE',N'%s', N'INDEX', N'%s';\n", v.IndexComment, md.dc.Info.CurrentSchema(), newTableName, v.IndexName))
|
||||
sqlArr = append(sqlArr, meta.GenerateIndexDDL(indexs, *tabInfo)...)
|
||||
return strings.Join(sqlArr, ";"), nil
|
||||
}
|
||||
|
||||
// 获取建索引ddl
|
||||
|
||||
func (md *MssqlMetaData) GenerateIndexDDL(indexs []dbi.Index, tableInfo dbi.Table) []string {
|
||||
|
||||
tbName := tableInfo.TableName
|
||||
if tableInfo.TableNewName != "" {
|
||||
tbName = tableInfo.TableNewName
|
||||
}
|
||||
|
||||
sqls := make([]string, 0)
|
||||
comments := make([]string, 0)
|
||||
for _, index := range indexs {
|
||||
// 通过字段、表名拼接索引名
|
||||
columnName := strings.ReplaceAll(index.ColumnName, "-", "")
|
||||
columnName = strings.ReplaceAll(columnName, "_", "")
|
||||
colName := strings.ReplaceAll(columnName, ",", "_")
|
||||
|
||||
keyType := "normal"
|
||||
unique := ""
|
||||
if index.IsUnique {
|
||||
keyType = "unique"
|
||||
unique = "unique"
|
||||
}
|
||||
indexName := fmt.Sprintf("%s_key_%s_%s", keyType, tbName, colName)
|
||||
|
||||
sqls = append(sqls, fmt.Sprintf("create %s NONCLUSTERED index %s on %s.%s(%s)", unique, indexName, md.dc.Info.CurrentSchema(), tbName, index.ColumnName))
|
||||
if index.IndexComment != "" {
|
||||
comments = append(comments, fmt.Sprintf("EXECUTE sp_addextendedproperty N'MS_Description', N'%s', N'SCHEMA', N'%s', N'TABLE', N'%s', N'INDEX', N'%s'", index.IndexComment, md.dc.Info.CurrentSchema(), tbName, indexName))
|
||||
}
|
||||
}
|
||||
return builder.String() + commentBuilder.String(), nil
|
||||
return sqls
|
||||
}
|
||||
|
||||
func (md *MssqlMetaData) genColumnBasicSql(column dbi.Column) string {
|
||||
meta := md.dc.GetMetaData()
|
||||
colName := meta.QuoteIdentifier(column.ColumnName)
|
||||
dataType := string(column.DataType)
|
||||
|
||||
incr := ""
|
||||
if column.IsIdentity {
|
||||
incr = " IDENTITY(1,1)"
|
||||
}
|
||||
|
||||
nullAble := ""
|
||||
if column.Nullable == "NO" {
|
||||
nullAble = " NOT NULL"
|
||||
}
|
||||
|
||||
defVal := "" // 默认值需要判断引号,如函数是不需要引号的 // 为了防止跨源函数不支持 当默认值是函数时,不需要设置默认值
|
||||
if column.ColumnDefault != "" && !strings.Contains(column.ColumnDefault, "(") {
|
||||
// 哪些字段类型默认值需要加引号
|
||||
mark := false
|
||||
if collx.ArrayAnyMatches([]string{"char", "text", "date", "time", "lob"}, dataType) {
|
||||
// 当数据类型是日期时间,默认值是日期时间函数时,默认值不需要引号
|
||||
if collx.ArrayAnyMatches([]string{"date", "time"}, strings.ToLower(dataType)) &&
|
||||
collx.ArrayAnyMatches([]string{"DATE", "TIME"}, strings.ToUpper(column.ColumnDefault)) {
|
||||
mark = false
|
||||
} else {
|
||||
mark = true
|
||||
}
|
||||
}
|
||||
|
||||
if mark {
|
||||
defVal = fmt.Sprintf(" DEFAULT '%s'", column.ColumnDefault)
|
||||
} else {
|
||||
defVal = fmt.Sprintf(" DEFAULT %s", column.ColumnDefault)
|
||||
}
|
||||
}
|
||||
|
||||
columnSql := fmt.Sprintf(" %s %s %s %s %s", colName, column.ShowDataType, incr, nullAble, defVal)
|
||||
return columnSql
|
||||
}
|
||||
|
||||
// 获取建表ddl
|
||||
func (md *MssqlMetaData) GenerateTableDDL(columns []dbi.Column, tableInfo dbi.Table, dropBeforeCreate bool) []string {
|
||||
|
||||
tbName := tableInfo.TableName
|
||||
if tableInfo.TableNewName != "" {
|
||||
tbName = tableInfo.TableNewName
|
||||
}
|
||||
|
||||
meta := md.dc.GetMetaData()
|
||||
replacer := strings.NewReplacer(";", "", "'", "")
|
||||
|
||||
sqlArr := make([]string, 0)
|
||||
|
||||
// 删除表
|
||||
if dropBeforeCreate {
|
||||
sqlArr = append(sqlArr, fmt.Sprintf("DROP TABLE IF EXISTS %s", meta.QuoteIdentifier(tbName)))
|
||||
}
|
||||
|
||||
// 组装建表语句
|
||||
createSql := fmt.Sprintf("CREATE TABLE %s (\n", meta.QuoteIdentifier(tbName))
|
||||
fields := make([]string, 0)
|
||||
pks := make([]string, 0)
|
||||
columnComments := make([]string, 0)
|
||||
|
||||
for _, column := range columns {
|
||||
if column.IsPrimaryKey {
|
||||
pks = append(pks, meta.QuoteIdentifier(column.ColumnName))
|
||||
}
|
||||
fields = append(fields, md.genColumnBasicSql(column))
|
||||
commentTmp := "EXECUTE sp_addextendedproperty N'MS_Description', N'%s', N'SCHEMA', N'%s', N'TABLE', N'%s', N'COLUMN', N'%s'"
|
||||
|
||||
// 防止注释内含有特殊字符串导致sql出错
|
||||
if column.ColumnComment != "" {
|
||||
comment := replacer.Replace(column.ColumnComment)
|
||||
columnComments = append(columnComments, fmt.Sprintf(commentTmp, comment, md.dc.Info.CurrentSchema(), tbName, column.ColumnName))
|
||||
}
|
||||
}
|
||||
|
||||
// create
|
||||
createSql += strings.Join(fields, ",\n")
|
||||
if len(pks) > 0 {
|
||||
createSql += fmt.Sprintf(", \n PRIMARY KEY CLUSTERED (%s)", strings.Join(pks, ","))
|
||||
}
|
||||
createSql += "\n)"
|
||||
|
||||
// comment
|
||||
tableCommentSql := ""
|
||||
if tableInfo.TableComment != "" {
|
||||
commentTmp := "EXECUTE sp_addextendedproperty N'MS_Description', N'%s', N'SCHEMA', N'%s', N'TABLE', N'%s'"
|
||||
tableCommentSql = fmt.Sprintf(commentTmp, replacer.Replace(tableInfo.TableComment), md.dc.Info.CurrentSchema(), tbName)
|
||||
}
|
||||
|
||||
sqlArr = append(sqlArr, createSql)
|
||||
|
||||
if tableCommentSql != "" {
|
||||
sqlArr = append(sqlArr, tableCommentSql)
|
||||
}
|
||||
if len(columnComments) > 0 {
|
||||
sqlArr = append(sqlArr, columnComments...)
|
||||
}
|
||||
|
||||
return sqlArr
|
||||
}
|
||||
|
||||
// 获取建表ddl
|
||||
func (md *MssqlMetaData) GetTableDDL(tableName string) (string, error) {
|
||||
return md.CopyTableDDL(tableName, "")
|
||||
|
||||
// 1.获取表信息
|
||||
tbs, err := md.GetTables(tableName)
|
||||
tableInfo := &dbi.Table{}
|
||||
if err != nil && len(tbs) > 0 {
|
||||
|
||||
logx.Errorf("获取表信息失败, %s", tableName)
|
||||
return "", err
|
||||
}
|
||||
tableInfo.TableName = tbs[0].TableName
|
||||
tableInfo.TableComment = tbs[0].TableComment
|
||||
|
||||
// 2.获取列信息
|
||||
columns, err := md.GetColumns(tableName)
|
||||
if err != nil {
|
||||
logx.Errorf("获取列信息失败, %s", tableName)
|
||||
return "", err
|
||||
}
|
||||
tableDDLArr := md.GenerateTableDDL(columns, *tableInfo, false)
|
||||
// 3.获取索引信息
|
||||
indexs, err := md.GetTableIndex(tableName)
|
||||
if err != nil {
|
||||
logx.Errorf("获取索引信息失败, %s", tableName)
|
||||
return "", err
|
||||
}
|
||||
// 组装返回
|
||||
tableDDLArr = append(tableDDLArr, md.GenerateIndexDDL(indexs, *tableInfo)...)
|
||||
return strings.Join(tableDDLArr, ";\n"), nil
|
||||
}
|
||||
|
||||
func (md *MssqlMetaData) GetSchemas() ([]string, error) {
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"mayfly-go/internal/db/dbm/dbi"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -98,99 +97,35 @@ func (md *MysqlDialect) ToColumn(column *dbi.Column) {
|
||||
column.CharMaxLength = 1000
|
||||
} else {
|
||||
column.DataType = dbi.ColumnDataType(ctype)
|
||||
// 如果是int整型,删除精度
|
||||
if strings.Contains(strings.ToLower(ctype), "int") {
|
||||
column.NumScale = 0
|
||||
column.CharMaxLength = 0
|
||||
} else
|
||||
// 如果是text,删除长度
|
||||
if strings.Contains(strings.ToLower(ctype), "text") {
|
||||
column.CharMaxLength = 0
|
||||
column.NumPrecision = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (md *MysqlDialect) CreateTable(columns []dbi.Column, tableInfo dbi.Table, dropOldTable bool) (int, error) {
|
||||
if dropOldTable {
|
||||
_, _ = md.dc.Exec(fmt.Sprintf("DROP TABLE IF EXISTS %s", tableInfo.TableName))
|
||||
}
|
||||
// 组装建表语句
|
||||
createSql := fmt.Sprintf("CREATE TABLE %s (\n", tableInfo.TableName)
|
||||
fields := make([]string, 0)
|
||||
pks := make([]string, 0)
|
||||
// 把通用类型转换为达梦类型
|
||||
for _, column := range columns {
|
||||
if column.IsPrimaryKey {
|
||||
pks = append(pks, column.ColumnName)
|
||||
}
|
||||
fields = append(fields, md.genColumnBasicSql(column))
|
||||
}
|
||||
createSql += strings.Join(fields, ",")
|
||||
if len(pks) > 0 {
|
||||
createSql += fmt.Sprintf(", PRIMARY KEY (%s)", strings.Join(pks, ","))
|
||||
}
|
||||
createSql += ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 "
|
||||
if tableInfo.TableComment != "" {
|
||||
replacer := strings.NewReplacer(";", "", "'", "")
|
||||
createSql += fmt.Sprintf(" COMMENT '%s'", replacer.Replace(tableInfo.TableComment))
|
||||
}
|
||||
_, err := md.dc.Exec(createSql)
|
||||
|
||||
return 1, err
|
||||
}
|
||||
|
||||
func (md *MysqlDialect) genColumnBasicSql(column dbi.Column) string {
|
||||
|
||||
incr := ""
|
||||
if column.IsIdentity {
|
||||
incr = " AUTO_INCREMENT"
|
||||
}
|
||||
|
||||
nullAble := ""
|
||||
if column.Nullable == "NO" {
|
||||
nullAble = " NOT NULL"
|
||||
}
|
||||
|
||||
defVal := "" // 默认值需要判断引号,如函数是不需要引号的 // 为了防止跨源函数不支持 当默认值是函数时,不需要设置默认值
|
||||
if column.ColumnDefault != "" && !strings.Contains(column.ColumnDefault, "(") {
|
||||
// 哪些字段类型默认值需要加引号
|
||||
mark := false
|
||||
if collx.ArrayAnyMatches([]string{"char", "text", "date", "time", "lob"}, strings.ToLower(column.ColumnType)) {
|
||||
// 当数据类型是日期时间,默认值是日期时间函数时,默认值不需要引号
|
||||
if collx.ArrayAnyMatches([]string{"date", "time"}, strings.ToLower(column.ColumnType)) &&
|
||||
collx.ArrayAnyMatches([]string{"DATE", "TIME"}, strings.ToUpper(column.ColumnDefault)) {
|
||||
mark = false
|
||||
} else {
|
||||
mark = true
|
||||
}
|
||||
}
|
||||
if mark {
|
||||
defVal = fmt.Sprintf(" DEFAULT '%s'", column.ColumnDefault)
|
||||
} else {
|
||||
defVal = fmt.Sprintf(" DEFAULT %s", column.ColumnDefault)
|
||||
sqlArr := md.dc.GetMetaData().GenerateTableDDL(columns, tableInfo, dropOldTable)
|
||||
for _, sqlStr := range sqlArr {
|
||||
_, err := md.dc.Exec(sqlStr)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
comment := ""
|
||||
if column.ColumnComment != "" {
|
||||
// 防止注释内含有特殊字符串导致sql出错
|
||||
replacer := strings.NewReplacer(";", "", "'", "")
|
||||
commentStr := replacer.Replace(column.ColumnComment)
|
||||
comment = fmt.Sprintf(" COMMENT '%s'", commentStr)
|
||||
}
|
||||
|
||||
columnSql := fmt.Sprintf(" %s %s %s %s %s %s", md.dc.GetMetaData().QuoteIdentifier(column.ColumnName), column.GetColumnType(), nullAble, incr, defVal, comment)
|
||||
return columnSql
|
||||
return len(sqlArr), nil
|
||||
}
|
||||
|
||||
func (md *MysqlDialect) CreateIndex(tableInfo dbi.Table, indexs []dbi.Index) error {
|
||||
meta := md.dc.GetMetaData()
|
||||
for _, index := range indexs {
|
||||
// 通过字段、表名拼接索引名
|
||||
columnName := strings.ReplaceAll(index.ColumnName, "-", "")
|
||||
columnName = strings.ReplaceAll(columnName, "_", "")
|
||||
colName := strings.ReplaceAll(columnName, ",", "_")
|
||||
|
||||
keyType := "normal"
|
||||
unique := ""
|
||||
if index.IsUnique {
|
||||
keyType = "unique"
|
||||
unique = "unique"
|
||||
}
|
||||
indexName := fmt.Sprintf("%s_key_%s_%s", keyType, tableInfo.TableName, colName)
|
||||
sqlTmp := "ALTER TABLE %s ADD %s INDEX %s(%s) USING BTREE COMMENT '%s'"
|
||||
replacer := strings.NewReplacer(";", "", "'", "")
|
||||
_, err := md.dc.Exec(fmt.Sprintf(sqlTmp, meta.QuoteIdentifier(tableInfo.TableName), unique, indexName, index.ColumnName, replacer.Replace(index.IndexComment)))
|
||||
sqlArr := meta.GenerateIndexDDL(indexs, tableInfo)
|
||||
for _, sqlStr := range sqlArr {
|
||||
_, err := md.dc.Exec(sqlStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"mayfly-go/internal/db/dbm/dbi"
|
||||
"mayfly-go/pkg/errorx"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/utils/anyx"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"mayfly-go/pkg/utils/stringx"
|
||||
@@ -100,10 +101,10 @@ func (md *MysqlMetaData) GetColumns(tableNames ...string) ([]dbi.Column, error)
|
||||
|
||||
columns := make([]dbi.Column, 0)
|
||||
for _, re := range res {
|
||||
columns = append(columns, dbi.Column{
|
||||
|
||||
column := dbi.Column{
|
||||
TableName: anyx.ConvString(re["tableName"]),
|
||||
ColumnName: anyx.ConvString(re["columnName"]),
|
||||
ColumnType: strings.Replace(anyx.ConvString(re["columnType"]), " unsigned", "", 1),
|
||||
DataType: dbi.ColumnDataType(anyx.ConvString(re["dataType"])),
|
||||
ColumnComment: anyx.ConvString(re["columnComment"]),
|
||||
Nullable: anyx.ConvString(re["nullable"]),
|
||||
@@ -113,7 +114,11 @@ func (md *MysqlMetaData) GetColumns(tableNames ...string) ([]dbi.Column, error)
|
||||
CharMaxLength: anyx.ConvInt(re["charMaxLength"]),
|
||||
NumPrecision: anyx.ConvInt(re["numPrecision"]),
|
||||
NumScale: anyx.ConvInt(re["numScale"]),
|
||||
})
|
||||
}
|
||||
|
||||
// 初始化列展示的长度,精度
|
||||
column.InitShowNum()
|
||||
columns = append(columns, column)
|
||||
}
|
||||
return columns, nil
|
||||
}
|
||||
@@ -174,13 +179,141 @@ func (md *MysqlMetaData) GetTableIndex(tableName string) ([]dbi.Index, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 获取建索引ddl
|
||||
func (md *MysqlMetaData) GenerateIndexDDL(indexs []dbi.Index, tableInfo dbi.Table) []string {
|
||||
meta := md.dc.GetMetaData()
|
||||
sqlArr := make([]string, 0)
|
||||
for _, index := range indexs {
|
||||
// 通过字段、表名拼接索引名
|
||||
columnName := strings.ReplaceAll(index.ColumnName, "-", "")
|
||||
columnName = strings.ReplaceAll(columnName, "_", "")
|
||||
colName := strings.ReplaceAll(columnName, ",", "_")
|
||||
|
||||
keyType := "normal"
|
||||
unique := ""
|
||||
if index.IsUnique {
|
||||
keyType = "unique"
|
||||
unique = "unique"
|
||||
}
|
||||
indexName := fmt.Sprintf("%s_key_%s_%s", keyType, tableInfo.TableName, colName)
|
||||
sqlTmp := "ALTER TABLE %s ADD %s INDEX %s(%s) USING BTREE COMMENT '%s'"
|
||||
replacer := strings.NewReplacer(";", "", "'", "")
|
||||
sqlArr = append(sqlArr, fmt.Sprintf(sqlTmp, meta.QuoteIdentifier(tableInfo.TableName), unique, indexName, index.ColumnName, replacer.Replace(index.IndexComment)))
|
||||
}
|
||||
return sqlArr
|
||||
}
|
||||
|
||||
func (md *MysqlMetaData) genColumnBasicSql(column dbi.Column) string {
|
||||
replacer := strings.NewReplacer(";", "", "'", "")
|
||||
dataType := string(column.DataType)
|
||||
|
||||
incr := ""
|
||||
if column.IsIdentity {
|
||||
incr = " AUTO_INCREMENT"
|
||||
}
|
||||
|
||||
nullAble := ""
|
||||
if column.Nullable == "NO" {
|
||||
nullAble = " NOT NULL"
|
||||
}
|
||||
|
||||
defVal := "" // 默认值需要判断引号,如函数是不需要引号的 // 为了防止跨源函数不支持 当默认值是函数时,不需要设置默认值
|
||||
if column.ColumnDefault != "" && !strings.Contains(column.ColumnDefault, "(") {
|
||||
// 哪些字段类型默认值需要加引号
|
||||
mark := false
|
||||
if collx.ArrayAnyMatches([]string{"char", "text", "date", "time", "lob"}, strings.ToLower(dataType)) {
|
||||
// 当数据类型是日期时间,默认值是日期时间函数时,默认值不需要引号
|
||||
if collx.ArrayAnyMatches([]string{"date", "time"}, strings.ToLower(dataType)) &&
|
||||
collx.ArrayAnyMatches([]string{"DATE", "TIME"}, strings.ToUpper(column.ColumnDefault)) {
|
||||
mark = false
|
||||
} else {
|
||||
mark = true
|
||||
}
|
||||
}
|
||||
if mark {
|
||||
defVal = fmt.Sprintf(" DEFAULT '%s'", column.ColumnDefault)
|
||||
} else {
|
||||
defVal = fmt.Sprintf(" DEFAULT %s", column.ColumnDefault)
|
||||
}
|
||||
}
|
||||
comment := ""
|
||||
if column.ColumnComment != "" {
|
||||
// 防止注释内含有特殊字符串导致sql出错
|
||||
commentStr := replacer.Replace(column.ColumnComment)
|
||||
comment = fmt.Sprintf(" COMMENT '%s'", commentStr)
|
||||
}
|
||||
|
||||
columnSql := fmt.Sprintf(" %s %s %s %s %s %s", md.dc.GetMetaData().QuoteIdentifier(column.ColumnName), column.ShowDataType, nullAble, incr, defVal, comment)
|
||||
return columnSql
|
||||
}
|
||||
|
||||
// 获取建表ddl
|
||||
func (md *MysqlMetaData) GenerateTableDDL(columns []dbi.Column, tableInfo dbi.Table, dropBeforeCreate bool) []string {
|
||||
meta := md.dc.GetMetaData()
|
||||
sqlArr := make([]string, 0)
|
||||
|
||||
if dropBeforeCreate {
|
||||
sqlArr = append(sqlArr, fmt.Sprintf("DROP TABLE IF EXISTS %s;", meta.QuoteIdentifier(tableInfo.TableName)))
|
||||
}
|
||||
|
||||
// 组装建表语句
|
||||
createSql := fmt.Sprintf("CREATE TABLE %s (\n", meta.QuoteIdentifier(tableInfo.TableName))
|
||||
fields := make([]string, 0)
|
||||
pks := make([]string, 0)
|
||||
// 把通用类型转换为达梦类型
|
||||
for _, column := range columns {
|
||||
if column.IsPrimaryKey {
|
||||
pks = append(pks, column.ColumnName)
|
||||
}
|
||||
fields = append(fields, md.genColumnBasicSql(column))
|
||||
}
|
||||
|
||||
// 建表ddl
|
||||
createSql += strings.Join(fields, ",\n")
|
||||
if len(pks) > 0 {
|
||||
createSql += fmt.Sprintf(", \nPRIMARY KEY (%s)", strings.Join(pks, ","))
|
||||
}
|
||||
createSql += fmt.Sprintf(") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ")
|
||||
|
||||
// 表注释
|
||||
if tableInfo.TableComment != "" {
|
||||
replacer := strings.NewReplacer(";", "", "'", "")
|
||||
createSql += fmt.Sprintf(" COMMENT '%s'", replacer.Replace(tableInfo.TableComment))
|
||||
}
|
||||
|
||||
sqlArr = append(sqlArr, createSql)
|
||||
|
||||
return sqlArr
|
||||
}
|
||||
|
||||
// 获取建表ddl
|
||||
func (md *MysqlMetaData) GetTableDDL(tableName string) (string, error) {
|
||||
_, res, err := md.dc.Query(fmt.Sprintf("show create table `%s` ", tableName))
|
||||
if err != nil {
|
||||
// 1.获取表信息
|
||||
tbs, err := md.GetTables(tableName)
|
||||
tableInfo := &dbi.Table{}
|
||||
if err != nil && len(tbs) > 0 {
|
||||
logx.Errorf("获取表信息失败, %s", tableName)
|
||||
return "", err
|
||||
}
|
||||
return anyx.ConvString(res[0]["Create Table"]) + ";", nil
|
||||
tableInfo.TableName = tbs[0].TableName
|
||||
tableInfo.TableComment = tbs[0].TableComment
|
||||
|
||||
// 2.获取列信息
|
||||
columns, err := md.GetColumns(tableName)
|
||||
if err != nil {
|
||||
logx.Errorf("获取列信息失败, %s", tableName)
|
||||
return "", err
|
||||
}
|
||||
tableDDLArr := md.GenerateTableDDL(columns, *tableInfo, false)
|
||||
// 3.获取索引信息
|
||||
indexs, err := md.GetTableIndex(tableName)
|
||||
if err != nil {
|
||||
logx.Errorf("获取索引信息失败, %s", tableName)
|
||||
return "", err
|
||||
}
|
||||
// 组装返回
|
||||
tableDDLArr = append(tableDDLArr, md.GenerateIndexDDL(indexs, *tableInfo)...)
|
||||
return strings.Join(tableDDLArr, ";\n"), nil
|
||||
}
|
||||
|
||||
func (md *MysqlMetaData) GetSchemas() ([]string, error) {
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"mayfly-go/internal/db/dbm/dbi"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/utils/anyx"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -156,213 +155,60 @@ func (od *OracleDialect) CopyTable(copy *dbi.DbCopyTable) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// func (od *OracleDialect) TransColumns(columns []dbi.Column) []dbi.Column {
|
||||
// var commonColumns []dbi.Column
|
||||
// for _, column := range columns {
|
||||
// // 取出当前数据库类型
|
||||
// arr := strings.Split(column.ColumnType, "(")
|
||||
// ctype := arr[0]
|
||||
func (od *OracleDialect) ToCommonColumn(dialectColumn *dbi.Column) {
|
||||
// 翻译为通用数据库类型
|
||||
dataType := dialectColumn.DataType
|
||||
t1 := commonColumnTypeMap[string(dataType)]
|
||||
if t1 == "" {
|
||||
dialectColumn.DataType = dbi.CommonTypeVarchar
|
||||
dialectColumn.CharMaxLength = 2000
|
||||
} else {
|
||||
dialectColumn.DataType = t1
|
||||
// 如果是number类型,需要根据公共类型加上长度, 如 bigint 需要转换为number(19,0)
|
||||
if strings.Contains(string(t1), "NUMBER") {
|
||||
dialectColumn.CharMaxLength = 19
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// // 翻译为通用数据库类型
|
||||
// t1 := commonColumnTypeMap[ctype]
|
||||
// if t1 == "" {
|
||||
// ctype = "NVARCHAR2(2000)"
|
||||
// } else {
|
||||
// // 回写到列信息
|
||||
// if t1 == "NUMBER" {
|
||||
// // 如果是转number类型,需要根据公共类型加上长度, 如 bigint 需要转换为number(19,0)
|
||||
// if column.ColumnType == dbi.CommonTypeBigint {
|
||||
// ctype = t1 + "(19, 0)"
|
||||
// } else {
|
||||
// ctype = t1
|
||||
// }
|
||||
// } else if t1 != "NUMBER" && len(arr) > 1 {
|
||||
// ctype = t1 + "(" + arr[1]
|
||||
// } else {
|
||||
// ctype = t1
|
||||
// }
|
||||
// }
|
||||
// column.ColumnType = ctype
|
||||
// commonColumns = append(commonColumns, column)
|
||||
// }
|
||||
// return commonColumns
|
||||
// }
|
||||
func (od *OracleDialect) ToColumn(commonColumn *dbi.Column) {
|
||||
ctype := oracleColumnTypeMap[commonColumn.DataType]
|
||||
if ctype == "" {
|
||||
commonColumn.DataType = "NVARCHAR2"
|
||||
commonColumn.CharMaxLength = 2000
|
||||
} else {
|
||||
commonColumn.DataType = dbi.ColumnDataType(ctype)
|
||||
// 如果类型是数字,类型后不需要带长度
|
||||
if strings.Contains(strings.ToLower(ctype), "int") {
|
||||
commonColumn.CharMaxLength = 0
|
||||
commonColumn.NumPrecision = 0
|
||||
} else if strings.Contains(strings.ToLower(ctype), "char") {
|
||||
// 如果是字符串类型,长度最大4000,否则修改字段类型为clob
|
||||
if commonColumn.CharMaxLength > 4000 {
|
||||
commonColumn.DataType = "CLOB"
|
||||
commonColumn.CharMaxLength = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (od *OracleDialect) CreateTable(commonColumns []dbi.Column, tableInfo dbi.Table, dropOldTable bool) (int, error) {
|
||||
meta := od.dc.GetMetaData()
|
||||
replacer := strings.NewReplacer(";", "", "'", "")
|
||||
quoteTableName := meta.QuoteIdentifier(tableInfo.TableName)
|
||||
if dropOldTable {
|
||||
// 如果表存在,先删除表
|
||||
dropSqlTmp := `
|
||||
declare
|
||||
num number;
|
||||
begin
|
||||
select count(1) into num from user_tables where table_name = '%s' and owner = (SELECT sys_context('USERENV', 'CURRENT_SCHEMA') FROM dual) ;
|
||||
if num > 0 then
|
||||
execute immediate 'drop table "%s"' ;
|
||||
end if;
|
||||
end;
|
||||
`
|
||||
_, _ = od.dc.Exec(fmt.Sprintf(dropSqlTmp, tableInfo.TableName, tableInfo.TableName))
|
||||
}
|
||||
// 组装建表语句
|
||||
createSql := fmt.Sprintf("CREATE TABLE %s (", quoteTableName)
|
||||
fields := make([]string, 0)
|
||||
pks := make([]string, 0)
|
||||
columnComments := make([]string, 0)
|
||||
// 把通用类型转换为达梦类型
|
||||
for _, column := range commonColumns {
|
||||
// 取出当前数据库类型
|
||||
arr := strings.Split(column.ColumnType, "(")
|
||||
ctype := arr[0]
|
||||
// 翻译为通用数据库类型
|
||||
t1 := oracleColumnTypeMap[dbi.ColumnDataType(ctype)]
|
||||
if t1 == "" {
|
||||
ctype = "NVARCHAR2(2000)"
|
||||
} else {
|
||||
// 回写到列信息
|
||||
if len(arr) > 1 {
|
||||
// 如果是字符串类型,长度最大4000,否则修改字段类型为clob
|
||||
if strings.Contains(strings.ToLower(t1), "char") {
|
||||
match := bracketsRegexp.FindStringSubmatch(column.ColumnType)
|
||||
if len(match) > 1 {
|
||||
size := anyx.ConvInt(match[1])
|
||||
if size >= 4000 { // 如果长度超过4000,则替换为text类型
|
||||
ctype = "CLOB"
|
||||
} else {
|
||||
ctype = fmt.Sprintf("%s(%d)", t1, size)
|
||||
}
|
||||
} else {
|
||||
ctype = t1 + "(2000)"
|
||||
}
|
||||
} else {
|
||||
ctype = t1 + "(" + arr[1]
|
||||
}
|
||||
} else {
|
||||
ctype = t1
|
||||
}
|
||||
}
|
||||
column.ColumnType = ctype
|
||||
|
||||
if column.IsPrimaryKey {
|
||||
pks = append(pks, meta.QuoteIdentifier(column.ColumnName))
|
||||
}
|
||||
fields = append(fields, od.genColumnBasicSql(column))
|
||||
// 防止注释内含有特殊字符串导致sql出错
|
||||
comment := replacer.Replace(column.ColumnComment)
|
||||
if comment != "" {
|
||||
columnComments = append(columnComments, fmt.Sprintf("COMMENT ON COLUMN %s.%s IS '%s'", quoteTableName, meta.QuoteIdentifier(column.ColumnName), comment))
|
||||
}
|
||||
}
|
||||
createSql += strings.Join(fields, ",")
|
||||
if len(pks) > 0 {
|
||||
createSql += fmt.Sprintf(", PRIMARY KEY (%s)", strings.Join(pks, ","))
|
||||
}
|
||||
createSql += ")"
|
||||
|
||||
tableCommentSql := ""
|
||||
if tableInfo.TableComment != "" {
|
||||
tableCommentSql = fmt.Sprintf(" COMMENT ON TABLE %s is '%s'", meta.QuoteIdentifier(tableInfo.TableName), replacer.Replace(tableInfo.TableComment))
|
||||
}
|
||||
|
||||
sqlArr := meta.GenerateTableDDL(commonColumns, tableInfo, dropOldTable)
|
||||
// 需要分开执行sql
|
||||
var err error
|
||||
if createSql != "" {
|
||||
_, err = od.dc.Exec(createSql)
|
||||
}
|
||||
if tableCommentSql != "" {
|
||||
_, err = od.dc.Exec(tableCommentSql)
|
||||
}
|
||||
if len(columnComments) > 0 {
|
||||
for _, commentSql := range columnComments {
|
||||
_, err = od.dc.Exec(commentSql)
|
||||
for _, sqlStr := range sqlArr {
|
||||
_, err := od.dc.Exec(sqlStr)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
return 1, err
|
||||
}
|
||||
|
||||
func (od *OracleDialect) genColumnBasicSql(column dbi.Column) string {
|
||||
meta := od.dc.GetMetaData()
|
||||
colName := meta.QuoteIdentifier(column.ColumnName)
|
||||
|
||||
if column.IsIdentity {
|
||||
// 如果是自增,不需要设置默认值和空值,自增列数据类型必须是number
|
||||
return fmt.Sprintf(" %s NUMBER generated by default as IDENTITY", colName)
|
||||
}
|
||||
|
||||
nullAble := ""
|
||||
if column.Nullable == "NO" {
|
||||
nullAble = " NOT NULL"
|
||||
}
|
||||
|
||||
defVal := "" // 默认值需要判断引号,如函数是不需要引号的
|
||||
if column.ColumnDefault != "" {
|
||||
mark := false
|
||||
// 哪些字段类型默认值需要加引号
|
||||
if collx.ArrayAnyMatches([]string{"CHAR", "LONG", "DATE", "TIME", "CLOB", "BLOB", "BFILE"}, column.ColumnType) {
|
||||
// 默认值是时间日期函数的必须要加引号
|
||||
val := strings.ToUpper(column.ColumnDefault)
|
||||
if collx.ArrayAnyMatches([]string{"DATE", "TIMESTAMP"}, column.ColumnType) && val == "CURRENT_DATE" || val == "CURRENT_TIMESTAMP" {
|
||||
mark = false
|
||||
} else {
|
||||
mark = true
|
||||
}
|
||||
if mark {
|
||||
defVal = fmt.Sprintf(" DEFAULT '%s'", column.ColumnDefault)
|
||||
} else {
|
||||
defVal = fmt.Sprintf(" DEFAULT %s", column.ColumnDefault)
|
||||
}
|
||||
} else {
|
||||
// 如果是数字,默认值提取数字
|
||||
if collx.ArrayAnyMatches([]string{"NUM", "INT"}, column.ColumnType) {
|
||||
match := bracketsRegexp.FindStringSubmatch(column.ColumnType)
|
||||
if len(match) > 1 {
|
||||
length := anyx.ConvInt(match[1])
|
||||
defVal = fmt.Sprintf(" DEFAULT %d", length)
|
||||
} else {
|
||||
defVal = fmt.Sprintf(" DEFAULT 0")
|
||||
}
|
||||
}
|
||||
|
||||
defVal = fmt.Sprintf(" DEFAULT %s", column.ColumnDefault)
|
||||
}
|
||||
}
|
||||
|
||||
columnSql := fmt.Sprintf(" %s %s %s %s", colName, column.ColumnType, defVal, nullAble)
|
||||
return columnSql
|
||||
return len(sqlArr), nil
|
||||
}
|
||||
|
||||
func (od *OracleDialect) CreateIndex(tableInfo dbi.Table, indexs []dbi.Index) error {
|
||||
meta := od.dc.GetMetaData()
|
||||
sqls := make([]string, 0)
|
||||
comments := make([]string, 0)
|
||||
for _, index := range indexs {
|
||||
// 通过字段、表名拼接索引名
|
||||
columnName := strings.ReplaceAll(index.ColumnName, "-", "")
|
||||
columnName = strings.ReplaceAll(columnName, "_", "")
|
||||
colName := strings.ReplaceAll(columnName, ",", "_")
|
||||
|
||||
keyType := "normal"
|
||||
unique := ""
|
||||
if index.IsUnique {
|
||||
keyType = "unique"
|
||||
unique = "unique"
|
||||
}
|
||||
indexName := fmt.Sprintf("%s_key_%s_%s", keyType, tableInfo.TableName, colName)
|
||||
|
||||
sqls = append(sqls, fmt.Sprintf("CREATE %s INDEX %s ON %s(%s)", unique, indexName, meta.QuoteIdentifier(tableInfo.TableName), index.ColumnName))
|
||||
if index.IndexComment != "" {
|
||||
comments = append(comments, fmt.Sprintf("COMMENT ON INDEX %s IS '%s'", indexName, index.IndexComment))
|
||||
}
|
||||
}
|
||||
_, err := od.dc.Exec(strings.Join(sqls, ";"))
|
||||
|
||||
// 添加注释
|
||||
if len(comments) > 0 {
|
||||
_, err = od.dc.Exec(strings.Join(comments, ";"))
|
||||
}
|
||||
sqlArr := meta.GenerateIndexDDL(indexs, tableInfo)
|
||||
_, err := od.dc.Exec(strings.Join(sqlArr, ";"))
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"mayfly-go/internal/db/dbm/dbi"
|
||||
"mayfly-go/pkg/errorx"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/utils/anyx"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"mayfly-go/pkg/utils/stringx"
|
||||
@@ -122,17 +123,21 @@ func (od *OracleMetaData) GetColumns(tableNames ...string) ([]dbi.Column, error)
|
||||
if strings.Contains(defaultVal, ".nextval") {
|
||||
defaultVal = ""
|
||||
}
|
||||
columns = append(columns, dbi.Column{
|
||||
column := dbi.Column{
|
||||
TableName: anyx.ConvString(re["TABLE_NAME"]),
|
||||
ColumnName: anyx.ConvString(re["COLUMN_NAME"]),
|
||||
ColumnType: anyx.ConvString(re["COLUMN_TYPE"]),
|
||||
DataType: dbi.ColumnDataType(anyx.ConvString(re["DATA_TYPE"])),
|
||||
ColumnComment: anyx.ConvString(re["COLUMN_COMMENT"]),
|
||||
Nullable: anyx.ConvString(re["NULLABLE"]),
|
||||
IsPrimaryKey: anyx.ConvInt(re["IS_PRIMARY_KEY"]) == 1,
|
||||
IsIdentity: anyx.ConvInt(re["IS_IDENTITY"]) == 1,
|
||||
ColumnDefault: defaultVal,
|
||||
NumScale: anyx.ConvInt(re["NUM_SCALE"]),
|
||||
})
|
||||
}
|
||||
|
||||
// 初始化列展示的长度,精度
|
||||
column.InitShowNum()
|
||||
columns = append(columns, column)
|
||||
}
|
||||
return columns, nil
|
||||
}
|
||||
@@ -191,71 +196,188 @@ func (od *OracleMetaData) GetTableIndex(tableName string) ([]dbi.Index, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 获取建索引ddl
|
||||
func (od *OracleMetaData) GenerateIndexDDL(indexs []dbi.Index, tableInfo dbi.Table) []string {
|
||||
|
||||
meta := od.dc.GetMetaData()
|
||||
sqls := make([]string, 0)
|
||||
comments := make([]string, 0)
|
||||
|
||||
for _, index := range indexs {
|
||||
// 通过字段、表名拼接索引名
|
||||
columnName := strings.ReplaceAll(index.ColumnName, "-", "")
|
||||
columnName = strings.ReplaceAll(columnName, "_", "")
|
||||
colName := strings.ReplaceAll(columnName, ",", "_")
|
||||
|
||||
keyType := "normal"
|
||||
unique := ""
|
||||
if index.IsUnique {
|
||||
keyType = "unique"
|
||||
unique = "unique"
|
||||
}
|
||||
indexName := fmt.Sprintf("%s_key_%s_%s", keyType, tableInfo.TableName, colName)
|
||||
|
||||
sqls = append(sqls, fmt.Sprintf("CREATE %s INDEX %s ON %s(%s)", unique, indexName, meta.QuoteIdentifier(tableInfo.TableName), index.ColumnName))
|
||||
if index.IndexComment != "" {
|
||||
comments = append(comments, fmt.Sprintf("COMMENT ON INDEX %s IS '%s'", indexName, index.IndexComment))
|
||||
}
|
||||
}
|
||||
|
||||
sqlArr := make([]string, 0)
|
||||
|
||||
sqlArr = append(sqlArr, sqls...)
|
||||
|
||||
if len(comments) > 0 {
|
||||
sqlArr = append(sqlArr, comments...)
|
||||
}
|
||||
|
||||
return sqlArr
|
||||
}
|
||||
|
||||
func (od *OracleMetaData) genColumnBasicSql(column dbi.Column) string {
|
||||
meta := od.dc.GetMetaData()
|
||||
colName := meta.QuoteIdentifier(column.ColumnName)
|
||||
dataType := string(column.DataType)
|
||||
|
||||
if column.IsIdentity {
|
||||
// 如果是自增,不需要设置默认值和空值,自增列数据类型必须是number
|
||||
return fmt.Sprintf(" %s NUMBER generated by default as IDENTITY", colName)
|
||||
}
|
||||
|
||||
nullAble := ""
|
||||
if column.Nullable == "NO" {
|
||||
nullAble = " NOT NULL"
|
||||
}
|
||||
|
||||
defVal := "" // 默认值需要判断引号,如函数是不需要引号的
|
||||
if column.ColumnDefault != "" {
|
||||
mark := false
|
||||
// 哪些字段类型默认值需要加引号
|
||||
if collx.ArrayAnyMatches([]string{"CHAR", "LONG", "DATE", "TIME", "CLOB", "BLOB", "BFILE"}, dataType) {
|
||||
// 默认值是时间日期函数的必须要加引号
|
||||
val := strings.ToUpper(column.ColumnDefault)
|
||||
if collx.ArrayAnyMatches([]string{"DATE", "TIMESTAMP"}, dataType) && val == "CURRENT_DATE" || val == "CURRENT_TIMESTAMP" {
|
||||
mark = false
|
||||
} else {
|
||||
mark = true
|
||||
}
|
||||
if mark {
|
||||
defVal = fmt.Sprintf(" DEFAULT '%s'", column.ColumnDefault)
|
||||
} else {
|
||||
defVal = fmt.Sprintf(" DEFAULT %s", column.ColumnDefault)
|
||||
}
|
||||
} else {
|
||||
// 如果是数字,默认值提取数字
|
||||
if collx.ArrayAnyMatches([]string{"NUM", "INT"}, dataType) {
|
||||
match := bracketsRegexp.FindStringSubmatch(dataType)
|
||||
if len(match) > 1 {
|
||||
length := anyx.ConvInt(match[1])
|
||||
defVal = fmt.Sprintf(" DEFAULT %d", length)
|
||||
} else {
|
||||
defVal = fmt.Sprintf(" DEFAULT 0")
|
||||
}
|
||||
}
|
||||
|
||||
defVal = fmt.Sprintf(" DEFAULT %s", column.ColumnDefault)
|
||||
}
|
||||
}
|
||||
|
||||
columnSql := fmt.Sprintf(" %s %s %s %s", colName, column.ShowDataType, defVal, nullAble)
|
||||
return columnSql
|
||||
}
|
||||
|
||||
// 获取建表ddl
|
||||
func (od *OracleMetaData) GetTableDDL(tableName string) (string, error) {
|
||||
ddlSql := fmt.Sprintf("SELECT DBMS_METADATA.GET_DDL('TABLE', '%s', (SELECT sys_context('USERENV', 'CURRENT_SCHEMA') FROM dual)) AS TABLE_DDL FROM DUAL", tableName)
|
||||
_, res, err := od.dc.Query(ddlSql)
|
||||
if err != nil {
|
||||
return "", err
|
||||
func (od *OracleMetaData) GenerateTableDDL(columns []dbi.Column, tableInfo dbi.Table, dropBeforeCreate bool) []string {
|
||||
meta := od.dc.GetMetaData()
|
||||
replacer := strings.NewReplacer(";", "", "'", "")
|
||||
quoteTableName := meta.QuoteIdentifier(tableInfo.TableName)
|
||||
sqlArr := make([]string, 0)
|
||||
|
||||
if dropBeforeCreate {
|
||||
dropSqlTmp := `
|
||||
declare
|
||||
num number;
|
||||
begin
|
||||
select count(1) into num from user_tables where table_name = '%s' and owner = (SELECT sys_context('USERENV', 'CURRENT_SCHEMA') FROM dual) ;
|
||||
if num > 0 then
|
||||
execute immediate 'drop table "%s"' ;
|
||||
end if;
|
||||
end;
|
||||
`
|
||||
sqlArr = append(sqlArr, fmt.Sprintf(dropSqlTmp, tableInfo.TableName, tableInfo.TableName))
|
||||
}
|
||||
// 建表ddl
|
||||
var builder strings.Builder
|
||||
for _, re := range res {
|
||||
builder.WriteString(anyx.ConvString(re["TABLE_DDL"]))
|
||||
|
||||
// 组装建表语句
|
||||
createSql := fmt.Sprintf("CREATE TABLE %s ( \n", quoteTableName)
|
||||
fields := make([]string, 0)
|
||||
pks := make([]string, 0)
|
||||
columnComments := make([]string, 0)
|
||||
// 把通用类型转换为达梦类型
|
||||
for _, column := range columns {
|
||||
if column.IsPrimaryKey {
|
||||
pks = append(pks, meta.QuoteIdentifier(column.ColumnName))
|
||||
}
|
||||
fields = append(fields, od.genColumnBasicSql(column))
|
||||
// 防止注释内含有特殊字符串导致sql出错
|
||||
if column.ColumnComment != "" {
|
||||
comment := replacer.Replace(column.ColumnComment)
|
||||
columnComments = append(columnComments, fmt.Sprintf("COMMENT ON COLUMN %s.%s IS '%s'", quoteTableName, meta.QuoteIdentifier(column.ColumnName), comment))
|
||||
}
|
||||
}
|
||||
|
||||
// 建表
|
||||
createSql += strings.Join(fields, ",\n")
|
||||
if len(pks) > 0 {
|
||||
createSql += fmt.Sprintf(", \nPRIMARY KEY (%s)", strings.Join(pks, ","))
|
||||
}
|
||||
createSql += "\n)"
|
||||
sqlArr = append(sqlArr, createSql)
|
||||
|
||||
// 表注释
|
||||
_, res, err = od.dc.Query(fmt.Sprintf(`
|
||||
select OWNER, COMMENTS from ALL_TAB_COMMENTS where TABLE_TYPE='TABLE' and TABLE_NAME = '%s'
|
||||
and owner = (SELECT sys_context('USERENV', 'CURRENT_SCHEMA') FROM dual) `, tableName))
|
||||
if err != nil {
|
||||
tableCommentSql := ""
|
||||
if tableInfo.TableComment != "" {
|
||||
tableCommentSql = fmt.Sprintf("COMMENT ON TABLE %s is '%s'", meta.QuoteIdentifier(tableInfo.TableName), replacer.Replace(tableInfo.TableComment))
|
||||
sqlArr = append(sqlArr, tableCommentSql)
|
||||
}
|
||||
|
||||
// 列注释
|
||||
if len(columnComments) > 0 {
|
||||
sqlArr = append(sqlArr, columnComments...)
|
||||
}
|
||||
|
||||
return sqlArr
|
||||
}
|
||||
|
||||
// 获取建表ddl
|
||||
func (od *OracleMetaData) GetTableDDL(tableName string) (string, error) {
|
||||
|
||||
// 1.获取表信息
|
||||
tbs, err := od.GetTables(tableName)
|
||||
tableInfo := &dbi.Table{}
|
||||
if err != nil && len(tbs) > 0 {
|
||||
|
||||
logx.Errorf("获取表信息失败, %s", tableName)
|
||||
return "", err
|
||||
}
|
||||
for _, re := range res {
|
||||
// COMMENT ON TABLE "SYS_MENU" IS '菜单表';
|
||||
if re["COMMENTS"] != nil {
|
||||
tableComment := fmt.Sprintf("\n\nCOMMENT ON TABLE \"%s\".\"%s\" IS '%s';", re["OWNER"].(string), tableName, re["COMMENTS"].(string))
|
||||
builder.WriteString(tableComment)
|
||||
}
|
||||
}
|
||||
tableInfo.TableName = tbs[0].TableName
|
||||
tableInfo.TableComment = tbs[0].TableComment
|
||||
|
||||
// 字段注释
|
||||
fieldSql := fmt.Sprintf(`
|
||||
SELECT OWNER, COLUMN_NAME, COMMENTS
|
||||
FROM ALL_COL_COMMENTS
|
||||
WHERE OWNER = (SELECT sys_context('USERENV', 'CURRENT_SCHEMA') FROM dual)
|
||||
AND TABLE_NAME = '%s'
|
||||
`, tableName)
|
||||
_, res, err = od.dc.Query(fieldSql)
|
||||
// 2.获取列信息
|
||||
columns, err := od.GetColumns(tableName)
|
||||
if err != nil {
|
||||
logx.Errorf("获取列信息失败, %s", tableName)
|
||||
return "", err
|
||||
}
|
||||
|
||||
builder.WriteString("\n")
|
||||
for _, re := range res {
|
||||
// COMMENT ON COLUMN "SYS_MENU"."BIZ_CODE" IS '业务编码,应用编码1';
|
||||
if re["COMMENTS"] != nil {
|
||||
fieldComment := fmt.Sprintf("\nCOMMENT ON COLUMN \"%s\".\"%s\".\"%s\" IS '%s';", re["OWNER"].(string), tableName, re["COLUMN_NAME"].(string), re["COMMENTS"].(string))
|
||||
builder.WriteString(fieldComment)
|
||||
}
|
||||
}
|
||||
|
||||
// 索引信息
|
||||
indexSql := fmt.Sprintf(`
|
||||
select DBMS_METADATA.GET_DDL('INDEX', a.INDEX_NAME, a.OWNER) AS INDEX_DEF from ALL_INDEXES a
|
||||
join ALL_objects b on a.owner = b.owner and b.object_name = a.index_name and b.object_type = 'INDEX'
|
||||
where a.owner = (SELECT sys_context('USERENV', 'CURRENT_SCHEMA') FROM dual)
|
||||
and a.table_name = '%s'
|
||||
`, tableName)
|
||||
_, res, err = od.dc.Query(indexSql)
|
||||
tableDDLArr := od.GenerateTableDDL(columns, *tableInfo, false)
|
||||
// 3.获取索引信息
|
||||
indexs, err := od.GetTableIndex(tableName)
|
||||
if err != nil {
|
||||
logx.Errorf("获取索引信息失败, %s", tableName)
|
||||
return "", err
|
||||
}
|
||||
for _, re := range res {
|
||||
builder.WriteString("\n\n" + anyx.ConvString(re["INDEX_DEF"]))
|
||||
}
|
||||
|
||||
return builder.String(), nil
|
||||
// 组装返回
|
||||
tableDDLArr = append(tableDDLArr, od.GenerateIndexDDL(indexs, *tableInfo)...)
|
||||
return strings.Join(tableDDLArr, ";\n"), nil
|
||||
}
|
||||
|
||||
// 获取DM当前连接的库可访问的schemaNames
|
||||
|
||||
@@ -66,7 +66,7 @@ func (pd *PgsqlDialect) pgsqlOnDuplicateStrategySql(duplicateStrategy int, table
|
||||
updateColumns = append(updateColumns, fmt.Sprintf("%s = excluded.%s", col, col))
|
||||
}
|
||||
// 查询唯一键名,拼接冲突sql
|
||||
_, keyRes, _ := pd.dc.Query("SELECT constraint_name FROM information_schema.table_constraints WHERE constraint_schema = $1 AND table_name = $2 AND constraint_type in ('PRIMARY KEY', 'UNIQUE') ", pd.currentSchema(), tableName)
|
||||
_, keyRes, _ := pd.dc.Query("SELECT constraint_name FROM information_schema.table_constraints WHERE constraint_schema = $1 AND table_name = $2 AND constraint_type in ('PRIMARY KEY', 'UNIQUE') ", pd.dc.Info.CurrentSchema(), tableName)
|
||||
if len(keyRes) > 0 {
|
||||
for _, re := range keyRes {
|
||||
key := anyx.ToString(re["constraint_name"])
|
||||
@@ -117,11 +117,6 @@ func (pd *PgsqlDialect) gaussOnDuplicateStrategySql(duplicateStrategy int, table
|
||||
return suffix
|
||||
}
|
||||
|
||||
// 从连接信息中获取数据库和schema信息
|
||||
func (pd *PgsqlDialect) currentSchema() string {
|
||||
return pd.dc.Info.CurrentSchema()
|
||||
}
|
||||
|
||||
func (pd *PgsqlDialect) CopyTable(copy *dbi.DbCopyTable) error {
|
||||
tableName := copy.TableName
|
||||
// 生成新表名,为老表明+_copy_时间戳
|
||||
@@ -180,189 +175,48 @@ func (pd *PgsqlDialect) CopyTable(copy *dbi.DbCopyTable) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (pd *PgsqlDialect) CreateTable(commonColumns []dbi.Column, tableInfo dbi.Table, dropOldTable bool) (int, error) {
|
||||
meta := pd.dc.GetMetaData()
|
||||
replacer := strings.NewReplacer(";", "", "'", "")
|
||||
if dropOldTable {
|
||||
_, _ = pd.dc.Exec(fmt.Sprintf("DROP TABLE IF EXISTS %s", tableInfo.TableName))
|
||||
func (pd *PgsqlDialect) ToCommonColumn(column *dbi.Column) {
|
||||
// 翻译为通用数据库类型
|
||||
dataType := column.DataType
|
||||
t1 := commonColumnTypeMap[string(dataType)]
|
||||
if t1 == "" {
|
||||
column.DataType = dbi.CommonTypeVarchar
|
||||
column.CharMaxLength = 2000
|
||||
} else {
|
||||
column.DataType = t1
|
||||
}
|
||||
// 组装建表语句
|
||||
createSql := fmt.Sprintf("CREATE TABLE %s (\n", meta.QuoteIdentifier(tableInfo.TableName))
|
||||
fields := make([]string, 0)
|
||||
pks := make([]string, 0)
|
||||
columnComments := make([]string, 0)
|
||||
// 把通用类型转换为达梦类型
|
||||
for _, column := range commonColumns {
|
||||
// 取出当前数据库类型
|
||||
arr := strings.Split(column.ColumnType, "(")
|
||||
ctype := arr[0]
|
||||
// 翻译为通用数据库类型
|
||||
t1 := pgsqlColumnTypeMap[dbi.ColumnDataType(ctype)]
|
||||
if t1 == "" {
|
||||
ctype = "varchar(2000)"
|
||||
} else {
|
||||
// 回写到列信息
|
||||
if len(arr) > 1 {
|
||||
if strings.Contains(strings.ToLower(t1), "int") {
|
||||
// 如果是数字,类型后不需要带长度
|
||||
ctype = t1
|
||||
} else if strings.Contains(strings.ToLower(t1), "char") {
|
||||
// 如果是字符串,长度翻倍
|
||||
match := bracketsRegexp.FindStringSubmatch(column.ColumnType)
|
||||
if len(match) > 1 {
|
||||
ctype = fmt.Sprintf("%s(%d)", t1, anyx.ConvInt(match[1])*2)
|
||||
} else {
|
||||
ctype = t1 + "(1000)"
|
||||
}
|
||||
} else {
|
||||
ctype = t1 + "(" + arr[1]
|
||||
}
|
||||
} else {
|
||||
ctype = t1
|
||||
}
|
||||
}
|
||||
column.ColumnType = ctype
|
||||
|
||||
if column.IsPrimaryKey {
|
||||
pks = append(pks, meta.QuoteIdentifier(column.ColumnName))
|
||||
}
|
||||
fields = append(fields, pd.genColumnBasicSql(column))
|
||||
commentTmp := "comment on column %s.%s is '%s'"
|
||||
// 防止注释内含有特殊字符串导致sql出错
|
||||
comment := replacer.Replace(column.ColumnComment)
|
||||
columnComments = append(columnComments, fmt.Sprintf(commentTmp, column.TableName, column.ColumnName, comment))
|
||||
}
|
||||
createSql += strings.Join(fields, ",")
|
||||
if len(pks) > 0 {
|
||||
createSql += fmt.Sprintf(", PRIMARY KEY (%s)", strings.Join(pks, ","))
|
||||
}
|
||||
createSql += ")"
|
||||
tableCommentSql := ""
|
||||
if tableInfo.TableComment != "" {
|
||||
commentTmp := "comment on table %s is '%s'"
|
||||
tableCommentSql = fmt.Sprintf(commentTmp, tableInfo.TableName, replacer.Replace(tableInfo.TableComment))
|
||||
}
|
||||
|
||||
columnCommentSql := strings.Join(columnComments, ";")
|
||||
|
||||
sqls := make([]string, 0)
|
||||
|
||||
if createSql != "" {
|
||||
sqls = append(sqls, createSql)
|
||||
}
|
||||
if tableCommentSql != "" {
|
||||
sqls = append(sqls, tableCommentSql)
|
||||
}
|
||||
if columnCommentSql != "" {
|
||||
sqls = append(sqls, columnCommentSql)
|
||||
}
|
||||
|
||||
_, err := pd.dc.Exec(strings.Join(sqls, ";"))
|
||||
|
||||
return 1, err
|
||||
}
|
||||
|
||||
func (pd *PgsqlDialect) genColumnBasicSql(column dbi.Column) string {
|
||||
func (pd *PgsqlDialect) ToColumn(commonColumn *dbi.Column) {
|
||||
ctype := pgsqlColumnTypeMap[commonColumn.DataType]
|
||||
|
||||
if ctype == "" {
|
||||
commonColumn.DataType = "varchar"
|
||||
commonColumn.CharMaxLength = 2000
|
||||
} else {
|
||||
commonColumn.DataType = dbi.ColumnDataType(ctype)
|
||||
// 哪些字段可以指定长度
|
||||
if !collx.ArrayAnyMatches([]string{"char", "time", "bit", "num", "decimal"}, ctype) {
|
||||
commonColumn.CharMaxLength = 0
|
||||
commonColumn.NumPrecision = 0
|
||||
} else if strings.Contains(strings.ToLower(ctype), "char") {
|
||||
// 如果类型是文本,长度翻倍
|
||||
commonColumn.CharMaxLength = commonColumn.CharMaxLength * 2
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (pd *PgsqlDialect) CreateTable(commonColumns []dbi.Column, tableInfo dbi.Table, dropOldTable bool) (int, error) {
|
||||
meta := pd.dc.GetMetaData()
|
||||
colName := meta.QuoteIdentifier(column.ColumnName)
|
||||
|
||||
// 如果是自增类型,需要转换为serial
|
||||
if column.IsIdentity {
|
||||
if column.ColumnType == "int4" {
|
||||
column.ColumnType = "serial"
|
||||
} else if column.ColumnType == "int2" {
|
||||
column.ColumnType = "smallserial"
|
||||
} else if column.ColumnType == "int8" {
|
||||
column.ColumnType = "bigserial"
|
||||
} else {
|
||||
column.ColumnType = "bigserial"
|
||||
}
|
||||
|
||||
return fmt.Sprintf(" %s %s NOT NULL", colName, column.ColumnType)
|
||||
}
|
||||
|
||||
nullAble := ""
|
||||
if column.Nullable == "NO" {
|
||||
nullAble = " NOT NULL"
|
||||
// 如果字段不能为空,则设置默认值
|
||||
if column.ColumnDefault == "" {
|
||||
if collx.ArrayAnyMatches([]string{"char", "text", "lob"}, strings.ToLower(column.ColumnType)) {
|
||||
// 文本默认值为空字符串
|
||||
column.ColumnDefault = " "
|
||||
} else if collx.ArrayAnyMatches([]string{"int", "num"}, strings.ToLower(column.ColumnType)) {
|
||||
// 数字默认值为0
|
||||
column.ColumnDefault = "0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defVal := "" // 默认值需要判断引号,如函数是不需要引号的 // 为了防止跨源函数不支持 当默认值是函数时,不需要设置默认值
|
||||
if column.ColumnDefault != "" && !strings.Contains(column.ColumnDefault, "(") {
|
||||
// 哪些字段类型默认值需要加引号
|
||||
mark := false
|
||||
if collx.ArrayAnyMatches([]string{"char", "text", "date", "time", "lob"}, strings.ToLower(column.ColumnType)) {
|
||||
// 如果是文本类型,则默认值不能带括号
|
||||
if collx.ArrayAnyMatches([]string{"char", "text", "lob"}, strings.ToLower(column.ColumnType)) {
|
||||
column.ColumnDefault = ""
|
||||
}
|
||||
|
||||
// 当数据类型是日期时间,默认值是日期时间函数时,默认值不需要引号
|
||||
if collx.ArrayAnyMatches([]string{"date", "time"}, strings.ToLower(column.ColumnType)) &&
|
||||
collx.ArrayAnyMatches([]string{"DATE", "TIME"}, strings.ToUpper(column.ColumnDefault)) {
|
||||
mark = false
|
||||
} else {
|
||||
mark = true
|
||||
}
|
||||
}
|
||||
// 如果数据类型是日期时间,则写死默认值函数
|
||||
if collx.ArrayAnyMatches([]string{"date", "time"}, strings.ToLower(column.ColumnType)) {
|
||||
column.ColumnDefault = "CURRENT_TIMESTAMP"
|
||||
}
|
||||
|
||||
if column.ColumnDefault != "" {
|
||||
if mark {
|
||||
defVal = fmt.Sprintf(" DEFAULT '%s'", column.ColumnDefault)
|
||||
} else {
|
||||
defVal = fmt.Sprintf(" DEFAULT %s", column.ColumnDefault)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
columnSql := fmt.Sprintf(" %s %s %s %s ", colName, column.ColumnType, nullAble, defVal)
|
||||
return columnSql
|
||||
sqlArr := meta.GenerateTableDDL(commonColumns, tableInfo, dropOldTable)
|
||||
_, err := pd.dc.Exec(strings.Join(sqlArr, ";"))
|
||||
return len(sqlArr), err
|
||||
}
|
||||
|
||||
func (pd *PgsqlDialect) CreateIndex(tableInfo dbi.Table, indexs []dbi.Index) error {
|
||||
sqls := make([]string, 0)
|
||||
comments := make([]string, 0)
|
||||
for _, index := range indexs {
|
||||
// 通过字段、表名拼接索引名
|
||||
columnName := strings.ReplaceAll(index.ColumnName, "-", "")
|
||||
columnName = strings.ReplaceAll(columnName, "_", "")
|
||||
colName := strings.ReplaceAll(columnName, ",", "_")
|
||||
|
||||
keyType := "normal"
|
||||
unique := ""
|
||||
if index.IsUnique {
|
||||
keyType = "unique"
|
||||
unique = "unique"
|
||||
}
|
||||
indexName := fmt.Sprintf("%s_key_%s_%s", keyType, tableInfo.TableName, colName)
|
||||
|
||||
// 如果索引名存在,先删除索引
|
||||
sqls = append(sqls, fmt.Sprintf("drop index if exists %s.%s", pd.currentSchema(), indexName))
|
||||
|
||||
// 创建索引
|
||||
sqls = append(sqls, fmt.Sprintf("CREATE %s INDEX %s on %s.%s(%s)", unique, indexName, pd.currentSchema(), tableInfo.TableName, index.ColumnName))
|
||||
if index.IndexComment != "" {
|
||||
comments = append(comments, fmt.Sprintf("COMMENT ON INDEX %s.%s IS '%s'", pd.currentSchema(), indexName, index.IndexComment))
|
||||
}
|
||||
}
|
||||
_, err := pd.dc.Exec(strings.Join(sqls, ";"))
|
||||
// 添加注释
|
||||
if len(comments) > 0 {
|
||||
_, err = pd.dc.Exec(strings.Join(comments, ";"))
|
||||
}
|
||||
sqlArr := pd.dc.GetMetaData().GenerateIndexDDL(indexs, tableInfo)
|
||||
_, err := pd.dc.Exec(strings.Join(sqlArr, ";"))
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ type PostgresMeta struct {
|
||||
Param string
|
||||
}
|
||||
|
||||
func (md *PostgresMeta) GetSqlDb(d *dbi.DbInfo) (*sql.DB, error) {
|
||||
func (pm *PostgresMeta) GetSqlDb(d *dbi.DbInfo) (*sql.DB, error) {
|
||||
driverName := "postgres"
|
||||
// SSH Conect
|
||||
if d.SshTunnelMachineId > 0 {
|
||||
@@ -74,8 +74,8 @@ 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)
|
||||
if pm.Param != "" && !strings.Contains(dsn, "dbtype") {
|
||||
dsn = fmt.Sprintf("%s %s", dsn, pm.Param)
|
||||
}
|
||||
|
||||
return sql.Open(driverName, dsn)
|
||||
@@ -94,8 +94,8 @@ type PqSqlDialer struct {
|
||||
sshTunnelMachineId int
|
||||
}
|
||||
|
||||
func (d *PqSqlDialer) Open(name string) (driver.Conn, error) {
|
||||
return pq.DialOpen(d, name)
|
||||
func (pd *PqSqlDialer) Open(name string) (driver.Conn, error) {
|
||||
return pq.DialOpen(pd, name)
|
||||
}
|
||||
|
||||
func (pd *PqSqlDialer) Dial(network, address string) (net.Conn, error) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"mayfly-go/internal/db/dbm/dbi"
|
||||
"mayfly-go/pkg/errorx"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/utils/anyx"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"mayfly-go/pkg/utils/stringx"
|
||||
@@ -18,7 +19,6 @@ const (
|
||||
PGSQL_TABLE_INFO_KEY = "PGSQL_TABLE_INFO"
|
||||
PGSQL_INDEX_INFO_KEY = "PGSQL_INDEX_INFO"
|
||||
PGSQL_COLUMN_MA_KEY = "PGSQL_COLUMN_MA"
|
||||
PGSQL_TABLE_DDL_KEY = "PGSQL_TABLE_DDL_FUNC"
|
||||
)
|
||||
|
||||
type PgsqlMetaData struct {
|
||||
@@ -99,17 +99,23 @@ func (pd *PgsqlMetaData) GetColumns(tableNames ...string) ([]dbi.Column, error)
|
||||
|
||||
columns := make([]dbi.Column, 0)
|
||||
for _, re := range res {
|
||||
columns = append(columns, dbi.Column{
|
||||
column := dbi.Column{
|
||||
TableName: anyx.ConvString(re["tableName"]),
|
||||
ColumnName: anyx.ConvString(re["columnName"]),
|
||||
ColumnType: anyx.ConvString(re["columnType"]),
|
||||
DataType: dbi.ColumnDataType(anyx.ConvString(re["dataType"])),
|
||||
CharMaxLength: anyx.ConvInt(re["charMaxLength"]),
|
||||
ColumnComment: anyx.ConvString(re["columnComment"]),
|
||||
Nullable: anyx.ConvString(re["nullable"]),
|
||||
IsPrimaryKey: anyx.ConvInt(re["isPrimaryKey"]) == 1,
|
||||
IsIdentity: anyx.ConvInt(re["isIdentity"]) == 1,
|
||||
ColumnDefault: anyx.ConvString(re["columnDefault"]),
|
||||
NumPrecision: anyx.ConvInt(re["numPrecision"]),
|
||||
NumScale: anyx.ConvInt(re["numScale"]),
|
||||
})
|
||||
}
|
||||
|
||||
// 初始化列展示的长度,精度
|
||||
column.InitShowNum()
|
||||
columns = append(columns, column)
|
||||
}
|
||||
return columns, nil
|
||||
}
|
||||
@@ -168,20 +174,207 @@ func (pd *PgsqlMetaData) GetTableIndex(tableName string) ([]dbi.Index, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (pd *PgsqlMetaData) GenerateIndexDDL(indexs []dbi.Index, tableInfo dbi.Table) []string {
|
||||
creates := make([]string, 0)
|
||||
drops := make([]string, 0)
|
||||
comments := make([]string, 0)
|
||||
for _, index := range indexs {
|
||||
// 通过字段、表名拼接索引名
|
||||
columnName := strings.ReplaceAll(index.ColumnName, "-", "")
|
||||
columnName = strings.ReplaceAll(columnName, "_", "")
|
||||
colName := strings.ReplaceAll(columnName, ",", "_")
|
||||
|
||||
keyType := "normal"
|
||||
unique := ""
|
||||
if index.IsUnique {
|
||||
keyType = "unique"
|
||||
unique = "unique"
|
||||
}
|
||||
indexName := fmt.Sprintf("%s_key_%s_%s", keyType, tableInfo.TableName, colName)
|
||||
|
||||
// 如果索引名存在,先删除索引
|
||||
drops = append(drops, fmt.Sprintf("drop index if exists %s.%s", pd.dc.Info.CurrentSchema(), indexName))
|
||||
|
||||
// 创建索引
|
||||
creates = append(creates, fmt.Sprintf("CREATE %s INDEX %s on %s.%s(%s)", unique, indexName, pd.dc.Info.CurrentSchema(), tableInfo.TableName, index.ColumnName))
|
||||
if index.IndexComment != "" {
|
||||
comments = append(comments, fmt.Sprintf("COMMENT ON INDEX %s.%s IS '%s'", pd.dc.Info.CurrentSchema(), indexName, index.IndexComment))
|
||||
}
|
||||
}
|
||||
|
||||
sqlArr := make([]string, 0)
|
||||
|
||||
if len(drops) > 0 {
|
||||
sqlArr = append(sqlArr, drops...)
|
||||
}
|
||||
|
||||
if len(creates) > 0 {
|
||||
sqlArr = append(sqlArr, creates...)
|
||||
}
|
||||
if len(comments) > 0 {
|
||||
sqlArr = append(sqlArr, comments...)
|
||||
}
|
||||
return sqlArr
|
||||
}
|
||||
|
||||
func (pd *PgsqlMetaData) genColumnBasicSql(column dbi.Column) string {
|
||||
meta := pd.dc.GetMetaData()
|
||||
colName := meta.QuoteIdentifier(column.ColumnName)
|
||||
dataType := string(column.DataType)
|
||||
|
||||
// 如果是自增类型,需要转换为serial
|
||||
if column.IsIdentity {
|
||||
if dataType == "int4" {
|
||||
column.DataType = "serial"
|
||||
} else if dataType == "int2" {
|
||||
column.DataType = "smallserial"
|
||||
} else if dataType == "int8" {
|
||||
column.DataType = "bigserial"
|
||||
} else {
|
||||
column.DataType = "bigserial"
|
||||
}
|
||||
|
||||
return fmt.Sprintf(" %s %s NOT NULL", colName, column.ShowDataType)
|
||||
}
|
||||
|
||||
nullAble := ""
|
||||
if column.Nullable == "NO" {
|
||||
nullAble = " NOT NULL"
|
||||
// 如果字段不能为空,则设置默认值
|
||||
if column.ColumnDefault == "" {
|
||||
if collx.ArrayAnyMatches([]string{"char", "text", "lob"}, strings.ToLower(dataType)) {
|
||||
// 文本默认值为空字符串
|
||||
column.ColumnDefault = " "
|
||||
} else if collx.ArrayAnyMatches([]string{"int", "num"}, strings.ToLower(dataType)) {
|
||||
// 数字默认值为0
|
||||
column.ColumnDefault = "0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defVal := "" // 默认值需要判断引号,如函数是不需要引号的 // 为了防止跨源函数不支持 当默认值是函数时,不需要设置默认值
|
||||
if column.ColumnDefault != "" && !strings.Contains(column.ColumnDefault, "(") {
|
||||
// 哪些字段类型默认值需要加引号
|
||||
mark := false
|
||||
if collx.ArrayAnyMatches([]string{"char", "text", "date", "time", "lob"}, dataType) {
|
||||
// 如果是文本类型,则默认值不能带括号
|
||||
if collx.ArrayAnyMatches([]string{"char", "text", "lob"}, dataType) {
|
||||
column.ColumnDefault = ""
|
||||
}
|
||||
|
||||
// 当数据类型是日期时间,默认值是日期时间函数时,默认值不需要引号
|
||||
if collx.ArrayAnyMatches([]string{"date", "time"}, strings.ToLower(dataType)) &&
|
||||
collx.ArrayAnyMatches([]string{"DATE", "TIME"}, strings.ToUpper(column.ColumnDefault)) {
|
||||
mark = false
|
||||
} else {
|
||||
mark = true
|
||||
}
|
||||
}
|
||||
// 如果数据类型是日期时间,则写死默认值函数
|
||||
if collx.ArrayAnyMatches([]string{"date", "time"}, strings.ToLower(dataType)) {
|
||||
column.ColumnDefault = "CURRENT_TIMESTAMP"
|
||||
}
|
||||
|
||||
if column.ColumnDefault != "" {
|
||||
if mark {
|
||||
defVal = fmt.Sprintf(" DEFAULT '%s'", column.ColumnDefault)
|
||||
} else {
|
||||
defVal = fmt.Sprintf(" DEFAULT %s", column.ColumnDefault)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
columnSql := fmt.Sprintf(" %s %s %s %s ", colName, column.ShowDataType, nullAble, defVal)
|
||||
return columnSql
|
||||
}
|
||||
|
||||
func (pd *PgsqlMetaData) GenerateTableDDL(columns []dbi.Column, tableInfo dbi.Table, dropBeforeCreate bool) []string {
|
||||
|
||||
meta := pd.dc.GetMetaData()
|
||||
replacer := strings.NewReplacer(";", "", "'", "")
|
||||
|
||||
sqlArr := make([]string, 0)
|
||||
if dropBeforeCreate {
|
||||
sqlArr = append(sqlArr, fmt.Sprintf("DROP TABLE IF EXISTS %s", meta.QuoteIdentifier(tableInfo.TableName)))
|
||||
}
|
||||
// 组装建表语句
|
||||
createSql := fmt.Sprintf("CREATE TABLE %s (\n", meta.QuoteIdentifier(tableInfo.TableName))
|
||||
fields := make([]string, 0)
|
||||
pks := make([]string, 0)
|
||||
columnComments := make([]string, 0)
|
||||
commentTmp := "comment on column %s.%s is '%s'"
|
||||
|
||||
for _, column := range columns {
|
||||
if column.IsPrimaryKey {
|
||||
pks = append(pks, meta.QuoteIdentifier(column.ColumnName))
|
||||
}
|
||||
|
||||
fields = append(fields, pd.genColumnBasicSql(column))
|
||||
|
||||
// 防止注释内含有特殊字符串导致sql出错
|
||||
if column.ColumnComment != "" {
|
||||
comment := replacer.Replace(column.ColumnComment)
|
||||
columnComments = append(columnComments, fmt.Sprintf(commentTmp, column.TableName, column.ColumnName, comment))
|
||||
}
|
||||
}
|
||||
|
||||
createSql += strings.Join(fields, ",\n")
|
||||
if len(pks) > 0 {
|
||||
createSql += fmt.Sprintf(", \nPRIMARY KEY (%s)", strings.Join(pks, ","))
|
||||
}
|
||||
createSql += ")"
|
||||
|
||||
tableCommentSql := ""
|
||||
if tableInfo.TableComment != "" {
|
||||
commentTmp := "comment on table %s is '%s'"
|
||||
tableCommentSql = fmt.Sprintf(commentTmp, tableInfo.TableName, replacer.Replace(tableInfo.TableComment))
|
||||
}
|
||||
|
||||
// create
|
||||
sqlArr = append(sqlArr, createSql)
|
||||
|
||||
// table comment
|
||||
if tableCommentSql != "" {
|
||||
sqlArr = append(sqlArr, tableCommentSql)
|
||||
}
|
||||
// column comment
|
||||
if len(columnComments) > 0 {
|
||||
sqlArr = append(sqlArr, columnComments...)
|
||||
}
|
||||
|
||||
return sqlArr
|
||||
}
|
||||
|
||||
// 获取建表ddl
|
||||
func (pd *PgsqlMetaData) GetTableDDL(tableName string) (string, error) {
|
||||
_, err := pd.dc.Exec(dbi.GetLocalSql(PGSQL_META_FILE, PGSQL_TABLE_DDL_KEY))
|
||||
if err != nil {
|
||||
|
||||
// 1.获取表信息
|
||||
tbs, err := pd.GetTables(tableName)
|
||||
tableInfo := &dbi.Table{}
|
||||
if err != nil && len(tbs) > 0 {
|
||||
|
||||
logx.Errorf("获取表信息失败, %s", tableName)
|
||||
return "", err
|
||||
}
|
||||
tableInfo.TableName = tbs[0].TableName
|
||||
tableInfo.TableComment = tbs[0].TableComment
|
||||
|
||||
ddlSql := fmt.Sprintf("select showcreatetable('%s','%s') as sql", pd.dc.Info.CurrentSchema(), tableName)
|
||||
_, res, err := pd.dc.Query(ddlSql)
|
||||
// 2.获取列信息
|
||||
columns, err := pd.GetColumns(tableName)
|
||||
if err != nil {
|
||||
logx.Errorf("获取列信息失败, %s", tableName)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return res[0]["sql"].(string), nil
|
||||
tableDDLArr := pd.GenerateTableDDL(columns, *tableInfo, false)
|
||||
// 3.获取索引信息
|
||||
indexs, err := pd.GetTableIndex(tableName)
|
||||
if err != nil {
|
||||
logx.Errorf("获取索引信息失败, %s", tableName)
|
||||
return "", err
|
||||
}
|
||||
// 组装返回
|
||||
tableDDLArr = append(tableDDLArr, pd.GenerateIndexDDL(indexs, *tableInfo)...)
|
||||
return strings.Join(tableDDLArr, ";\n"), nil
|
||||
}
|
||||
|
||||
// 获取pgsql当前连接的库可访问的schemaNames
|
||||
@@ -247,7 +440,7 @@ var (
|
||||
"nchar": dbi.CommonTypeChar,
|
||||
"varchar": dbi.CommonTypeVarchar,
|
||||
"text": dbi.CommonTypeText,
|
||||
"bytea": dbi.CommonTypeBinary,
|
||||
"bytea": dbi.CommonTypeText,
|
||||
"date": dbi.CommonTypeDate,
|
||||
"time": dbi.CommonTypeTime,
|
||||
"timestamp": dbi.CommonTypeTimestamp,
|
||||
@@ -260,10 +453,10 @@ var (
|
||||
dbi.CommonTypeBlob: "text",
|
||||
dbi.CommonTypeLongblob: "text",
|
||||
dbi.CommonTypeLongtext: "text",
|
||||
dbi.CommonTypeBinary: "bytea",
|
||||
dbi.CommonTypeBinary: "text",
|
||||
dbi.CommonTypeMediumblob: "text",
|
||||
dbi.CommonTypeMediumtext: "text",
|
||||
dbi.CommonTypeVarbinary: "bytea",
|
||||
dbi.CommonTypeVarbinary: "text",
|
||||
dbi.CommonTypeInt: "int4",
|
||||
dbi.CommonTypeSmallint: "int2",
|
||||
dbi.CommonTypeTinyint: "int2",
|
||||
|
||||
@@ -4,8 +4,6 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"mayfly-go/internal/db/dbm/dbi"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -88,127 +86,46 @@ func (sd *SqliteDialect) CopyTable(copy *dbi.DbCopyTable) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// func (sd *SqliteDialect) TransColumns(columns []dbi.Column) []dbi.Column {
|
||||
// var commonColumns []dbi.Column
|
||||
// for _, column := range columns {
|
||||
// // 取出当前数据库类型
|
||||
// arr := strings.Split(column.ColumnType, "(")
|
||||
// ctype := arr[0]
|
||||
// // 翻译为通用数据库类型
|
||||
// t1 := commonColumnTypeMap[ctype]
|
||||
// if t1 == "" {
|
||||
// ctype = "varchar(2000)"
|
||||
// } else {
|
||||
// // 回写到列信息
|
||||
// if len(arr) > 1 {
|
||||
// ctype = t1 + "(" + arr[1]
|
||||
// } else {
|
||||
// ctype = t1
|
||||
// }
|
||||
// }
|
||||
// column.ColumnType = ctype
|
||||
// commonColumns = append(commonColumns, column)
|
||||
// }
|
||||
// return commonColumns
|
||||
// }
|
||||
func (sd *SqliteDialect) ToCommonColumn(dialectColumn *dbi.Column) {
|
||||
// 翻译为通用数据库类型
|
||||
dataType := dialectColumn.DataType
|
||||
t1 := commonColumnTypeMap[string(dataType)]
|
||||
if t1 == "" {
|
||||
dialectColumn.DataType = dbi.CommonTypeVarchar
|
||||
dialectColumn.CharMaxLength = 2000
|
||||
} else {
|
||||
dialectColumn.DataType = t1
|
||||
}
|
||||
}
|
||||
|
||||
func (sd *SqliteDialect) CreateTable(commonColumns []dbi.Column, tableInfo dbi.Table, dropOldTable bool) (int, error) {
|
||||
tbName := sd.dc.GetMetaData().QuoteIdentifier(tableInfo.TableName)
|
||||
if dropOldTable {
|
||||
_, err := sd.dc.Exec(fmt.Sprintf("DROP TABLE IF EXISTS %s", tbName))
|
||||
func (sd *SqliteDialect) ToColumn(commonColumn *dbi.Column) {
|
||||
ctype := sqliteColumnTypeMap[commonColumn.DataType]
|
||||
if ctype == "" {
|
||||
commonColumn.DataType = "nvarchar"
|
||||
commonColumn.CharMaxLength = 2000
|
||||
}
|
||||
}
|
||||
|
||||
func (sd *SqliteDialect) CreateTable(columns []dbi.Column, tableInfo dbi.Table, dropOldTable bool) (int, error) {
|
||||
sqlArr := sd.dc.GetMetaData().GenerateTableDDL(columns, tableInfo, dropOldTable)
|
||||
for _, sqlStr := range sqlArr {
|
||||
_, err := sd.dc.Exec(sqlStr)
|
||||
if err != nil {
|
||||
logx.Error("删除表失败", err)
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
// 组装建表语句
|
||||
createSql := fmt.Sprintf("CREATE TABLE %s (\n", tbName)
|
||||
fields := make([]string, 0)
|
||||
// 把通用类型转换为达梦类型
|
||||
for _, column := range commonColumns {
|
||||
// 取出当前数据库类型
|
||||
arr := strings.Split(column.ColumnType, "(")
|
||||
ctype := arr[0]
|
||||
// 翻译为通用数据库类型
|
||||
t1 := sqliteColumnTypeMap[dbi.ColumnDataType(ctype)]
|
||||
if t1 == "" {
|
||||
ctype = "nvarchar(2000)"
|
||||
} else {
|
||||
// 回写到列信息
|
||||
if len(arr) > 1 {
|
||||
ctype = t1 + "(" + arr[1]
|
||||
}
|
||||
}
|
||||
column.ColumnType = ctype
|
||||
fields = append(fields, sd.genColumnBasicSql(column))
|
||||
}
|
||||
createSql += strings.Join(fields, ",")
|
||||
createSql += fmt.Sprintf(") ")
|
||||
_, err := sd.dc.Exec(createSql)
|
||||
|
||||
return 1, err
|
||||
return len(sqlArr), nil
|
||||
}
|
||||
|
||||
func (sd *SqliteDialect) CreateIndex(tableInfo dbi.Table, indexs []dbi.Index) error {
|
||||
sqls := make([]string, 0)
|
||||
for _, index := range indexs {
|
||||
// 通过字段、表名拼接索引名
|
||||
columnName := strings.ReplaceAll(index.ColumnName, "-", "")
|
||||
columnName = strings.ReplaceAll(columnName, "_", "")
|
||||
colName := strings.ReplaceAll(columnName, ",", "_")
|
||||
|
||||
keyType := "normal"
|
||||
unique := ""
|
||||
if index.IsUnique {
|
||||
keyType = "unique"
|
||||
unique = "unique"
|
||||
}
|
||||
indexName := fmt.Sprintf("%s_key_%s_%s", keyType, tableInfo.TableName, colName)
|
||||
sqlTmp := "CREATE %s INDEX %s ON \"%s\" (%s) "
|
||||
sqls = append(sqls, fmt.Sprintf(sqlTmp, unique, indexName, tableInfo.TableName, index.ColumnName))
|
||||
}
|
||||
_, err := sd.dc.Exec(strings.Join(sqls, ";"))
|
||||
return err
|
||||
}
|
||||
|
||||
func (sd *SqliteDialect) genColumnBasicSql(column dbi.Column) string {
|
||||
|
||||
incr := ""
|
||||
if column.IsIdentity {
|
||||
incr = " AUTOINCREMENT"
|
||||
}
|
||||
|
||||
nullAble := ""
|
||||
if column.Nullable == "NO" {
|
||||
nullAble = " NOT NULL"
|
||||
}
|
||||
|
||||
// 如果是主键,则直接返回,不判断默认值
|
||||
if column.IsPrimaryKey {
|
||||
return fmt.Sprintf(" %s integer PRIMARY KEY %s %s", column.ColumnName, incr, nullAble)
|
||||
}
|
||||
|
||||
defVal := "" // 默认值需要判断引号,如函数是不需要引号的 // 为了防止跨源函数不支持 当默认值是函数时,不需要设置默认值
|
||||
if column.ColumnDefault != "" && !strings.Contains(column.ColumnDefault, "(") {
|
||||
// 哪些字段类型默认值需要加引号
|
||||
mark := false
|
||||
if collx.ArrayAnyMatches([]string{"char", "text", "date", "time", "lob"}, strings.ToLower(column.ColumnType)) {
|
||||
// 当数据类型是日期时间,默认值是日期时间函数时,默认值不需要引号
|
||||
if collx.ArrayAnyMatches([]string{"date", "time"}, strings.ToLower(column.ColumnType)) &&
|
||||
collx.ArrayAnyMatches([]string{"DATE", "TIME"}, strings.ToUpper(column.ColumnDefault)) {
|
||||
mark = false
|
||||
} else {
|
||||
mark = true
|
||||
}
|
||||
}
|
||||
if mark {
|
||||
defVal = fmt.Sprintf(" DEFAULT '%s'", column.ColumnDefault)
|
||||
} else {
|
||||
defVal = fmt.Sprintf(" DEFAULT %s", column.ColumnDefault)
|
||||
sqlArr := sd.dc.GetMetaData().GenerateIndexDDL(indexs, tableInfo)
|
||||
for _, sqlStr := range sqlArr {
|
||||
_, err := sd.dc.Exec(sqlStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf(" %s %s %s %s", sd.dc.GetMetaData().QuoteIdentifier(column.ColumnName), column.ColumnType, nullAble, defVal)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sd *SqliteDialect) UpdateSequence(tableName string, columns []dbi.Column) {
|
||||
|
||||
@@ -82,6 +82,18 @@ func (sd *SqliteMetaData) GetTables(tableNames ...string) ([]dbi.Table, error) {
|
||||
return tables, nil
|
||||
}
|
||||
|
||||
// GetDataTypes 正则提取字段类型中的关键字,
|
||||
// 如 decimal(10,2) 提取decimal, 10 ,2
|
||||
// 如:text 提取text,null,null
|
||||
// 如:varchar(100) 提取varchar, 100
|
||||
func (sd *SqliteMetaData) getDataTypes(dataType string) (string, string, string) {
|
||||
matches := dataTypeRegexp.FindStringSubmatch(dataType)
|
||||
if len(matches) == 0 {
|
||||
return "", "", ""
|
||||
}
|
||||
return matches[1], matches[2], matches[3]
|
||||
}
|
||||
|
||||
// 获取列元信息, 如列名等
|
||||
func (sd *SqliteMetaData) GetColumns(tableNames ...string) ([]dbi.Column, error) {
|
||||
|
||||
@@ -104,17 +116,33 @@ func (sd *SqliteMetaData) GetColumns(tableNames ...string) ([]dbi.Column, error)
|
||||
if strings.Contains(defaultValue, "'") {
|
||||
defaultValue = strings.ReplaceAll(defaultValue, "'", "")
|
||||
}
|
||||
columns = append(columns, dbi.Column{
|
||||
|
||||
column := dbi.Column{
|
||||
TableName: tableName,
|
||||
ColumnName: anyx.ConvString(re["name"]),
|
||||
ColumnType: strings.ToLower(anyx.ConvString(re["type"])),
|
||||
ColumnComment: "",
|
||||
Nullable: nullable,
|
||||
IsPrimaryKey: anyx.ConvInt(re["pk"]) == 1,
|
||||
IsIdentity: anyx.ConvInt(re["pk"]) == 1,
|
||||
ColumnDefault: defaultValue,
|
||||
NumScale: 0,
|
||||
})
|
||||
}
|
||||
|
||||
// 切割类型和长度,如果长度内有逗号,则说明是decimal类型
|
||||
columnType := anyx.ConvString(re["type"])
|
||||
dataType, length, scale := sd.getDataTypes(columnType)
|
||||
if scale != "0" && scale != "" {
|
||||
column.NumPrecision = anyx.ConvInt(length)
|
||||
column.NumScale = anyx.ConvInt(scale)
|
||||
column.CharMaxLength = 0
|
||||
} else {
|
||||
column.CharMaxLength = anyx.ConvInt(length)
|
||||
}
|
||||
column.DataType = dbi.ColumnDataType(dataType)
|
||||
|
||||
// 初始化列展示的长度,精度
|
||||
column.InitShowNum()
|
||||
columns = append(columns, column)
|
||||
}
|
||||
}
|
||||
return columns, nil
|
||||
@@ -175,6 +203,91 @@ func (sd *SqliteMetaData) GetTableIndex(tableName string) ([]dbi.Index, error) {
|
||||
return indexs, nil
|
||||
}
|
||||
|
||||
// 获取建索引ddl
|
||||
func (sd *SqliteMetaData) GenerateIndexDDL(indexs []dbi.Index, tableInfo dbi.Table) []string {
|
||||
sqls := make([]string, 0)
|
||||
for _, index := range indexs {
|
||||
// 通过字段、表名拼接索引名
|
||||
columnName := strings.ReplaceAll(index.ColumnName, "-", "")
|
||||
columnName = strings.ReplaceAll(columnName, "_", "")
|
||||
colName := strings.ReplaceAll(columnName, ",", "_")
|
||||
|
||||
keyType := "normal"
|
||||
unique := ""
|
||||
if index.IsUnique {
|
||||
keyType = "unique"
|
||||
unique = "unique"
|
||||
}
|
||||
indexName := fmt.Sprintf("%s_key_%s_%s", keyType, tableInfo.TableName, colName)
|
||||
sqlTmp := "CREATE %s INDEX %s ON \"%s\" (%s) "
|
||||
sqls = append(sqls, fmt.Sprintf(sqlTmp, unique, indexName, tableInfo.TableName, index.ColumnName))
|
||||
}
|
||||
return sqls
|
||||
}
|
||||
|
||||
func (sd *SqliteMetaData) genColumnBasicSql(column dbi.Column) string {
|
||||
|
||||
incr := ""
|
||||
if column.IsIdentity {
|
||||
incr = " AUTOINCREMENT"
|
||||
}
|
||||
|
||||
nullAble := ""
|
||||
if column.Nullable == "NO" {
|
||||
nullAble = " NOT NULL"
|
||||
}
|
||||
|
||||
// 如果是主键,则直接返回,不判断默认值
|
||||
if column.IsPrimaryKey {
|
||||
return fmt.Sprintf(" %s integer PRIMARY KEY %s %s", column.ColumnName, incr, nullAble)
|
||||
}
|
||||
|
||||
defVal := "" // 默认值需要判断引号,如函数是不需要引号的 // 为了防止跨源函数不支持 当默认值是函数时,不需要设置默认值
|
||||
if column.ColumnDefault != "" && !strings.Contains(column.ColumnDefault, "(") {
|
||||
// 哪些字段类型默认值需要加引号
|
||||
mark := false
|
||||
if collx.ArrayAnyMatches([]string{"char", "text", "date", "time", "lob"}, strings.ToLower(string(column.DataType))) {
|
||||
// 当数据类型是日期时间,默认值是日期时间函数时,默认值不需要引号
|
||||
if collx.ArrayAnyMatches([]string{"date", "time"}, strings.ToLower(string(column.DataType))) &&
|
||||
collx.ArrayAnyMatches([]string{"DATE", "TIME"}, strings.ToUpper(column.ColumnDefault)) {
|
||||
mark = false
|
||||
} else {
|
||||
mark = true
|
||||
}
|
||||
}
|
||||
if mark {
|
||||
defVal = fmt.Sprintf(" DEFAULT '%s'", column.ColumnDefault)
|
||||
} else {
|
||||
defVal = fmt.Sprintf(" DEFAULT %s", column.ColumnDefault)
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf(" %s %s %s %s", sd.dc.GetMetaData().QuoteIdentifier(column.ColumnName), column.ShowDataType, nullAble, defVal)
|
||||
}
|
||||
|
||||
// 获取建表ddl
|
||||
func (sd *SqliteMetaData) GenerateTableDDL(columns []dbi.Column, tableInfo dbi.Table, dropBeforeCreate bool) []string {
|
||||
sqlArr := make([]string, 0)
|
||||
tbName := sd.dc.GetMetaData().QuoteIdentifier(tableInfo.TableName)
|
||||
if dropBeforeCreate {
|
||||
sqlArr = append(sqlArr, fmt.Sprintf("DROP TABLE IF EXISTS %s", tbName))
|
||||
}
|
||||
// 组装建表语句
|
||||
createSql := fmt.Sprintf("CREATE TABLE %s (\n", tbName)
|
||||
fields := make([]string, 0)
|
||||
|
||||
// 把通用类型转换为达梦类型
|
||||
for _, column := range columns {
|
||||
fields = append(fields, sd.genColumnBasicSql(column))
|
||||
}
|
||||
createSql += strings.Join(fields, ",")
|
||||
createSql += fmt.Sprintf(") ")
|
||||
|
||||
sqlArr = append(sqlArr, createSql)
|
||||
|
||||
return sqlArr
|
||||
}
|
||||
|
||||
// 获取建表ddl
|
||||
func (sd *SqliteMetaData) GetTableDDL(tableName string) (string, error) {
|
||||
_, res, err := sd.dc.Query("select sql from sqlite_master WHERE tbl_name=? order by type desc", tableName)
|
||||
@@ -203,6 +316,8 @@ var (
|
||||
// 日期时间类型
|
||||
datetimeRegexp = regexp.MustCompile(`(?i)datetime`)
|
||||
|
||||
dataTypeRegexp = regexp.MustCompile(`(\w+)\((\d*),?(\d*)\)`)
|
||||
|
||||
converter = new(DataConverter)
|
||||
|
||||
// sqlite数据类型 映射 公共数据类型
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user