dialect.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. package gorm
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "reflect"
  6. "strconv"
  7. "strings"
  8. )
  9. // Dialect interface contains behaviors that differ across SQL database
  10. type Dialect interface {
  11. // GetName get dialect's name
  12. GetName() string
  13. // SetDB set db for dialect
  14. SetDB(db SQLCommon)
  15. // BindVar return the placeholder for actual values in SQL statements, in many dbs it is "?", Postgres using $1
  16. BindVar(i int) string
  17. // Quote quotes field name to avoid SQL parsing exceptions by using a reserved word as a field name
  18. Quote(key string) string
  19. // DataTypeOf return data's sql type
  20. DataTypeOf(field *StructField) string
  21. // HasIndex check has index or not
  22. HasIndex(tableName string, indexName string) bool
  23. // HasForeignKey check has foreign key or not
  24. HasForeignKey(tableName string, foreignKeyName string) bool
  25. // RemoveIndex remove index
  26. RemoveIndex(tableName string, indexName string) error
  27. // HasTable check has table or not
  28. HasTable(tableName string) bool
  29. // HasColumn check has column or not
  30. HasColumn(tableName string, columnName string) bool
  31. // ModifyColumn modify column's type
  32. ModifyColumn(tableName string, columnName string, typ string) error
  33. // LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case
  34. LimitAndOffsetSQL(limit, offset interface{}) string
  35. // SelectFromDummyTable return select values, for most dbs, `SELECT values` just works, mysql needs `SELECT value FROM DUAL`
  36. SelectFromDummyTable() string
  37. // LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING`
  38. LastInsertIDReturningSuffix(tableName, columnName string) string
  39. // DefaultValueStr
  40. DefaultValueStr() string
  41. // BuildKeyName returns a valid key name (foreign key, index key) for the given table, field and reference
  42. BuildKeyName(kind, tableName string, fields ...string) string
  43. // CurrentDatabase return current database name
  44. CurrentDatabase() string
  45. }
  46. var dialectsMap = map[string]Dialect{}
  47. func newDialect(name string, db SQLCommon) Dialect {
  48. if value, ok := dialectsMap[name]; ok {
  49. dialect := reflect.New(reflect.TypeOf(value).Elem()).Interface().(Dialect)
  50. dialect.SetDB(db)
  51. return dialect
  52. }
  53. fmt.Printf("`%v` is not officially supported, running under compatibility mode.\n", name)
  54. commontDialect := &commonDialect{}
  55. commontDialect.SetDB(db)
  56. return commontDialect
  57. }
  58. // RegisterDialect register new dialect
  59. func RegisterDialect(name string, dialect Dialect) {
  60. dialectsMap[name] = dialect
  61. }
  62. // GetDialect gets the dialect for the specified dialect name
  63. func GetDialect(name string) (dialect Dialect, ok bool) {
  64. dialect, ok = dialectsMap[name]
  65. return
  66. }
  67. // ParseFieldStructForDialect get field's sql data type
  68. var ParseFieldStructForDialect = func(field *StructField, dialect Dialect) (fieldValue reflect.Value, sqlType string, size int, additionalType string) {
  69. // Get redirected field type
  70. var (
  71. reflectType = field.Struct.Type
  72. dataType, _ = field.TagSettingsGet("TYPE")
  73. )
  74. for reflectType.Kind() == reflect.Ptr {
  75. reflectType = reflectType.Elem()
  76. }
  77. // Get redirected field value
  78. fieldValue = reflect.Indirect(reflect.New(reflectType))
  79. if gormDataType, ok := fieldValue.Interface().(interface {
  80. GormDataType(Dialect) string
  81. }); ok {
  82. dataType = gormDataType.GormDataType(dialect)
  83. }
  84. // Get scanner's real value
  85. if dataType == "" {
  86. var getScannerValue func(reflect.Value)
  87. getScannerValue = func(value reflect.Value) {
  88. fieldValue = value
  89. if _, isScanner := reflect.New(fieldValue.Type()).Interface().(sql.Scanner); isScanner && fieldValue.Kind() == reflect.Struct {
  90. getScannerValue(fieldValue.Field(0))
  91. }
  92. }
  93. getScannerValue(fieldValue)
  94. }
  95. // Default Size
  96. if num, ok := field.TagSettingsGet("SIZE"); ok {
  97. size, _ = strconv.Atoi(num)
  98. } else {
  99. size = 255
  100. }
  101. // Default type from tag setting
  102. notNull, _ := field.TagSettingsGet("NOT NULL")
  103. unique, _ := field.TagSettingsGet("UNIQUE")
  104. additionalType = notNull + " " + unique
  105. if value, ok := field.TagSettingsGet("DEFAULT"); ok {
  106. additionalType = additionalType + " DEFAULT " + value
  107. }
  108. if value, ok := field.TagSettingsGet("COMMENT"); ok {
  109. additionalType = additionalType + " COMMENT " + value
  110. }
  111. return fieldValue, dataType, size, strings.TrimSpace(additionalType)
  112. }
  113. func currentDatabaseAndTable(dialect Dialect, tableName string) (string, string) {
  114. if strings.Contains(tableName, ".") {
  115. splitStrings := strings.SplitN(tableName, ".", 2)
  116. return splitStrings[0], splitStrings[1]
  117. }
  118. return dialect.CurrentDatabase(), tableName
  119. }