123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- package gorm
- import (
- "database/sql"
- "fmt"
- "reflect"
- "strconv"
- "strings"
- )
- // Dialect interface contains behaviors that differ across SQL database
- type Dialect interface {
- // GetName get dialect's name
- GetName() string
- // SetDB set db for dialect
- SetDB(db SQLCommon)
- // BindVar return the placeholder for actual values in SQL statements, in many dbs it is "?", Postgres using $1
- BindVar(i int) string
- // Quote quotes field name to avoid SQL parsing exceptions by using a reserved word as a field name
- Quote(key string) string
- // DataTypeOf return data's sql type
- DataTypeOf(field *StructField) string
- // HasIndex check has index or not
- HasIndex(tableName string, indexName string) bool
- // HasForeignKey check has foreign key or not
- HasForeignKey(tableName string, foreignKeyName string) bool
- // RemoveIndex remove index
- RemoveIndex(tableName string, indexName string) error
- // HasTable check has table or not
- HasTable(tableName string) bool
- // HasColumn check has column or not
- HasColumn(tableName string, columnName string) bool
- // LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case
- LimitAndOffsetSQL(limit, offset interface{}) string
- // SelectFromDummyTable return select values, for most dbs, `SELECT values` just works, mysql needs `SELECT value FROM DUAL`
- SelectFromDummyTable() string
- // LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING`
- LastInsertIDReturningSuffix(tableName, columnName string) string
- // BuildForeignKeyName returns a foreign key name for the given table, field and reference
- BuildForeignKeyName(tableName, field, dest string) string
- // CurrentDatabase return current database name
- CurrentDatabase() string
- }
- var dialectsMap = map[string]Dialect{}
- func newDialect(name string, db SQLCommon) Dialect {
- if value, ok := dialectsMap[name]; ok {
- dialect := reflect.New(reflect.TypeOf(value).Elem()).Interface().(Dialect)
- dialect.SetDB(db)
- return dialect
- }
- fmt.Printf("`%v` is not officially supported, running under compatibility mode.\n", name)
- commontDialect := &commonDialect{}
- commontDialect.SetDB(db)
- return commontDialect
- }
- // RegisterDialect register new dialect
- func RegisterDialect(name string, dialect Dialect) {
- dialectsMap[name] = dialect
- }
- // ParseFieldStructForDialect get field's sql data type
- var ParseFieldStructForDialect = func(field *StructField, dialect Dialect) (fieldValue reflect.Value, sqlType string, size int, additionalType string) {
- // Get redirected field type
- var (
- reflectType = field.Struct.Type
- dataType = field.TagSettings["TYPE"]
- )
- for reflectType.Kind() == reflect.Ptr {
- reflectType = reflectType.Elem()
- }
- // Get redirected field value
- fieldValue = reflect.Indirect(reflect.New(reflectType))
- if gormDataType, ok := fieldValue.Interface().(interface {
- GormDataType(Dialect) string
- }); ok {
- dataType = gormDataType.GormDataType(dialect)
- }
- // Get scanner's real value
- var getScannerValue func(reflect.Value)
- getScannerValue = func(value reflect.Value) {
- fieldValue = value
- if _, isScanner := reflect.New(fieldValue.Type()).Interface().(sql.Scanner); isScanner && fieldValue.Kind() == reflect.Struct {
- getScannerValue(fieldValue.Field(0))
- }
- }
- getScannerValue(fieldValue)
- // Default Size
- if num, ok := field.TagSettings["SIZE"]; ok {
- size, _ = strconv.Atoi(num)
- } else {
- size = 255
- }
- // Default type from tag setting
- additionalType = field.TagSettings["NOT NULL"] + " " + field.TagSettings["UNIQUE"]
- if value, ok := field.TagSettings["DEFAULT"]; ok {
- additionalType = additionalType + " DEFAULT " + value
- }
- return fieldValue, dataType, size, strings.TrimSpace(additionalType)
- }
|