Açıklama Yok
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

get_mysql_create_table.go 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. package dbs
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "strings"
  6. "time"
  7. "git.x2erp.com/qdy/go-svc-mcp/internal/mcp"
  8. )
  9. func init() {
  10. mcp.Register("get_mysql_create_table", "在MySQL数据库中创建新表,支持字段约束和注释",
  11. map[string]interface{}{
  12. "type": "object",
  13. "properties": map[string]interface{}{
  14. "table_name": map[string]interface{}{
  15. "type": "string",
  16. "description": "表名称",
  17. },
  18. "table_description": map[string]interface{}{
  19. "type": "string",
  20. "description": "表描述/注释",
  21. "default": "",
  22. },
  23. "schema": map[string]interface{}{
  24. "type": "string",
  25. "description": "数据库名称(默认为当前数据库)",
  26. "default": "",
  27. },
  28. "fields": map[string]interface{}{
  29. "type": "array",
  30. "description": "字段定义",
  31. "items": map[string]interface{}{
  32. "type": "object",
  33. "properties": map[string]interface{}{
  34. "field_name": map[string]interface{}{
  35. "type": "string",
  36. "description": "字段名称",
  37. },
  38. "data_type": map[string]interface{}{
  39. "type": "string",
  40. "description": "数据类型(如 VARCHAR(255), INT, DATETIME 等)",
  41. },
  42. "is_nullable": map[string]interface{}{
  43. "type": "boolean",
  44. "description": "是否允许为空",
  45. "default": true,
  46. },
  47. "field_default": map[string]interface{}{
  48. "type": "string",
  49. "description": "默认值",
  50. "default": "",
  51. },
  52. "field_description": map[string]interface{}{
  53. "type": "string",
  54. "description": "字段描述/注释",
  55. "default": "",
  56. },
  57. "is_primary_key": map[string]interface{}{
  58. "type": "boolean",
  59. "description": "是否为主键",
  60. "default": false,
  61. },
  62. "is_unique": map[string]interface{}{
  63. "type": "boolean",
  64. "description": "是否唯一约束",
  65. "default": false,
  66. },
  67. "auto_increment": map[string]interface{}{
  68. "type": "boolean",
  69. "description": "是否自增(仅适用于数值类型)",
  70. "default": false,
  71. },
  72. },
  73. "required": []string{"field_name", "data_type"},
  74. },
  75. },
  76. "database_key": map[string]interface{}{
  77. "type": "string",
  78. "description": "数据库配置键名:warehouse(仓库数据库)或 business(业务数据库),可选,默认使用主数据库",
  79. "enum": []string{"warehouse", "business"},
  80. "default": "",
  81. },
  82. },
  83. "required": []string{"table_name", "fields"},
  84. },
  85. func(input json.RawMessage, deps *mcp.ToolDependencies) (interface{}, error) {
  86. var params struct {
  87. TableName string `json:"table_name"`
  88. TableDescription string `json:"table_description"`
  89. Schema string `json:"schema"`
  90. DatabaseKey string `json:"database_key"`
  91. Fields []struct {
  92. FieldName string `json:"field_name"`
  93. DataType string `json:"data_type"`
  94. IsNullable bool `json:"is_nullable"`
  95. FieldDefault string `json:"field_default"`
  96. FieldDescription string `json:"field_description"`
  97. IsPrimaryKey bool `json:"is_primary_key"`
  98. IsUnique bool `json:"is_unique"`
  99. AutoIncrement bool `json:"auto_increment"`
  100. } `json:"fields"`
  101. }
  102. if len(input) > 0 {
  103. if err := json.Unmarshal(input, &params); err != nil {
  104. return nil, err
  105. }
  106. }
  107. // 获取数据库工厂
  108. dbFactory, err := GetDBFactory(params.DatabaseKey, deps)
  109. if err != nil {
  110. return nil, err
  111. }
  112. // 获取数据库类型,确保是MySQL
  113. dbType := dbFactory.GetDBType()
  114. if dbType != "mysql" {
  115. return nil, fmt.Errorf("数据库类型为 %s,此工具仅支持MySQL数据库", dbType)
  116. }
  117. // 获取当前数据库名称
  118. currentDatabase := dbFactory.GetDatabaseName()
  119. schema := strings.TrimSpace(params.Schema)
  120. if schema == "" {
  121. schema = currentDatabase
  122. }
  123. tableName := strings.TrimSpace(params.TableName)
  124. if tableName == "" {
  125. return nil, fmt.Errorf("表名称不能为空")
  126. }
  127. if len(params.Fields) == 0 {
  128. return nil, fmt.Errorf("至少需要定义一个字段")
  129. }
  130. // 检查表是否已存在
  131. tableExistsQuery := `SELECT COUNT(*) as table_count FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?`
  132. tableCheckResults, err := dbFactory.QuerySliceMapWithParams(tableExistsQuery, schema, tableName)
  133. if err != nil {
  134. return nil, fmt.Errorf("检查表是否存在失败: %v", err)
  135. }
  136. tableExists := false
  137. if len(tableCheckResults) > 0 {
  138. if count, ok := tableCheckResults[0]["table_count"].(int64); ok && count > 0 {
  139. tableExists = true
  140. }
  141. }
  142. if tableExists {
  143. return nil, fmt.Errorf("表 '%s' 已存在于数据库 '%s' 中", tableName, schema)
  144. }
  145. // 构建建表SQL
  146. var fieldDefinitions []string
  147. var primaryKeyFields []string
  148. for _, field := range params.Fields {
  149. fieldName := strings.TrimSpace(field.FieldName)
  150. dataType := strings.TrimSpace(field.DataType)
  151. if fieldName == "" || dataType == "" {
  152. return nil, fmt.Errorf("字段名称和数据类型不能为空")
  153. }
  154. // 构建字段定义
  155. fieldDef := fmt.Sprintf("`%s` %s", fieldName, dataType)
  156. // 添加NOT NULL约束
  157. if !field.IsNullable {
  158. fieldDef += " NOT NULL"
  159. }
  160. // 添加默认值
  161. if field.FieldDefault != "" {
  162. // 检查默认值是否需要引号(字符串类型需要引号)
  163. fieldDef += fmt.Sprintf(" DEFAULT '%s'", strings.ReplaceAll(field.FieldDefault, "'", "''"))
  164. }
  165. // 添加自增
  166. if field.AutoIncrement {
  167. fieldDef += " AUTO_INCREMENT"
  168. }
  169. // 添加唯一约束(如果不是主键)
  170. if field.IsUnique && !field.IsPrimaryKey {
  171. fieldDef += " UNIQUE"
  172. }
  173. fieldDefinitions = append(fieldDefinitions, fieldDef)
  174. // 收集主键字段
  175. if field.IsPrimaryKey {
  176. primaryKeyFields = append(primaryKeyFields, fmt.Sprintf("`%s`", fieldName))
  177. }
  178. }
  179. // 添加主键约束
  180. if len(primaryKeyFields) > 0 {
  181. primaryKeyDef := fmt.Sprintf("PRIMARY KEY (%s)", strings.Join(primaryKeyFields, ", "))
  182. fieldDefinitions = append(fieldDefinitions, primaryKeyDef)
  183. }
  184. // 构建完整的CREATE TABLE语句
  185. createTableSQL := fmt.Sprintf("CREATE TABLE `%s`.`%s` (\n %s\n)", schema, tableName, strings.Join(fieldDefinitions, ",\n "))
  186. // 添加表注释
  187. tableDescription := strings.TrimSpace(params.TableDescription)
  188. if tableDescription != "" {
  189. createTableSQL += fmt.Sprintf(" COMMENT='%s'", strings.ReplaceAll(tableDescription, "'", "''"))
  190. }
  191. // 执行建表SQL
  192. _, err = dbFactory.Execute(createTableSQL)
  193. if err != nil {
  194. return nil, fmt.Errorf("创建表失败: %v", err)
  195. }
  196. // 添加字段注释
  197. for _, field := range params.Fields {
  198. fieldDescription := strings.TrimSpace(field.FieldDescription)
  199. if fieldDescription != "" {
  200. fieldName := strings.TrimSpace(field.FieldName)
  201. commentSQL := fmt.Sprintf("ALTER TABLE `%s`.`%s` MODIFY COLUMN `%s` %s COMMENT '%s'",
  202. schema, tableName, fieldName, field.DataType, strings.ReplaceAll(fieldDescription, "'", "''"))
  203. // 重新构建完整的字段定义
  204. fieldDef := fmt.Sprintf("`%s` %s", fieldName, field.DataType)
  205. if !field.IsNullable {
  206. fieldDef += " NOT NULL"
  207. }
  208. if field.FieldDefault != "" {
  209. fieldDef += fmt.Sprintf(" DEFAULT '%s'", strings.ReplaceAll(field.FieldDefault, "'", "''"))
  210. }
  211. if field.AutoIncrement {
  212. fieldDef += " AUTO_INCREMENT"
  213. }
  214. if field.IsUnique && !field.IsPrimaryKey {
  215. fieldDef += " UNIQUE"
  216. }
  217. commentSQL = fmt.Sprintf("ALTER TABLE `%s`.`%s` MODIFY COLUMN %s COMMENT '%s'",
  218. schema, tableName, fieldDef, strings.ReplaceAll(fieldDescription, "'", "''"))
  219. _, err = dbFactory.Execute(commentSQL)
  220. if err != nil {
  221. // 字段注释添加失败不是致命错误,记录但继续
  222. fmt.Printf("添加字段注释失败: %v\n", err)
  223. }
  224. }
  225. }
  226. return map[string]interface{}{
  227. "tenant_id": deps.ReqCtx.TenantID,
  228. "user_id": deps.ReqCtx.UserID,
  229. "database_type": dbType,
  230. "database_name": dbFactory.GetDatabaseName(),
  231. "schema": schema,
  232. "table_name": tableName,
  233. "table_description": tableDescription,
  234. "total_fields": len(params.Fields),
  235. "primary_key_fields": len(primaryKeyFields),
  236. "sql_statement": createTableSQL,
  237. "status": "success",
  238. "message": fmt.Sprintf("表 '%s' 创建成功", tableName),
  239. "timestamp": time.Now().Format(time.RFC3339),
  240. }, nil
  241. },
  242. )
  243. }