11 // Dialect interface contains behaviors that differ across SQL database
12 type Dialect interface {
13 // GetName get dialect's name
16 // SetDB set db for dialect
19 // BindVar return the placeholder for actual values in SQL statements, in many dbs it is "?", Postgres using $1
21 // Quote quotes field name to avoid SQL parsing exceptions by using a reserved word as a field name
22 Quote(key string) string
23 // DataTypeOf return data's sql type
24 DataTypeOf(field *StructField) string
26 // HasIndex check has index or not
27 HasIndex(tableName string, indexName string) bool
28 // HasForeignKey check has foreign key or not
29 HasForeignKey(tableName string, foreignKeyName string) bool
30 // RemoveIndex remove index
31 RemoveIndex(tableName string, indexName string) error
32 // HasTable check has table or not
33 HasTable(tableName string) bool
34 // HasColumn check has column or not
35 HasColumn(tableName string, columnName string) bool
36 // ModifyColumn modify column's type
37 ModifyColumn(tableName string, columnName string, typ string) error
39 // LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case
40 LimitAndOffsetSQL(limit, offset interface{}) string
41 // SelectFromDummyTable return select values, for most dbs, `SELECT values` just works, mysql needs `SELECT value FROM DUAL`
42 SelectFromDummyTable() string
43 // LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING`
44 LastInsertIDReturningSuffix(tableName, columnName string) string
46 DefaultValueStr() string
48 // BuildKeyName returns a valid key name (foreign key, index key) for the given table, field and reference
49 BuildKeyName(kind, tableName string, fields ...string) string
51 // CurrentDatabase return current database name
52 CurrentDatabase() string
55 var dialectsMap = map[string]Dialect{}
57 func newDialect(name string, db SQLCommon) Dialect {
58 if value, ok := dialectsMap[name]; ok {
59 dialect := reflect.New(reflect.TypeOf(value).Elem()).Interface().(Dialect)
64 fmt.Printf("`%v` is not officially supported, running under compatibility mode.\n", name)
65 commontDialect := &commonDialect{}
66 commontDialect.SetDB(db)
70 // RegisterDialect register new dialect
71 func RegisterDialect(name string, dialect Dialect) {
72 dialectsMap[name] = dialect
75 // GetDialect gets the dialect for the specified dialect name
76 func GetDialect(name string) (dialect Dialect, ok bool) {
77 dialect, ok = dialectsMap[name]
81 // ParseFieldStructForDialect get field's sql data type
82 var ParseFieldStructForDialect = func(field *StructField, dialect Dialect) (fieldValue reflect.Value, sqlType string, size int, additionalType string) {
83 // Get redirected field type
85 reflectType = field.Struct.Type
86 dataType, _ = field.TagSettingsGet("TYPE")
89 for reflectType.Kind() == reflect.Ptr {
90 reflectType = reflectType.Elem()
93 // Get redirected field value
94 fieldValue = reflect.Indirect(reflect.New(reflectType))
96 if gormDataType, ok := fieldValue.Interface().(interface {
97 GormDataType(Dialect) string
99 dataType = gormDataType.GormDataType(dialect)
102 // Get scanner's real value
104 var getScannerValue func(reflect.Value)
105 getScannerValue = func(value reflect.Value) {
107 if _, isScanner := reflect.New(fieldValue.Type()).Interface().(sql.Scanner); isScanner && fieldValue.Kind() == reflect.Struct {
108 getScannerValue(fieldValue.Field(0))
111 getScannerValue(fieldValue)
115 if num, ok := field.TagSettingsGet("SIZE"); ok {
116 size, _ = strconv.Atoi(num)
121 // Default type from tag setting
122 notNull, _ := field.TagSettingsGet("NOT NULL")
123 unique, _ := field.TagSettingsGet("UNIQUE")
124 additionalType = notNull + " " + unique
125 if value, ok := field.TagSettingsGet("DEFAULT"); ok {
126 additionalType = additionalType + " DEFAULT " + value
129 return fieldValue, dataType, size, strings.TrimSpace(additionalType)
132 func currentDatabaseAndTable(dialect Dialect, tableName string) (string, string) {
133 if strings.Contains(tableName, ".") {
134 splitStrings := strings.SplitN(tableName, ".", 2)
135 return splitStrings[0], splitStrings[1]
137 return dialect.CurrentDatabase(), tableName