From f9d322e4537ef38ca08015b887c743b9068aed1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Mon, 16 May 2022 12:38:32 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=95=E5=85=A5sql2go=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 5 +- go.sum | 9 +++- sql2go/dao_tpl.tpl | 59 ++++++++++++++++++++++++ sql2go/define.go | 51 ++++++++++++++++++++ sql2go/generate_dao.go | 59 ++++++++++++++++++++++++ sql2go/generate_dao_test.go | 23 ++++++++++ sql2go/go_test.go | 70 ++++++++++++++++++++++++++++ sql2go/parser.go | 92 +++++++++++++++++++++++++++++++++++++ sql2go/parser_test.go | 18 ++++++++ 9 files changed, 384 insertions(+), 2 deletions(-) create mode 100644 sql2go/dao_tpl.tpl create mode 100644 sql2go/define.go create mode 100644 sql2go/generate_dao.go create mode 100644 sql2go/generate_dao_test.go create mode 100644 sql2go/go_test.go create mode 100644 sql2go/parser.go create mode 100644 sql2go/parser_test.go diff --git a/go.mod b/go.mod index 078eded..287c55e 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,10 @@ go 1.17 require ( git.zhangdeman.cn/zhangdeman/logger v0.0.0-20220514052229-cf395d3dc4c3 + git.zhangdeman.cn/zhangdeman/util v0.0.0-20220514082633-1be4d9eab11f github.com/gin-gonic/gin v1.7.7 github.com/pkg/errors v0.9.1 + github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 go.uber.org/zap v1.21.0 gorm.io/driver/mysql v1.3.3 gorm.io/gorm v1.23.5 @@ -27,10 +29,11 @@ require ( github.com/mattn/go-isatty v0.0.12 // indirect github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/ugorji/go/codec v1.1.7 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect - gopkg.in/yaml.v2 v2.2.8 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index c21e48e..82ba6d4 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ git.zhangdeman.cn/zhangdeman/logger v0.0.0-20220514052229-cf395d3dc4c3 h1:T41tE9F2Gy8eKVSKtTPhf7RaRT12qHEXTfx4IJuoIS4= git.zhangdeman.cn/zhangdeman/logger v0.0.0-20220514052229-cf395d3dc4c3/go.mod h1:0A5BV9pE31nuFE60TLbP7BIhhV/fcWoi+fHrcV2clJw= +git.zhangdeman.cn/zhangdeman/util v0.0.0-20220514082633-1be4d9eab11f h1:1amgaCqOPn7gvcUEEX614cO8lkIz+G8W/YtGXLIdW1w= +git.zhangdeman.cn/zhangdeman/util v0.0.0-20220514082633-1be4d9eab11f/go.mod h1:YI/XeTmrr9+8dxa4ThPkmNcEE8WHG5pZkKujpSWwIxM= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -54,6 +56,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -63,6 +67,8 @@ github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 h1:zzrxE1FKn5ryBNl9eKOeqQ58Y/Qpo3Q9QNxKHX5uzzQ= +github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2/go.mod h1:hzfGeIUDq/j97IG+FhNqkowIyEcD88LrW6fyU3K3WqY= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -106,8 +112,9 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/sql2go/dao_tpl.tpl b/sql2go/dao_tpl.tpl new file mode 100644 index 0000000..be7f268 --- /dev/null +++ b/sql2go/dao_tpl.tpl @@ -0,0 +1,59 @@ +// Package {PACKAGE} ... +// +// Description : {PACKAGE} ... +package {PACKAGE} + +import ( + "gorm.io/gorm" + "errors" +) + +// {DATA_STRUCT_NAME} 数据库表的数据结构 +{DATA_STRUCT} + +// New{DATA_STRUCT_DAO} 获取DAO实例 +func New{DATA_STRUCT_DAO}() *{DATA_STRUCT_DAO} { + return &{DATA_STRUCT_DAO}{ + table : "{DB_TABLE_NAME}", + } +} + +// {DATA_STRUCT_DAO} sql2go tool generate +type {DATA_STRUCT_DAO} struct { + table string +} + +// GetDetailBy{PRIMARY_KEY} 根据主键ID获取详情 +func ({DAO_RECEIVER} *{DATA_STRUCT_DAO}) GetDetailBy{PRIMARY_KEY}(dbInstance *gorm.DB, {PRIMARY_KEY} {PRIMARY_KEY_TYPE}) (*{DATA_STRUCT_NAME}, error) { + var ( + err error + detail {DATA_STRUCT_NAME} + ) + if err = dbInstance.Table({DAO_RECEIVER}.table).Where("{PRIMARY_KEY_FIELD} = ?", {PRIMARY_KEY}).Limit(1).First(&detail).Error; nil != err { + return nil, err + } + return &detail, nil +} + +// GetList 获取数据列表 +func ({DAO_RECEIVER} *{DATA_STRUCT_DAO}) GetList(dbInstance *gorm.DB, condition map[string]interface{}, limit int, offset int) ([]{DATA_STRUCT_NAME}, error) { + if nil == condition { + condition = make(map[string]interface{}) + } + var ( + err error + list []{DATA_STRUCT_NAME} + ) + if err = dbInstance.Table({DAO_RECEIVER}.table).Where(condition).Limit(limit).Offset(offset).Find(&list).Error; nil != err { + return make([]{DATA_STRUCT_NAME}, 0), err + } + return list, nil +} + +// Create 创建数据 +func ({DAO_RECEIVER} *{DATA_STRUCT_DAO}) Create(dbInstance *gorm.DB, data *{DATA_STRUCT_NAME}) error { + if nil == data { + return errors.New("data is nil") + } + return dbInstance.Table({DAO_RECEIVER}.table).Create(data).Error +} diff --git a/sql2go/define.go b/sql2go/define.go new file mode 100644 index 0000000..49ff0aa --- /dev/null +++ b/sql2go/define.go @@ -0,0 +1,51 @@ +// Package sql2go... +// +// Description : sql2go... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2021-10-25 4:50 下午 +package sql2go + +// sqlTypeMap mysql数据类型 => go 数据类型映射 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 4:50 下午 2021/10/25 +var sqlTypeMap = map[string]string{ + "int": "int", + "integer": "int", + "tinyint": "int8", + "smallint": "int16", + "mediumint": "int32", + "bigint": "int64", + "int unsigned": "uint", + "integer unsigned": "uint", + "tinyint unsigned": "uint8", + "smallint unsigned": "uint16", + "mediumint unsigned": "uint32", + "bigint unsigned": "uint64", + "bit": "byte", + "bool": "bool", + "enum": "string", + "set": "string", + "varchar": "string", + "char": "string", + "tinytext": "string", + "mediumtext": "string", + "text": "string", + "longtext": "string", + "blob": "string", + "tinyblob": "string", + "mediumblob": "string", + "longblob": "string", + "date": "time.Time", + "datetime": "time.Time", + "timestamp": "time.Time", + "time": "time.Time", + "float": "float64", + "double": "float64", + "decimal": "float64", + "binary": "string", + "varbinary": "string", +} diff --git a/sql2go/generate_dao.go b/sql2go/generate_dao.go new file mode 100644 index 0000000..0e14921 --- /dev/null +++ b/sql2go/generate_dao.go @@ -0,0 +1,59 @@ +// Package sql2go... +// +// Description : sql2go... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2021-11-17 10:14 上午 +package sql2go + +import ( + "strings" + + "git.zhangdeman.cn/zhangdeman/util" +) + +// GenerateDao 根据sql自动生成dao +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 10:15 上午 2021/11/17 +func GenerateDao(sql string, packageName string) (string, error) { + if len(packageName) == 0 { + packageName = "dao" + } + dataStruct, basic, err := ParseCreateTableSql(sql) + if nil != err { + return "", err + } + // 读入模板 + tplByte, _ := util.File.ReadFileContent("dao_tpl.tpl") + tpl := string(tplByte) + replaceTable := map[string]string{ + "{PACKAGE}": packageName, + "{DATA_STRUCT_DAO}": basic.ModelStruct + "Dao", + "{DATA_STRUCT_NAME}": basic.ModelStruct, + "{DATA_STRUCT}": dataStruct, + "{DAO_RECEIVER}": getDaoReceiver(basic.TableName), + "{DB_TABLE_NAME}": basic.TableName, + "{PRIMARY_KEY}": "ID", + "{PRIMARY_KEY_TYPE}": basic.PrimaryFieldType, + } + + for oldVal, newVal := range replaceTable { + tpl = strings.ReplaceAll(tpl, oldVal, newVal) + } + return tpl, nil +} + +func getDaoReceiver(tableName string) string { + nameArr := strings.Split(tableName, "_") + result := "" + for _, item := range nameArr { + if len(item) > 0 { + result += string([]byte(item)[0]) + } + } + result += "d" + return result +} diff --git a/sql2go/generate_dao_test.go b/sql2go/generate_dao_test.go new file mode 100644 index 0000000..ae82869 --- /dev/null +++ b/sql2go/generate_dao_test.go @@ -0,0 +1,23 @@ +// Package sql2go... +// +// Description : sql2go... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2021-11-17 11:46 上午 +package sql2go + +import ( + "fmt" + "testing" +) + +// TestGenerateDao ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 12:05 下午 2021/11/17 +func TestGenerateDao(t *testing.T) { + sql := "CREATE TABLE `app` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',\n `code` varchar(128) NOT NULL DEFAULT '' COMMENT '分配的app_code',\n `secret` varchar(64) NOT NULL DEFAULT '' COMMENT '分配的私钥',\n `status` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '当前状态 o - 初始化 1- 使用中 2 - 禁用 3 - 删除',\n `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述信息',\n `apply_user_name` varchar(64) NOT NULL DEFAULT '' COMMENT '申请人姓名',\n `apply_user_contact` varchar(128) NOT NULL DEFAULT '' COMMENT '申请人联系方式',\n `create_user_id` varchar(128) NOT NULL DEFAULT '' COMMENT '创建人ID',\n `modify_user_id` varchar(128) NOT NULL DEFAULT '' COMMENT '修改人ID',\n PRIMARY KEY (`id`),\n UNIQUE KEY `uniq_code` (`code`)\n) ENGINE=InnoDB AUTO_INCREMENT=100001 DEFAULT CHARSET=utf8mb4 COMMENT='APP信息表'" + fmt.Println(GenerateDao(sql, "sql2go")) +} diff --git a/sql2go/go_test.go b/sql2go/go_test.go new file mode 100644 index 0000000..cd06500 --- /dev/null +++ b/sql2go/go_test.go @@ -0,0 +1,70 @@ +// Package dao ... +// +// Description : dao ... +package sql2go + +import ( + "errors" + + "gorm.io/gorm" +) + +// App 数据库表的数据结构 +type App struct { + ID int64 `json:"id" gorm:"column:id;default:;NOT NULL"` // id 主键ID + Code string `json:"code" gorm:"column:code;default:;NOT NULL"` // code 分配的app_code + Secret string `json:"secret" gorm:"column:secret;default:;NOT NULL"` // secret 分配的私钥 + Status int `json:"status" gorm:"column:status;default:0;NOT NULL"` // status 当前状态 o - 初始化 1- 使用中 2 - 禁用 3 - 删除 + Description string `json:"description" gorm:"column:description;default:;NOT NULL"` // description 描述信息 + ApplyUserName string `json:"apply_user_name" gorm:"column:apply_user_name;default:;NOT NULL"` // apply_user_name 申请人姓名 + ApplyUserContact string `json:"apply_user_contact" gorm:"column:apply_user_contact;default:;NOT NULL"` // apply_user_contact 申请人联系方式 + CreateUserID string `json:"create_user_id" gorm:"column:create_user_id;default:;NOT NULL"` // create_user_id 创建人ID + ModifyUserID string `json:"modify_user_id" gorm:"column:modify_user_id;default:;NOT NULL"` // modify_user_id 修改人ID +} + +// NewAppDao 获取DAO实例 +func NewAppDao() *AppDao { + return &AppDao{ + table: "app", + } +} + +// AppDao sql2go tool generate +type AppDao struct { + table string +} + +// GetDetailByID 根据主键ID获取详情 +func (ad *AppDao) GetDetailByID(dbInstance *gorm.DB, ID int64) (*App, error) { + var ( + err error + detail App + ) + if err = dbInstance.Table(ad.table).Where("{PRIMARY_KEY_FIELD} = ?", ID).Limit(1).First(&detail).Error; nil != err { + return nil, err + } + return &detail, nil +} + +// GetList 获取数据列表 +func (ad *AppDao) GetList(dbInstance *gorm.DB, condition map[string]interface{}, limit int, offset int) ([]App, error) { + if nil == condition { + condition = make(map[string]interface{}) + } + var ( + err error + list []App + ) + if err = dbInstance.Table(ad.table).Where(condition).Limit(limit).Offset(offset).Find(&list).Error; nil != err { + return make([]App, 0), err + } + return list, nil +} + +// Create 创建数据 +func (ad *AppDao) Create(dbInstance *gorm.DB, data *App) error { + if nil == data { + return errors.New("data is nil") + } + return dbInstance.Table(ad.table).Create(data).Error +} diff --git a/sql2go/parser.go b/sql2go/parser.go new file mode 100644 index 0000000..cb98b54 --- /dev/null +++ b/sql2go/parser.go @@ -0,0 +1,92 @@ +// Package sql2go... +// +// Description : sql2go... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2021-10-25 4:49 下午 +package sql2go + +import ( + "errors" + "strings" + + "git.zhangdeman.cn/zhangdeman/util" + + "github.com/xwb1989/sqlparser" +) + +const ( + // CreateSQLColumnTPL 每个字段的模版 + CreateSQLColumnTPL = "{FIELD} {TYPE} `json:\"{JSON_TAG}\" gorm:\"column:{COLUMN};default:{DEFAULT_VALUE};{NOT_NULL}\"` // {COMMENT}" +) + +// BasicTableInfo ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 11:47 上午 2021/11/17 +type BasicTableInfo struct { + TableName string + ModelStruct string + PrimaryField string + PrimaryFieldType string +} + +// ParseCreateTableSql 解析建表sql +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 4:49 下午 2021/10/25 +func ParseCreateTableSql(sql string) (string, *BasicTableInfo, error) { + var ( + stmt sqlparser.Statement + err error + basic *BasicTableInfo + ) + basic = &BasicTableInfo{ + TableName: "", + ModelStruct: "", + PrimaryField: "ID", + PrimaryFieldType: "", + } + sql = strings.ReplaceAll(strings.ReplaceAll(sql, "CURRENT_TIMESTAMP()", "CURRENT_TIMESTAMP"), "current_timestamp()", "CURRENT_TIMESTAMP") + if stmt, err = sqlparser.ParseStrictDDL(sql); nil != err { + return "", nil, err + } + + r, ok := stmt.(*sqlparser.DDL) + if !ok { + return "", nil, errors.New("input sql is not ddl") + } + basic.TableName = sqlparser.String(r.NewName) + basic.ModelStruct = util.String.SnakeCaseToCamel(basic.TableName) + structResult := "type " + basic.ModelStruct + " struct { \n" + + for _, item := range r.TableSpec.Columns { + data := map[string]string{ + "{FIELD}": util.String.SnakeCaseToCamel(item.Name.String()), + "{COLUMN}": item.Name.String(), + "{JSON_TAG}": item.Name.String(), + "{DEFAULT_VALUE}": "", + "{COMMENT}": item.Name.String() + " " + string(item.Type.Comment.Val), + "{TYPE}": sqlTypeMap[item.Type.Type], + } + if data["{FIELD}"] == "ID" { + basic.PrimaryFieldType = data["{TYPE}"] + } + if item.Type.NotNull { + data["{NOT_NULL}"] = "NOT NULL" + } + if nil != item.Type.Default { + data["{DEFAULT_VALUE}"] += string(item.Type.Default.Val) + } + val := CreateSQLColumnTPL + for k, v := range data { + val = strings.ReplaceAll(val, k, v) + } + structResult += val + "\n" + } + structResult = structResult + "}" + return structResult, basic, nil +} diff --git a/sql2go/parser_test.go b/sql2go/parser_test.go new file mode 100644 index 0000000..34801bb --- /dev/null +++ b/sql2go/parser_test.go @@ -0,0 +1,18 @@ +// Package sql2go... +// +// Description : sql2go... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2021-10-25 5:02 下午 +package sql2go + +import ( + "fmt" + "testing" +) + +func TestParseSql(t *testing.T) { + sql := "CREATE TABLE `app` (\n `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',\n `code` varchar(128) NOT NULL DEFAULT '' COMMENT '分配的app_code',\n `secret` varchar(64) NOT NULL DEFAULT '' COMMENT '分配的私钥',\n `status` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '当前状态 o - 初始化 1- 使用中 2 - 禁用 3 - 删除',\n `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述信息',\n `apply_user_name` varchar(64) NOT NULL DEFAULT '' COMMENT '申请人姓名',\n `apply_user_contact` varchar(128) NOT NULL DEFAULT '' COMMENT '申请人联系方式',\n `create_user_id` varchar(128) NOT NULL DEFAULT '' COMMENT '创建人ID',\n `modify_user_id` varchar(128) NOT NULL DEFAULT '' COMMENT '修改人ID',\n PRIMARY KEY (`id`),\n UNIQUE KEY `uniq_code` (`code`)\n) ENGINE=InnoDB AUTO_INCREMENT=100001 DEFAULT CHARSET=utf8mb4 COMMENT='APP信息表'" + fmt.Println(ParseCreateTableSql(sql)) +}