dialect.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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. // NormalizeIndexAndColumn returns valid index name and column name depending on each dialect
  44. NormalizeIndexAndColumn(indexName, columnName string) (string, string)
  45. // CurrentDatabase return current database name
  46. CurrentDatabase() string
  47. }
  48. var dialectsMap = map[string]Dialect{}
  49. func newDialect(name string, db SQLCommon) Dialect {
  50. if value, ok := dialectsMap[name]; ok {
  51. dialect := reflect.New(reflect.TypeOf(value).Elem()).Interface().(Dialect)
  52. dialect.SetDB(db)
  53. return dialect
  54. }
  55. fmt.Printf("`%v` is not officially supported, running under compatibility mode.\n", name)
  56. commontDialect := &commonDialect{}
  57. commontDialect.SetDB(db)
  58. return commontDialect
  59. }
  60. // RegisterDialect register new dialect
  61. func RegisterDialect(name string, dialect Dialect) {
  62. dialectsMap[name] = dialect
  63. }
  64. // GetDialect gets the dialect for the specified dialect name
  65. func GetDialect(name string) (dialect Dialect, ok bool) {
  66. dialect, ok = dialectsMap[name]
  67. return
  68. }
  69. // ParseFieldStructForDialect get field's sql data type
  70. var ParseFieldStructForDialect = func(field *StructField, dialect Dialect) (fieldValue reflect.Value, sqlType string, size int, additionalType string) {
  71. // Get redirected field type
  72. var (
  73. reflectType = field.Struct.Type
  74. dataType, _ = field.TagSettingsGet("TYPE")
  75. )
  76. for reflectType.Kind() == reflect.Ptr {
  77. reflectType = reflectType.Elem()
  78. }
  79. // Get redirected field value
  80. fieldValue = reflect.Indirect(reflect.New(reflectType))
  81. if gormDataType, ok := fieldValue.Interface().(interface {
  82. GormDataType(Dialect) string
  83. }); ok {
  84. dataType = gormDataType.GormDataType(dialect)
  85. }
  86. // Get scanner's real value
  87. if dataType == "" {
  88. var getScannerValue func(reflect.Value)
  89. getScannerValue = func(value reflect.Value) {
  90. fieldValue = value
  91. if _, isScanner := reflect.New(fieldValue.Type()).Interface().(sql.Scanner); isScanner && fieldValue.Kind() == reflect.Struct {
  92. getScannerValue(fieldValue.Field(0))
  93. }
  94. }
  95. getScannerValue(fieldValue)
  96. }
  97. // Default Size
  98. if num, ok := field.TagSettingsGet("SIZE"); ok {
  99. size, _ = strconv.Atoi(num)
  100. } else {
  101. size = 255
  102. }
  103. // Default type from tag setting
  104. notNull, _ := field.TagSettingsGet("NOT NULL")
  105. unique, _ := field.TagSettingsGet("UNIQUE")
  106. additionalType = notNull + " " + unique
  107. if value, ok := field.TagSettingsGet("DEFAULT"); ok {
  108. additionalType = additionalType + " DEFAULT " + value
  109. }
  110. if value, ok := field.TagSettingsGet("COMMENT"); ok {
  111. additionalType = additionalType + " COMMENT " + value
  112. }
  113. return fieldValue, dataType, size, strings.TrimSpace(additionalType)
  114. }
  115. func currentDatabaseAndTable(dialect Dialect, tableName string) (string, string) {
  116. if strings.Contains(tableName, ".") {
  117. splitStrings := strings.SplitN(tableName, ".", 2)
  118. return splitStrings[0], splitStrings[1]
  119. }
  120. return dialect.CurrentDatabase(), tableName
  121. }