From 44f5337baef81e4188b399b3b36a01d5b8bbabdb Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Mon, 4 Jul 2022 13:57:36 +0800 Subject: [PATCH] clickhouse < 22.0's columns doesn't support precision, close #54 --- clickhouse.go | 32 +++++++++++++++++++------------- create.go | 5 +---- migrator.go | 14 +++++++++----- migrator_test.go | 4 ++-- 4 files changed, 31 insertions(+), 24 deletions(-) diff --git a/clickhouse.go b/clickhouse.go index f22c981..4153279 100644 --- a/clickhouse.go +++ b/clickhouse.go @@ -18,20 +18,22 @@ import ( ) type Config struct { - DriverName string - DSN string - Conn gorm.ConnPool - DisableDatetimePrecision bool - DontSupportRenameColumn bool - SkipInitializeWithVersion bool - DefaultGranularity int // 1 granule = 8192 rows - DefaultCompression string // default compression algorithm. LZ4 is lossless - DefaultIndexType string // index stores extremes of the expression - DefaultTableEngineOpts string + DriverName string + DSN string + Conn gorm.ConnPool + DisableDatetimePrecision bool + DontSupportRenameColumn bool + DontSupportColumnPrecision bool + SkipInitializeWithVersion bool + DefaultGranularity int // 1 granule = 8192 rows + DefaultCompression string // default compression algorithm. LZ4 is lossless + DefaultIndexType string // index stores extremes of the expression + DefaultTableEngineOpts string } type Dialector struct { *Config + Version string } func Open(dsn string) gorm.Dialector { @@ -86,17 +88,21 @@ func (dialector Dialector) Initialize(db *gorm.DB) (err error) { } if !dialector.SkipInitializeWithVersion { - var vs string - err = db.ConnPool.QueryRowContext(ctx, "SELECT version()").Scan(&vs) + err = db.ConnPool.QueryRowContext(ctx, "SELECT version()").Scan(&dialector.Version) if err != nil { return err } - if dbversion, err := version.NewVersion(vs); err == nil { + if dbversion, err := version.NewVersion(dialector.Version); err == nil { versionNoRenameColumn, _ := version.NewConstraint("< 20.4") if versionNoRenameColumn.Check(dbversion) { dialector.Config.DontSupportRenameColumn = true } + + versionNoPrecisionColumn, _ := version.NewConstraint("< 21.11") + if versionNoPrecisionColumn.Check(dbversion) { + dialector.DontSupportColumnPrecision = true + } } } diff --git a/create.go b/create.go index 0250a77..90bd3ab 100644 --- a/create.go +++ b/create.go @@ -18,7 +18,7 @@ func Create(db *gorm.DB) { db.Statement.SQL.Grow(180) db.Statement.AddClauseIfNotExists(clause.Insert{}) - if values := callbacks.ConvertToCreateValues(db.Statement); len(values.Values) > 1 { + if values := callbacks.ConvertToCreateValues(db.Statement); len(values.Values) >= 1 { prepareValues := clause.Values{ Columns: values.Columns, Values: [][]interface{}{values.Values[0]}, @@ -38,9 +38,6 @@ func Create(db *gorm.DB) { } } return - } else { - db.Statement.AddClause(values) - db.Statement.Build("INSERT", "VALUES", "ON CONFLICT") } } diff --git a/migrator.go b/migrator.go index afca0c5..139e2ca 100644 --- a/migrator.go +++ b/migrator.go @@ -16,7 +16,7 @@ import ( // Errors enumeration var ( - ErrRenameColumnUnsupported = errors.New("renaming column is not supported in your clickhouse version < 20.4.") + ErrRenameColumnUnsupported = errors.New("renaming column is not supported in your clickhouse version < 20.4") ErrRenameIndexUnsupported = errors.New("renaming index is not supported") ErrCreateIndexFailed = errors.New("failed to create index with name") ) @@ -66,10 +66,7 @@ func (m Migrator) FullDataTypeOf(field *schema.Field) (expr clause.Expr) { // NOTE: the codec algo name is case sensitive! if codecstr, ok := field.TagSettings["CODEC"]; ok && codecstr != "" { // parse codec one by one in the codec option - codecSlice := make([]string, 0, 10) - for _, codec := range strings.Split(codecstr, ",") { - codecSlice = append(codecSlice, codec) - } + codecSlice := strings.Split(codecstr, ",") codecArgsSQL := m.Dialector.DefaultCompression if len(codecSlice) > 0 { codecArgsSQL = strings.Join(codecSlice, ",") @@ -302,6 +299,9 @@ func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) { rawColumnTypes, err = rows.ColumnTypes() columnTypeSQL := "SELECT name, type, default_expression, comment, is_in_primary_key, character_octet_length, numeric_precision, numeric_precision_radix, numeric_scale, datetime_precision FROM system.columns WHERE database = ? AND table = ?" + if m.Dialector.DontSupportColumnPrecision { + columnTypeSQL = "SELECT name, type, default_expression, comment, is_in_primary_key FROM system.columns WHERE database = ? AND table = ?" + } columns, rowErr := m.DB.Raw(columnTypeSQL, m.CurrentDatabase(), stmt.Table).Rows() if rowErr != nil { return rowErr @@ -322,6 +322,10 @@ func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) { } ) + if m.Dialector.DontSupportColumnPrecision { + values = []interface{}{&column.NameValue, &column.DataTypeValue, &column.DefaultValueValue, &column.CommentValue, &column.PrimaryKeyValue} + } + if scanErr := columns.Scan(values...); scanErr != nil { return scanErr } diff --git a/migrator_test.go b/migrator_test.go index 12796fc..8212b43 100644 --- a/migrator_test.go +++ b/migrator_test.go @@ -68,11 +68,11 @@ func TestAutoMigrate(t *testing.T) { t.Fatalf("column name default_value should be correct, name: %v, column: %#v", columnType.Name(), columnType) } case "debit": - if decimal, scale, ok := columnType.DecimalSize(); !ok || scale != 0 || decimal != 4 { + if decimal, scale, ok := columnType.DecimalSize(); !ok || (scale != 0 || decimal != 4) { t.Fatalf("column name debit should be correct, name: %v, column: %#v", columnType.Name(), columnType) } case "birthday": - if decimal, scale, ok := columnType.DecimalSize(); !ok || scale != 0 || decimal != 4 { + if decimal, scale, ok := columnType.DecimalSize(); !ok || (scale != 0 || decimal != 4) { t.Fatalf("column name birthday should be correct, name: %v, column: %#v", columnType.Name(), columnType) } }