2014-07-02 13:47:30 +04:00
package gorm
import (
"fmt"
"reflect"
2016-05-22 01:13:26 +03:00
"regexp"
2016-06-21 06:13:33 +03:00
"strconv"
2016-02-14 08:51:34 +03:00
"strings"
2015-02-17 17:55:14 +03:00
"time"
2014-07-02 13:47:30 +04:00
)
2019-04-15 11:46:50 +03:00
var keyNameRegex = regexp . MustCompile ( "[^a-zA-Z0-9]+" )
2016-05-22 01:13:26 +03:00
// DefaultForeignKeyNamer contains the default foreign key name generator method
type DefaultForeignKeyNamer struct {
}
2016-02-15 09:09:24 +03:00
type commonDialect struct {
2017-03-14 23:32:38 +03:00
db SQLCommon
2016-05-22 01:13:26 +03:00
DefaultForeignKeyNamer
2016-02-15 09:09:24 +03:00
}
2014-07-02 13:47:30 +04:00
2016-02-14 13:06:42 +03:00
func init ( ) {
RegisterDialect ( "common" , & commonDialect { } )
}
2016-03-05 16:24:54 +03:00
func ( commonDialect ) GetName ( ) string {
return "common"
}
2017-03-14 23:32:38 +03:00
func ( s * commonDialect ) SetDB ( db SQLCommon ) {
2016-02-15 09:09:24 +03:00
s . db = db
}
2016-01-19 06:53:53 +03:00
func ( commonDialect ) BindVar ( i int ) string {
2017-04-18 11:13:02 +03:00
return "$$$" // ?
2014-07-02 13:47:30 +04:00
}
2016-01-18 15:32:52 +03:00
func ( commonDialect ) Quote ( key string ) string {
return fmt . Sprintf ( ` "%s" ` , key )
2014-09-16 00:03:14 +04:00
}
2017-10-13 10:08:55 +03:00
func ( s * commonDialect ) fieldCanAutoIncrement ( field * StructField ) bool {
2018-09-10 02:11:00 +03:00
if value , ok := field . TagSettingsGet ( "AUTO_INCREMENT" ) ; ok {
2018-02-10 14:25:58 +03:00
return strings . ToLower ( value ) != "false"
2017-10-13 10:08:55 +03:00
}
2018-02-10 03:24:39 +03:00
return field . IsPrimaryKey
2017-10-13 10:08:55 +03:00
}
2017-01-15 16:24:53 +03:00
func ( s * commonDialect ) DataTypeOf ( field * StructField ) string {
var dataValue , sqlType , size , additionalType = ParseFieldStructForDialect ( field , s )
2016-01-19 15:58:38 +03:00
2016-02-14 08:51:34 +03:00
if sqlType == "" {
switch dataValue . Kind ( ) {
case reflect . Bool :
sqlType = "BOOLEAN"
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uintptr :
2017-10-13 10:08:55 +03:00
if s . fieldCanAutoIncrement ( field ) {
2016-02-14 08:51:34 +03:00
sqlType = "INTEGER AUTO_INCREMENT"
} else {
sqlType = "INTEGER"
}
case reflect . Int64 , reflect . Uint64 :
2017-10-13 10:08:55 +03:00
if s . fieldCanAutoIncrement ( field ) {
2016-02-14 08:51:34 +03:00
sqlType = "BIGINT AUTO_INCREMENT"
} else {
sqlType = "BIGINT"
}
case reflect . Float32 , reflect . Float64 :
sqlType = "FLOAT"
case reflect . String :
2014-07-02 13:47:30 +04:00
if size > 0 && size < 65532 {
2016-02-14 08:51:34 +03:00
sqlType = fmt . Sprintf ( "VARCHAR(%d)" , size )
} else {
sqlType = "VARCHAR(65532)"
}
case reflect . Struct :
if _ , ok := dataValue . Interface ( ) . ( time . Time ) ; ok {
sqlType = "TIMESTAMP"
}
default :
if _ , ok := dataValue . Interface ( ) . ( [ ] byte ) ; ok {
if size > 0 && size < 65532 {
sqlType = fmt . Sprintf ( "BINARY(%d)" , size )
} else {
sqlType = "BINARY(65532)"
}
2014-07-02 13:47:30 +04:00
}
}
}
2016-02-14 08:51:34 +03:00
if sqlType == "" {
panic ( fmt . Sprintf ( "invalid sql type %s (%s) for commonDialect" , dataValue . Type ( ) . Name ( ) , dataValue . Kind ( ) . String ( ) ) )
}
if strings . TrimSpace ( additionalType ) == "" {
return sqlType
}
return fmt . Sprintf ( "%v %v" , sqlType , additionalType )
2014-07-02 13:47:30 +04:00
}
2016-02-15 09:09:24 +03:00
func ( s commonDialect ) HasIndex ( tableName string , indexName string ) bool {
var count int
2018-02-03 15:27:19 +03:00
currentDatabase , tableName := currentDatabaseAndTable ( & s , tableName )
2018-02-02 19:59:40 +03:00
s . db . QueryRow ( "SELECT count(*) FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema = ? AND table_name = ? AND index_name = ?" , currentDatabase , tableName , indexName ) . Scan ( & count )
2016-01-18 15:32:52 +03:00
return count > 0
2014-07-30 10:18:15 +04:00
}
2016-02-15 09:09:24 +03:00
func ( s commonDialect ) RemoveIndex ( tableName string , indexName string ) error {
_ , err := s . db . Exec ( fmt . Sprintf ( "DROP INDEX %v" , indexName ) )
return err
2014-07-02 13:47:30 +04:00
}
2016-03-05 17:50:49 +03:00
func ( s commonDialect ) HasForeignKey ( tableName string , foreignKeyName string ) bool {
return false
}
2016-02-15 09:09:24 +03:00
func ( s commonDialect ) HasTable ( tableName string ) bool {
var count int
2018-02-03 15:27:19 +03:00
currentDatabase , tableName := currentDatabaseAndTable ( & s , tableName )
2018-02-02 19:59:40 +03:00
s . db . QueryRow ( "SELECT count(*) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = ? AND table_name = ?" , currentDatabase , tableName ) . Scan ( & count )
2014-07-02 13:47:30 +04:00
return count > 0
}
2016-02-15 09:09:24 +03:00
func ( s commonDialect ) HasColumn ( tableName string , columnName string ) bool {
var count int
2018-02-03 15:27:19 +03:00
currentDatabase , tableName := currentDatabaseAndTable ( & s , tableName )
2018-02-02 19:59:40 +03:00
s . db . QueryRow ( "SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = ? AND table_name = ? AND column_name = ?" , currentDatabase , tableName , columnName ) . Scan ( & count )
2015-03-02 18:02:40 +03:00
return count > 0
}
2018-02-09 17:58:34 +03:00
func ( s commonDialect ) ModifyColumn ( tableName string , columnName string , typ string ) error {
_ , err := s . db . Exec ( fmt . Sprintf ( "ALTER TABLE %v ALTER COLUMN %v TYPE %v" , tableName , columnName , typ ) )
return err
}
2016-07-11 16:37:44 +03:00
func ( s commonDialect ) CurrentDatabase ( ) ( name string ) {
2016-02-15 09:09:24 +03:00
s . db . QueryRow ( "SELECT DATABASE()" ) . Scan ( & name )
2015-08-11 18:59:59 +03:00
return
2015-08-06 22:37:26 +03:00
}
2016-01-18 15:32:52 +03:00
2019-10-30 20:51:26 +03:00
// LimitAndOffsetSQL return generated SQL with Limit and Offset
func ( s commonDialect ) LimitAndOffsetSQL ( limit , offset interface { } ) ( sql string , err error ) {
2016-06-21 06:13:33 +03:00
if limit != nil {
2019-12-05 18:13:54 +03:00
if parsedLimit , err := s . parseInt ( limit ) ; err != nil {
2019-10-30 20:51:26 +03:00
return "" , err
2019-12-05 18:13:54 +03:00
} else if parsedLimit >= 0 {
2016-06-21 06:13:33 +03:00
sql += fmt . Sprintf ( " LIMIT %d" , parsedLimit )
2016-02-15 12:00:28 +03:00
}
2016-06-21 06:13:33 +03:00
}
if offset != nil {
2019-12-05 18:13:54 +03:00
if parsedOffset , err := s . parseInt ( offset ) ; err != nil {
2019-10-30 20:51:26 +03:00
return "" , err
2019-12-05 18:13:54 +03:00
} else if parsedOffset >= 0 {
2016-06-21 06:13:33 +03:00
sql += fmt . Sprintf ( " OFFSET %d" , parsedOffset )
2016-02-15 12:00:28 +03:00
}
2016-01-18 15:32:52 +03:00
}
return
}
func ( commonDialect ) SelectFromDummyTable ( ) string {
return ""
2019-10-17 17:54:11 +03:00
}
func ( commonDialect ) LastInsertIDOutputInterstitial ( tableName , columnName string , columns [ ] string ) string {
return ""
2016-01-18 15:32:52 +03:00
}
2016-03-07 09:54:20 +03:00
func ( commonDialect ) LastInsertIDReturningSuffix ( tableName , columnName string ) string {
2016-01-19 06:53:53 +03:00
return ""
2016-01-18 15:32:52 +03:00
}
2016-05-22 01:13:26 +03:00
2018-02-12 12:39:34 +03:00
func ( commonDialect ) DefaultValueStr ( ) string {
return "DEFAULT VALUES"
}
2018-02-03 15:27:19 +03:00
// BuildKeyName returns a valid key name (foreign key, index key) for the given table, field and reference
2018-02-02 17:01:31 +03:00
func ( DefaultForeignKeyNamer ) BuildKeyName ( kind , tableName string , fields ... string ) string {
keyName := fmt . Sprintf ( "%s_%s_%s" , kind , tableName , strings . Join ( fields , "_" ) )
2019-04-15 11:46:50 +03:00
keyName = keyNameRegex . ReplaceAllString ( keyName , "_" )
2016-05-22 01:13:26 +03:00
return keyName
}
2017-04-19 10:21:56 +03:00
2019-04-15 11:46:50 +03:00
// NormalizeIndexAndColumn returns argument's index name and column name without doing anything
func ( commonDialect ) NormalizeIndexAndColumn ( indexName , columnName string ) ( string , string ) {
return indexName , columnName
}
2019-10-30 20:51:26 +03:00
func ( commonDialect ) parseInt ( value interface { } ) ( int64 , error ) {
return strconv . ParseInt ( fmt . Sprint ( value ) , 0 , 0 )
}
2017-04-19 10:21:56 +03:00
// IsByteArrayOrSlice returns true of the reflected value is an array or slice
func IsByteArrayOrSlice ( value reflect . Value ) bool {
return ( value . Kind ( ) == reflect . Array || value . Kind ( ) == reflect . Slice ) && value . Type ( ) . Elem ( ) == reflect . TypeOf ( uint8 ( 0 ) )
}