dialect.go 4.8 KB

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