dialect.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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. // LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case
  32. LimitAndOffsetSQL(limit, offset interface{}) string
  33. // SelectFromDummyTable return select values, for most dbs, `SELECT values` just works, mysql needs `SELECT value FROM DUAL`
  34. SelectFromDummyTable() string
  35. // LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING`
  36. LastInsertIDReturningSuffix(tableName, columnName string) string
  37. // BuildForeignKeyName returns a foreign key name for the given table, field and reference
  38. BuildForeignKeyName(tableName, field, dest string) string
  39. // CurrentDatabase return current database name
  40. CurrentDatabase() string
  41. }
  42. var dialectsMap = map[string]Dialect{}
  43. func newDialect(name string, db SQLCommon) Dialect {
  44. if value, ok := dialectsMap[name]; ok {
  45. dialect := reflect.New(reflect.TypeOf(value).Elem()).Interface().(Dialect)
  46. dialect.SetDB(db)
  47. return dialect
  48. }
  49. fmt.Printf("`%v` is not officially supported, running under compatibility mode.\n", name)
  50. commontDialect := &commonDialect{}
  51. commontDialect.SetDB(db)
  52. return commontDialect
  53. }
  54. // RegisterDialect register new dialect
  55. func RegisterDialect(name string, dialect Dialect) {
  56. dialectsMap[name] = dialect
  57. }
  58. // ParseFieldStructForDialect get field's sql data type
  59. var ParseFieldStructForDialect = func(field *StructField, dialect Dialect) (fieldValue reflect.Value, sqlType string, size int, additionalType string) {
  60. // Get redirected field type
  61. var (
  62. reflectType = field.Struct.Type
  63. dataType = field.TagSettings["TYPE"]
  64. )
  65. for reflectType.Kind() == reflect.Ptr {
  66. reflectType = reflectType.Elem()
  67. }
  68. // Get redirected field value
  69. fieldValue = reflect.Indirect(reflect.New(reflectType))
  70. if gormDataType, ok := fieldValue.Interface().(interface {
  71. GormDataType(Dialect) string
  72. }); ok {
  73. dataType = gormDataType.GormDataType(dialect)
  74. }
  75. // Get scanner's real value
  76. var getScannerValue func(reflect.Value)
  77. getScannerValue = func(value reflect.Value) {
  78. fieldValue = value
  79. if _, isScanner := reflect.New(fieldValue.Type()).Interface().(sql.Scanner); isScanner && fieldValue.Kind() == reflect.Struct {
  80. getScannerValue(fieldValue.Field(0))
  81. }
  82. }
  83. getScannerValue(fieldValue)
  84. // Default Size
  85. if num, ok := field.TagSettings["SIZE"]; ok {
  86. size, _ = strconv.Atoi(num)
  87. } else {
  88. size = 255
  89. }
  90. // Default type from tag setting
  91. additionalType = field.TagSettings["NOT NULL"] + " " + field.TagSettings["UNIQUE"]
  92. if value, ok := field.TagSettings["DEFAULT"]; ok {
  93. additionalType = additionalType + " DEFAULT " + value
  94. }
  95. return fieldValue, dataType, size, strings.TrimSpace(additionalType)
  96. }