From 896b9fa105c6c802f6b83d064b80e8544593af68 Mon Sep 17 00:00:00 2001 From: houseme Date: Thu, 19 May 2022 23:33:04 +0800 Subject: [PATCH 1/3] [ISSUE #1866] Fix/polaris logs dir and docker image (#1867) * feat:modify polaris log dir * modify polaris image docker * fix: modify polaris docker image --- .github/workflows/gf.yml | 2 +- contrib/registry/polaris/polaris_test.go | 30 ++++++++++++++++++++---- example/registry/polaris/client/main.go | 8 ++++++- example/registry/polaris/server/main.go | 8 +++++++ 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/.github/workflows/gf.yml b/.github/workflows/gf.yml index 5b7f69129..9e5d8c160 100644 --- a/.github/workflows/gf.yml +++ b/.github/workflows/gf.yml @@ -91,7 +91,7 @@ jobs: - 8123:8123 - 9001:9001 polaris: - image: huyuanxin/polaris-server-with-config:latest + image: houseme/polaris-server-with-config:latest ports: - 8090:8090 - 8091:8091 diff --git a/contrib/registry/polaris/polaris_test.go b/contrib/registry/polaris/polaris_test.go index 10e119a1e..842658318 100644 --- a/contrib/registry/polaris/polaris_test.go +++ b/contrib/registry/polaris/polaris_test.go @@ -11,6 +11,7 @@ import ( "testing" "time" + "github.com/polarismesh/polaris-go/api" "github.com/polarismesh/polaris-go/pkg/config" "github.com/gogf/gf/v2/frame/g" @@ -21,7 +22,11 @@ import ( // TestRegistry TestRegistryManyService func TestRegistry(t *testing.T) { conf := config.NewDefaultConfiguration([]string{"127.0.0.1:8091"}) - + conf.Consumer.LocalCache.SetPersistDir("/tmp/polaris/backup") + err := api.SetLoggersDir("/tmp/polaris/log") + if err != nil { + t.Fatal(err) + } r := NewWithConfig( conf, WithTimeout(time.Second*10), @@ -38,7 +43,7 @@ func TestRegistry(t *testing.T) { Separator: instanceIDSeparator, } - err := r.Register(ctx, svc) + err = r.Register(ctx, svc) if err != nil { t.Fatal(err) } @@ -52,6 +57,12 @@ func TestRegistry(t *testing.T) { // TestRegistryMany TestRegistryManyService func TestRegistryMany(t *testing.T) { conf := config.NewDefaultConfiguration([]string{"127.0.0.1:8091"}) + conf.Consumer.LocalCache.SetPersistDir("/tmp/polaris/backup") + + err := api.SetLoggersDir("/tmp/polaris/log") + if err != nil { + t.Fatal(err) + } r := NewWithConfig( conf, @@ -81,7 +92,7 @@ func TestRegistryMany(t *testing.T) { Separator: instanceIDSeparator, } - err := r.Register(context.Background(), svc) + err = r.Register(context.Background(), svc) if err != nil { t.Fatal(err) } @@ -115,6 +126,11 @@ func TestRegistryMany(t *testing.T) { // TestGetService Test GetService func TestGetService(t *testing.T) { conf := config.NewDefaultConfiguration([]string{"127.0.0.1:8091"}) + conf.Consumer.LocalCache.SetPersistDir("/tmp/polaris/backup") + err := api.SetLoggersDir("/tmp/polaris/log") + if err != nil { + t.Fatal(err) + } r := NewWithConfig( conf, @@ -132,7 +148,7 @@ func TestGetService(t *testing.T) { Separator: instanceIDSeparator, } - err := r.Register(ctx, svc) + err = r.Register(ctx, svc) if err != nil { t.Fatal(err) } @@ -161,7 +177,11 @@ func TestGetService(t *testing.T) { // TestWatch Test Watch func TestWatch(t *testing.T) { conf := config.NewDefaultConfiguration([]string{"127.0.0.1:8091"}) - + conf.Consumer.LocalCache.SetPersistDir("/tmp/polaris/backup") + err := api.SetLoggersDir("/tmp/polaris/log") + if err != nil { + t.Fatal(err) + } r := NewWithConfig( conf, WithTimeout(time.Second*10), diff --git a/example/registry/polaris/client/main.go b/example/registry/polaris/client/main.go index 466eb9374..32bd43ac3 100644 --- a/example/registry/polaris/client/main.go +++ b/example/registry/polaris/client/main.go @@ -1,13 +1,14 @@ package main import ( + "context" "fmt" "time" + "github.com/polarismesh/polaris-go/api" "github.com/polarismesh/polaris-go/pkg/config" "github.com/gogf/gf/contrib/registry/polaris/v2" - "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/gsvc" "github.com/gogf/gf/v2/os/gctx" @@ -15,6 +16,11 @@ import ( func main() { conf := config.NewDefaultConfiguration([]string{"192.168.100.222:8091"}) + conf.Consumer.LocalCache.SetPersistDir("/tmp/polaris/backup") + err := api.SetLoggersDir("/tmp/polaris/log") + if err != nil { + g.Log().Fatal(context.Background(), err) + } gsvc.SetRegistry(polaris.NewWithConfig(conf, polaris.WithTTL(100))) diff --git a/example/registry/polaris/server/main.go b/example/registry/polaris/server/main.go index 63608d085..6d277e2dc 100644 --- a/example/registry/polaris/server/main.go +++ b/example/registry/polaris/server/main.go @@ -1,6 +1,9 @@ package main import ( + "context" + + "github.com/polarismesh/polaris-go/api" "github.com/polarismesh/polaris-go/pkg/config" "github.com/gogf/gf/contrib/registry/polaris/v2" @@ -11,6 +14,11 @@ import ( func main() { conf := config.NewDefaultConfiguration([]string{"192.168.100.222:8091"}) + conf.Consumer.LocalCache.SetPersistDir("/tmp/polaris/backup") + err := api.SetLoggersDir("/tmp/polaris/log") + if err != nil { + g.Log().Fatal(context.Background(), err) + } // TTL egt 2*time.Second gsvc.SetRegistry(polaris.NewWithConfig(conf, polaris.WithTTL(100))) From 8c969b2a84c5cafc01cde7ba643687d4f0a13af9 Mon Sep 17 00:00:00 2001 From: Daguang <28806852+DGuang21@users.noreply.github.com> Date: Mon, 23 May 2022 21:21:59 +0800 Subject: [PATCH 2/3] upgrade ClickHouse dependencies to V2 (#1772) --- contrib/drivers/README.md | 3 +- contrib/drivers/clickhouse/clickhouse.go | 217 +++++-- contrib/drivers/clickhouse/clickhouse_test.go | 556 +++++++++++++----- contrib/drivers/clickhouse/go.mod | 9 +- contrib/drivers/clickhouse/go.sum | 50 +- 5 files changed, 648 insertions(+), 187 deletions(-) diff --git a/contrib/drivers/README.md b/contrib/drivers/README.md index 0cee76286..2fd0180c3 100644 --- a/contrib/drivers/README.md +++ b/contrib/drivers/README.md @@ -75,8 +75,7 @@ Note: - It does not support `InsertIgnore/InsertGetId` features. - It does not support `Save/Replace` features. - It does not support `Transaction` feature. -- It does not support `Transaction` feature. - +- It does not support `RowsAffected` feature. # Custom Drivers diff --git a/contrib/drivers/clickhouse/clickhouse.go b/contrib/drivers/clickhouse/clickhouse.go index 0af84eaea..a5cc60794 100644 --- a/contrib/drivers/clickhouse/clickhouse.go +++ b/contrib/drivers/clickhouse/clickhouse.go @@ -10,19 +10,23 @@ package clickhouse import ( "context" "database/sql" + "database/sql/driver" "errors" "fmt" - "strings" - - "github.com/ClickHouse/clickhouse-go" - + "github.com/ClickHouse/clickhouse-go/v2" "github.com/gogf/gf/v2/container/gmap" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/os/gctx" + "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/text/gregex" "github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/util/gconv" + "github.com/google/uuid" + "net/url" + "strings" + "time" ) // Driver is the driver for postgresql database. @@ -32,13 +36,23 @@ type Driver struct { var ( // tableFieldsMap caches the table information retrieved from database. - tableFieldsMap = gmap.New(true) - errUnsupportedInsertIgnore = errors.New("unsupported method: InsertIgnore") - errUnsupportedInsertGetId = errors.New("unsupported method: InsertGetId") - errUnsupportedReplace = errors.New("unsupported method: Replace") - errUnsupportedBegin = errors.New("unsupported method: Begin") - errUnsupportedTransaction = errors.New("unsupported method: Transaction") - errSQLNull = errors.New("SQL cannot be null") + tableFieldsMap = gmap.New(true) + + errUnsupportedInsertIgnore = errors.New("unsupported method:InsertIgnore") + errUnsupportedInsertGetId = errors.New("unsupported method:InsertGetId") + errUnsupportedReplace = errors.New("unsupported method:Replace") + errUnsupportedBegin = errors.New("unsupported method:Begin") + errUnsupportedTransaction = errors.New("unsupported method:Transaction") +) + +const ( + updateFilterPattern = `(?i)UPDATE[\s]+?(\w+[\.]?\w+)[\s]+?SET` + deleteFilterPattern = `(?i)DELETE[\s]+?FROM[\s]+?(\w+[\.]?\w+)` + filterTypePattern = `(?i)^UPDATE|DELETE` + replaceSchemaPattern = `@(.+?)/([\w\.\-]+)+` + needParsedSqlInCtx gctx.StrKey = "NeedParsedSql" + OrmTagForStruct = "orm" + driverName = "clickhouse" ) func init() { @@ -62,27 +76,28 @@ func (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) { // Open creates and returns an underlying sql.DB object for clickhouse. func (d *Driver) Open(config *gdb.ConfigNode) (*sql.DB, error) { - var ( - source string - driver = "clickhouse" - ) // clickhouse://username:password@host1:9000,host2:9000/database?dial_timeout=200ms&max_execution_time=60 if config.Link != "" { - source = config.Link // Custom changing the schema in runtime. if config.Name != "" { - source, _ = gregex.ReplaceString(`@(.+?)/([\w\.\-]+)+`, "@$1/"+config.Name, source) + config.Link, _ = gregex.ReplaceString(replaceSchemaPattern, "@$1/"+config.Name, config.Link) + } else { + // If no schema, the link is matched for replacement + dbName, _ := gregex.MatchString(replaceSchemaPattern, config.Link) + if len(dbName) > 0 { + config.Name = dbName[len(dbName)-1] + } } } else if config.Pass != "" { - source = fmt.Sprintf( - "clickhouse://%s:%s@%s:%s/%s?charset=%s&debug=%s", - config.User, config.Pass, config.Host, config.Port, config.Name, config.Charset, gconv.String(config.Debug)) + config.Link = fmt.Sprintf( + "clickhouse://%s:%s@%s:%s/%s?charset=%s&debug=%t", + config.User, url.PathEscape(config.Pass), config.Host, config.Port, config.Name, config.Charset, config.Debug) } else { - source = fmt.Sprintf( - "clickhouse://%s@%s:%s/%s?charset=%s&debug=%s", - config.User, config.Host, config.Port, config.Name, config.Charset, gconv.String(config.Debug)) + config.Link = fmt.Sprintf( + "clickhouse://%s@%s:%s/%s?charset=%s&debug=%t", + config.User, config.Host, config.Port, config.Name, config.Charset, config.Debug) } - db, err := sql.Open(driver, source) + db, err := sql.Open(driverName, config.Link) if err != nil { return nil, err } @@ -133,7 +148,7 @@ func (d *Driver) TableFields( if link, err = d.SlaveLink(useSchema); err != nil { return nil } - getColumnsSql := fmt.Sprintf("select name,position,default_expression,comment from `system`.columns c where database = '%s' and `table` = '%s'", d.GetConfig().Name, table) + getColumnsSql := fmt.Sprintf("select name,position,default_expression,comment,type,is_in_partition_key,is_in_sorting_key,is_in_primary_key,is_in_sampling_key from `system`.columns c where database = '%s' and `table` = '%s'", d.GetConfig().Name, table) result, err = d.DoSelect(ctx, link, getColumnsSql) if err != nil { return nil @@ -215,29 +230,55 @@ func (d *Driver) ping(conn *sql.DB) error { func (d *Driver) DoFilter( ctx context.Context, link gdb.Link, originSql string, args []interface{}, ) (newSql string, newArgs []interface{}, err error) { - // It replaces STD SQL to Clickhouse SQL grammar. - // MySQL eg: UPDATE `table` SET xxx - // Clickhouse eg: ALTER TABLE `table` UPDATE xxx - // MySQL eg: DELETE FROM `table` - // Clickhouse eg: ALTER TABLE `table` DELETE WHERE filter_expr - result, err := gregex.MatchString("(?i)^UPDATE|DELETE", originSql) + if len(args) == 0 { + return originSql, args, nil + } + + var index int + // Convert placeholder char '?' to string "$x". + originSql, _ = gregex.ReplaceStringFunc(`\?`, originSql, func(s string) string { + index++ + return fmt.Sprintf(`$%d`, index) + }) + + // Only SQL generated through the framework is processed. + if !d.getNeedParsedSqlFromCtx(ctx) { + return originSql, args, nil + } + + // replace STD SQL to Clickhouse SQL grammar + modeRes, err := gregex.MatchString(filterTypePattern, strings.TrimSpace(originSql)) if err != nil { return "", nil, err } - if len(result) != 0 { - sqlSlice := strings.Split(originSql, " ") - if len(sqlSlice) < 3 { - return "", nil, errSQLNull + if len(modeRes) == 0 { + return originSql, args, nil + } + + // Only delete/ UPDATE statements require filter + switch strings.ToUpper(modeRes[0]) { + case "UPDATE": + // MySQL eg: UPDATE table_name SET field1=new-value1, field2=new-value2 [WHERE Clause] + // Clickhouse eg: ALTER TABLE [db.]table UPDATE column1 = expr1 [, ...] WHERE filter_expr + newSql, err = gregex.ReplaceStringFuncMatch(updateFilterPattern, originSql, func(s []string) string { + return fmt.Sprintf("ALTER TABLE %s UPDATE", s[1]) + }) + if err != nil { + return "", nil, err } - ck := []string{"ALTER", "TABLE"} - switch strings.ToUpper(result[0]) { - case "UPDATE": - sqlSlice = append(append(append(ck, sqlSlice[1]), result[0]), sqlSlice[3:]...) - return strings.Join(sqlSlice, " "), args, nil - case "DELETE": - sqlSlice = append(append(append(ck, sqlSlice[2]), result[0]), sqlSlice[3:]...) - return strings.Join(sqlSlice, " "), args, nil + return newSql, args, nil + + case "DELETE": + // MySQL eg: DELETE FROM table_name [WHERE Clause] + // Clickhouse eg: ALTER TABLE [db.]table [ON CLUSTER cluster] DELETE WHERE filter_expr + newSql, err = gregex.ReplaceStringFuncMatch(deleteFilterPattern, originSql, func(s []string) string { + return fmt.Sprintf("ALTER TABLE %s DELETE", s[1]) + }) + if err != nil { + return "", nil, err } + return newSql, args, nil + } return originSql, args, nil } @@ -295,6 +336,82 @@ func (d *Driver) DoInsert( return stdSqlResult, tx.Commit() } +// ConvertDataForRecord converting for any data that will be inserted into table/collection as a record. +func (d *Driver) ConvertDataForRecord(ctx context.Context, value interface{}) (map[string]interface{}, error) { + m := gconv.Map(value, OrmTagForStruct) + + // transforms a value of a particular type + for k, v := range m { + switch itemValue := v.(type) { + + case time.Time: + m[k] = itemValue + // If the time is zero, it then updates it to nil, + // which will insert/update the value to database as "null". + if itemValue.IsZero() { + m[k] = nil + } + + case uuid.UUID: + m[k] = itemValue + + case *time.Time: + m[k] = itemValue + // If the time is zero, it then updates it to nil, + // which will insert/update the value to database as "null". + if itemValue == nil || itemValue.IsZero() { + m[k] = nil + } + + case gtime.Time: + // for gtime type, needs to get time.Time + m[k] = itemValue.Time + // If the time is zero, it then updates it to nil, + // which will insert/update the value to database as "null". + if itemValue.IsZero() { + m[k] = nil + } + + case *gtime.Time: + // for gtime type, needs to get time.Time + if itemValue != nil { + m[k] = itemValue.Time + } + // If the time is zero, it then updates it to nil, + // which will insert/update the value to database as "null". + if itemValue == nil || itemValue.IsZero() { + m[k] = nil + } + + default: + // if the other type implements valuer for the driver package + // the converted result is used + // otherwise the interface data is committed + valuer, ok := itemValue.(driver.Valuer) + if !ok { + m[k] = itemValue + continue + } + convertedValue, err := valuer.Value() + if err != nil { + return nil, err + } + m[k] = convertedValue + } + } + return m, nil +} + +func (d *Driver) DoDelete(ctx context.Context, link gdb.Link, table string, condition string, args ...interface{}) (result sql.Result, err error) { + ctx = d.injectNeedParsedSql(ctx) + return d.Core.DoDelete(ctx, link, table, condition, args...) +} + +func (d *Driver) DoUpdate(ctx context.Context, link gdb.Link, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) { + ctx = d.injectNeedParsedSql(ctx) + return d.Core.DoUpdate(ctx, link, table, data, condition, args...) +} + // InsertIgnore Other queries for modifying data parts are not supported: REPLACE, MERGE, UPSERT, INSERT UPDATE. func (d *Driver) InsertIgnore(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) { return nil, errUnsupportedInsertIgnore @@ -317,3 +434,17 @@ func (d *Driver) Begin(ctx context.Context) (tx *gdb.TX, err error) { func (d *Driver) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) error { return errUnsupportedTransaction } + +func (d *Driver) injectNeedParsedSql(ctx context.Context) context.Context { + if ctx.Value(needParsedSqlInCtx) != nil { + return ctx + } + return context.WithValue(ctx, needParsedSqlInCtx, true) +} + +func (d *Driver) getNeedParsedSqlFromCtx(ctx context.Context) bool { + if ctx.Value(needParsedSqlInCtx) != nil { + return true + } + return false +} diff --git a/contrib/drivers/clickhouse/clickhouse_test.go b/contrib/drivers/clickhouse/clickhouse_test.go index 3ea9f3cc2..dff6ac3af 100644 --- a/contrib/drivers/clickhouse/clickhouse_test.go +++ b/contrib/drivers/clickhouse/clickhouse_test.go @@ -3,6 +3,10 @@ package clickhouse import ( "context" "fmt" + "github.com/gogf/gf/v2/os/gtime" + "github.com/gogf/gf/v2/util/guid" + "github.com/google/uuid" + "strings" "testing" "time" @@ -13,18 +17,103 @@ import ( "github.com/gogf/gf/v2/util/grand" ) -// table DDL -// CREATE TABLE visits -// ( -// id UInt64, -// duration Float64, -// url String, -// created DateTime -//) -// ENGINE = MergeTree() -// PRIMARY KEY id -// ORDER BY id -func InitClickhouse() gdb.DB { +const ( + sqlVisitsDDL = ` +CREATE TABLE IF NOT EXISTS visits ( +id UInt64, +duration Float64, +url String, +created DateTime +) ENGINE = MergeTree() +PRIMARY KEY id +ORDER BY id +` + dimSqlDDL = ` +CREATE TABLE IF NOT EXISTS dim ( +"code" String COMMENT '编码', +"translation" String COMMENT '译文', +"superior" UInt64 COMMENT '上级ID', +"row_number" UInt16 COMMENT '行号', +"is_active" UInt8 COMMENT '是否激活', +"is_preset" UInt8 COMMENT '是否预置', +"category" String COMMENT '类别', +"tree_path" Array(String) COMMENT '树路径', +"id" UInt64 COMMENT '代理主键ID', +"scd" UInt64 COMMENT '缓慢变化维ID', +"version" UInt64 COMMENT 'Merge版本ID', +"sign" Int8 COMMENT '标识位', +"created_by" UInt64 COMMENT '创建者ID', +"created_at" DateTime64(3,'Asia/Shanghai') COMMENT '创建时间', +"updated_by" UInt64 COMMENT '最后修改者ID', +"updated_at" DateTime64(3,'Asia/Shanghai') COMMENT '最后修改时间', +"updated_tick" UInt16 COMMENT '累计修改次数' +) ENGINE = ReplacingMergeTree("version") +ORDER BY ("id","scd") +COMMENT '会计准则'; +` + dimSqlDML = ` +insert into dim (code, translation, superior, row_number, is_active, is_preset, category, tree_path, id, scd, version, sign, created_by, created_at, updated_by, updated_at, updated_tick) +values ('CN', '{"zh_CN":"中国大陆会计准则","en_US":"Chinese mainland accounting legislation"}', 0, 1, 1, 1, 1, '[''CN'']', 607972403489804288, 0, 0, 0, 607536279118155777, '2017-09-06 00:00:00', 607536279118155777, '2017-09-06 00:00:00', 0), + ('HK', '{"zh_CN":"中国香港会计准则","en_US":"Chinese Hong Kong accounting legislation"}', 0, 2, 1, 1, 1, '[''HK'']', 607972558544834566, 0, 0, 0, 607536279118155777, '2017-09-06 00:00:00', 607536279118155777, '2017-09-06 00:00:00', 0); +` + factSqlDDL = ` +CREATE TABLE IF NOT EXISTS fact ( +"adjustment_level" UInt64 COMMENT '调整层ID', +"data_version" UInt64 COMMENT '数据版本ID', +"accounting_legislation" UInt64 COMMENT '会计准则ID', +"fiscal_year" UInt16 COMMENT '会计年度', +"fiscal_period" UInt8 COMMENT '会计期间', +"fiscal_year_period" UInt32 COMMENT '会计年度期间', +"legal_entity" UInt64 COMMENT '法人主体ID', +"cost_center" UInt64 COMMENT '成本中心ID', +"legal_entity_partner" UInt64 COMMENT '内部关联方ID', +"financial_posting" UInt64 COMMENT '凭证头ID', +"line" UInt16 COMMENT '行号', +"general_ledger_account" UInt64 COMMENT '总账科目ID', +"debit" Decimal64(9) COMMENT '借方金额', +"credit" Decimal64(9) COMMENT '贷方金额', +"transaction_currency" UInt64 COMMENT '交易币种ID', +"debit_tc" Decimal64(9) COMMENT '借方金额(交易币种)', +"credit_tc" Decimal64(9) COMMENT '贷方金额(交易币种)', +"posting_date" Date32 COMMENT '过账日期', +"gc_year" UInt16 COMMENT '公历年', +"gc_quarter" UInt8 COMMENT '公历季', +"gc_month" UInt8 COMMENT '公历月', +"gc_week" UInt8 COMMENT '公历周', +"raw_info" String COMMENT '源信息', +"summary" String COMMENT '摘要', +"id" UInt64 COMMENT '代理主键ID', +"version" UInt64 COMMENT 'Merge版本ID', +"sign" Int8 COMMENT '标识位' +) ENGINE = ReplacingMergeTree("version") +ORDER BY ("adjustment_level","data_version","legal_entity","fiscal_year","fiscal_period","financial_posting","line") +PARTITION BY ("adjustment_level","data_version","legal_entity","fiscal_year","fiscal_period") +COMMENT '数据主表'; +` + factSqlDML = ` +insert into fact (adjustment_level, data_version, accounting_legislation, fiscal_year, fiscal_period, fiscal_year_period, legal_entity, cost_center, legal_entity_partner, financial_posting, line, general_ledger_account, debit, credit, transaction_currency, debit_tc, credit_tc, posting_date, gc_year, gc_quarter, gc_month, gc_week, raw_info, summary, id, version, sign) +values (607970943242866688, 607973669943119880, 607972403489804288, 2022, 3, 202203, 607974511316307985, 0, 607976190010986520, 607996702456025136, 1, 607985607569838111, 8674.39, 0, 607974898261823505, 8674.39, 0, '2022-03-05', 2022, 1, 3, 11, '{}', '摘要', 607992882741121073, 0, 0), + (607970943242866688, 607973669943119880, 607972403489804288, 2022, 4, 202204, 607974511316307985, 0, 607976190010986520, 607993586419503145, 1, 607985607569838111, 9999.88, 0, 607974898261823505, 9999.88, 0, '2022-04-10', 2022, 2, 4, 18, '{}', '摘要', 607996939140599857, 0, 0); +` + expmSqlDDL = ` + CREATE TABLE IF NOT EXISTS data_type ( + Col1 UInt8 COMMENT '列1' + , Col2 Nullable(String) COMMENT '列2' + , Col3 FixedString(3) COMMENT '列3' + , Col4 String COMMENT '列4' + , Col5 Map(String, UInt8) COMMENT '列5' + , Col6 Array(String) COMMENT '列6' + , Col7 Tuple(String, UInt8, Array(Map(String, String))) COMMENT '列7' + , Col8 DateTime COMMENT '列8' + , Col9 UUID COMMENT '列9' + , Col10 DateTime COMMENT '列10' + ) ENGINE = MergeTree() + PRIMARY KEY Col4 + ORDER BY Col4 +` +) + +func clickhouseConfigDB() gdb.DB { connect, err := gdb.New(gdb.ConfigNode{ Host: "127.0.0.1", Port: "9000", @@ -38,135 +127,150 @@ func InitClickhouse() gdb.DB { return connect } -func TestDriverClickhouse_Create(t *testing.T) { - gtest.AssertNil(createClickhouseTable(InitClickhouse())) -} - -func createClickhouseTable(connect gdb.DB) error { - sqlStr := "CREATE TABLE IF NOT EXISTS visits (id UInt64,duration Float64,url String,created DateTime) ENGINE = MergeTree() PRIMARY KEY id ORDER BY id" - _, err := connect.Exec(context.Background(), sqlStr) +func createClickhouseTableVisits(connect gdb.DB) error { + _, err := connect.Exec(context.Background(), sqlVisitsDDL) return err } -func dropClickhouseTable(conn gdb.DB) { +func createClickhouseTableDim(connect gdb.DB) error { + _, err := connect.Exec(context.Background(), dimSqlDDL) + return err +} + +func createClickhouseTableFact(connect gdb.DB) error { + _, err := connect.Exec(context.Background(), factSqlDDL) + return err +} + +func createClickhouseExampleTable(connect gdb.DB) error { + _, err := connect.Exec(context.Background(), expmSqlDDL) + return err +} + +func dropClickhouseTableVisits(conn gdb.DB) { sqlStr := fmt.Sprintf("DROP TABLE IF EXISTS `visits`") _, _ = conn.Exec(context.Background(), sqlStr) } +func dropClickhouseTableDim(conn gdb.DB) { + sqlStr := fmt.Sprintf("DROP TABLE IF EXISTS `dim`") + _, _ = conn.Exec(context.Background(), sqlStr) +} + +func dropClickhouseTableFact(conn gdb.DB) { + sqlStr := fmt.Sprintf("DROP TABLE IF EXISTS `fact`") + _, _ = conn.Exec(context.Background(), sqlStr) +} + +func dropClickhouseExampleTable(conn gdb.DB) { + sqlStr := fmt.Sprintf("DROP TABLE IF EXISTS `data_type`") + _, _ = conn.Exec(context.Background(), sqlStr) +} + +func TestDriverClickhouse_Create(t *testing.T) { + gtest.AssertNil(createClickhouseTableVisits(clickhouseConfigDB())) +} + func TestDriverClickhouse_New(t *testing.T) { - connect := InitClickhouse() + connect := clickhouseConfigDB() gtest.AssertNE(connect, nil) gtest.AssertNil(connect.PingMaster()) gtest.AssertNil(connect.PingSlave()) } +func TestDriverClickhouse_OpenLink_Ping(t *testing.T) { + connect := clickhouseConfigDB() + gtest.AssertNE(connect, nil) + gtest.AssertNil(connect.PingMaster()) +} + func TestDriverClickhouse_Tables(t *testing.T) { - connect := InitClickhouse() - gtest.AssertEQ(createClickhouseTable(connect), nil) - defer dropClickhouseTable(connect) + connect := clickhouseConfigDB() + gtest.AssertEQ(createClickhouseTableVisits(connect), nil) + defer dropClickhouseTableVisits(connect) tables, err := connect.Tables(context.Background()) gtest.AssertNil(err) gtest.AssertNE(len(tables), 0) } +func TestDriverClickhouse_TableFields_Use_Config(t *testing.T) { + connect := clickhouseConfigDB() + gtest.AssertNil(createClickhouseTableVisits(connect)) + defer dropClickhouseTableVisits(connect) + field, err := connect.TableFields(context.Background(), "visits") + gtest.AssertNil(err) + gtest.AssertEQ(len(field), 4) + gtest.AssertNQ(field, nil) +} + +func TestDriverClickhouse_TableFields_Use_Link(t *testing.T) { + connect := clickhouseConfigDB() + gtest.AssertNil(createClickhouseTableVisits(connect)) + defer dropClickhouseTableVisits(connect) + field, err := connect.TableFields(context.Background(), "visits") + gtest.AssertNil(err) + gtest.AssertEQ(len(field), 4) + gtest.AssertNQ(field, nil) +} + func TestDriverClickhouse_Transaction(t *testing.T) { - connect := InitClickhouse() - defer dropClickhouseTable(connect) + connect := clickhouseConfigDB() + defer dropClickhouseTableVisits(connect) gtest.AssertNE(connect.Transaction(context.Background(), func(ctx context.Context, tx *gdb.TX) error { return nil }), nil) } -func TestDriverClickhouse_DoDelete(t *testing.T) { - connect := InitClickhouse() - gtest.AssertEQ(createClickhouseTable(connect), nil) - defer dropClickhouseTable(connect) - _, err := connect.Model("visits").Where("created >", "2021-01-01 00:00:00").Delete() - gtest.AssertNil(err) -} - -func TestDriverClickhouse_DoUpdate(t *testing.T) { - connect := InitClickhouse() - gtest.AssertEQ(createClickhouseTable(connect), nil) - defer dropClickhouseTable(connect) - _, err := connect.Model("visits").Where("created > ", "2021-01-01 15:15:15").Data(g.Map{ - "created": time.Now().Format("2006-01-02 15:04:05"), - }).Update() - gtest.AssertNil(err) - _, err = connect.Model("visits").Data(g.Map{ - "created": time.Now().Format("2006-01-02 15:04:05"), - }).Update() - gtest.AssertNE(err, nil) - _, err = connect.Model("visits").Update() - gtest.AssertNE(err, nil) -} - -func TestDriverClickhouse_Select(t *testing.T) { - connect := InitClickhouse() - gtest.AssertEQ(createClickhouseTable(connect), nil) - defer dropClickhouseTable(connect) - data, err := connect.Model("visits").All() - gtest.AssertNil(err) - gtest.AssertEQ(len(data), 0) -} - -func TestDriver_InsertIgnore(t *testing.T) { - connect := InitClickhouse() +func TestDriverClickhouse_InsertIgnore(t *testing.T) { + connect := clickhouseConfigDB() _, err := connect.InsertIgnore(context.Background(), "", nil) gtest.AssertEQ(err, errUnsupportedInsertIgnore) } -func TestDriver_InsertAndGetId(t *testing.T) { - connect := InitClickhouse() +func TestDriverClickhouse_InsertAndGetId(t *testing.T) { + connect := clickhouseConfigDB() _, err := connect.InsertAndGetId(context.Background(), "", nil) gtest.AssertEQ(err, errUnsupportedInsertGetId) } -func TestDriver_Replace(t *testing.T) { - connect := InitClickhouse() - _, err := connect.Replace(context.Background(), "", nil) - gtest.AssertEQ(err, errUnsupportedReplace) -} - -func TestDriverClickhouse_DoInsertOne(t *testing.T) { - connect := InitClickhouse() - gtest.AssertEQ(createClickhouseTable(connect), nil) - defer dropClickhouseTable(connect) +func TestDriverClickhouse_InsertOne(t *testing.T) { + connect := clickhouseConfigDB() + gtest.AssertEQ(createClickhouseTableVisits(connect), nil) + defer dropClickhouseTableVisits(connect) _, err := connect.Model("visits").Data(g.Map{ - "id": grand.Intn(999), "duration": float64(grand.Intn(999)), "url": gconv.String(grand.Intn(999)), - "created": time.Now().Format("2006-01-02 15:04:05"), + "created": time.Now(), }).Insert() gtest.AssertNil(err) } -func TestDriver_DoInsertMany(t *testing.T) { - connect := InitClickhouse() - gtest.AssertEQ(createClickhouseTable(connect), nil) - defer dropClickhouseTable(connect) +func TestDriverClickhouse_InsertMany(t *testing.T) { + connect := clickhouseConfigDB() + gtest.AssertEQ(createClickhouseTableVisits(connect), nil) + defer dropClickhouseTableVisits(connect) tx, err := connect.Begin(context.Background()) gtest.AssertEQ(err, errUnsupportedBegin) gtest.AssertNil(tx) } -func TestDriverClickhouse_DoInsert(t *testing.T) { - connect := InitClickhouse() - gtest.AssertEQ(createClickhouseTable(connect), nil) +func TestDriverClickhouse_Insert(t *testing.T) { + connect := clickhouseConfigDB() + gtest.AssertEQ(createClickhouseTableVisits(connect), nil) + defer dropClickhouseTableVisits(connect) type insertItem struct { - Id int `orm:"id"` - Duration float64 `orm:"duration"` - Url string `orm:"url"` - Created string `orm:"created"` + Id uint64 `orm:"id"` + Duration float64 `orm:"duration"` + Url string `orm:"url"` + Created time.Time `orm:"created"` } var ( insertUrl = "https://goframe.org" total = 0 item = insertItem{ - Id: 0, Duration: 1, Url: insertUrl, - Created: time.Now().Format("2006-01-02 15:04:05"), + Created: time.Now(), } ) _, err := connect.Model("visits").Data(item).Insert() @@ -176,13 +280,12 @@ func TestDriverClickhouse_DoInsert(t *testing.T) { total, err = connect.Model("visits").Count() gtest.AssertNil(err) gtest.AssertEQ(total, 2) - list := []*insertItem{} + var list []*insertItem for i := 0; i < 50; i++ { list = append(list, &insertItem{ - Id: grand.Intn(999), Duration: float64(grand.Intn(999)), Url: insertUrl, - Created: time.Now().Format("2006-01-02 15:04:05"), + Created: time.Now(), }) } _, err = connect.Model("visits").Data(list).Insert() @@ -192,63 +295,248 @@ func TestDriverClickhouse_DoInsert(t *testing.T) { total, err = connect.Model("visits").Count() gtest.AssertNil(err) gtest.AssertEQ(total, 102) - dropClickhouseTable(connect) } -func TestDriverClickhouse_DoExec(t *testing.T) { - connect := InitClickhouse() - gtest.AssertNil(createClickhouseTable(connect)) - defer dropClickhouseTable(connect) +func TestDriverClickhouse_Insert_Use_Exec(t *testing.T) { + connect := clickhouseConfigDB() + gtest.AssertEQ(createClickhouseTableFact(connect), nil) + defer dropClickhouseTableFact(connect) + _, err := connect.Exec(context.Background(), factSqlDML) + gtest.AssertNil(err) +} + +func TestDriverClickhouse_Delete(t *testing.T) { + connect := clickhouseConfigDB() + gtest.AssertEQ(createClickhouseTableVisits(connect), nil) + defer dropClickhouseTableVisits(connect) + _, err := connect.Model("visits").Where("created >", "2021-01-01 00:00:00").Delete() + gtest.AssertNil(err) + _, err = connect.Model("visits"). + Where("created >", "2021-01-01 00:00:00"). + Where("duration > ", 0). + Where("url is not null"). + Delete() + gtest.AssertNil(err) +} + +func TestDriverClickhouse_Update(t *testing.T) { + connect := clickhouseConfigDB() + gtest.AssertEQ(createClickhouseTableVisits(connect), nil) + defer dropClickhouseTableVisits(connect) + _, err := connect.Model("visits").Where("created > ", "2021-01-01 15:15:15").Data(g.Map{ + "created": time.Now().Format("2006-01-02 15:04:05"), + }).Update() + gtest.AssertNil(err) + _, err = connect.Model("visits"). + Where("created > ", "2021-01-01 15:15:15"). + Where("duration > ", 0). + Where("url is not null"). + Data(g.Map{ + "created": time.Now().Format("2006-01-02 15:04:05"), + }).Update() +} + +func TestDriverClickhouse_Replace(t *testing.T) { + connect := clickhouseConfigDB() + _, err := connect.Replace(context.Background(), "", nil) + gtest.AssertEQ(err, errUnsupportedReplace) +} + +func TestDriverClickhouse_DoFilter(t *testing.T) { + rawSQL := "select * from visits where 1 = 1" + this := Driver{} + replaceSQL, _, err := this.DoFilter(context.Background(), nil, rawSQL, []interface{}{1}) + gtest.AssertNil(err) + gtest.AssertEQ(rawSQL, replaceSQL) + + // this SQL can't run ,clickhouse will report an error because there is no WHERE statement + rawSQL = "update visit set url = '1'" + replaceSQL, _, err = this.DoFilter(context.Background(), nil, rawSQL, []interface{}{1}) + gtest.AssertNil(err) + + // this SQL can't run ,clickhouse will report an error because there is no WHERE statement + rawSQL = "delete from visit" + replaceSQL, _, err = this.DoFilter(context.Background(), nil, rawSQL, []interface{}{1}) + gtest.AssertNil(err) + + ctx := this.injectNeedParsedSql(context.Background()) + rawSQL = "UPDATE visit SET url = '1' WHERE url = '0'" + replaceSQL, _, err = this.DoFilter(ctx, nil, rawSQL, []interface{}{1}) + gtest.AssertNil(err) + gtest.AssertEQ(replaceSQL, "ALTER TABLE visit UPDATE url = '1' WHERE url = '0'") + + rawSQL = "DELETE FROM visit WHERE url = '0'" + replaceSQL, _, err = this.DoFilter(ctx, nil, rawSQL, []interface{}{1}) + gtest.AssertNil(err) + gtest.AssertEQ(replaceSQL, "ALTER TABLE visit DELETE WHERE url = '0'") +} + +func TestDriverClickhouse_Select(t *testing.T) { + connect := clickhouseConfigDB() + gtest.AssertNil(createClickhouseTableVisits(connect)) + defer dropClickhouseTableVisits(connect) + _, err := connect.Model("visits").Data(g.Map{ + "url": "goframe.org", + "duration": float64(1), + }).Insert() + gtest.AssertNil(err) + temp, err := connect.Model("visits").Where("url", "goframe.org").Where("duration >= ", 1).One() + gtest.AssertNil(err) + gtest.AssertEQ(temp.IsEmpty(), false) + _, err = connect.Model("visits").Data(g.Map{ + "url": "goframe.org", + "duration": float64(2), + }).Insert() + gtest.AssertNil(err) + data, err := connect.Model("visits").Where("url", "goframe.org").Where("duration >= ", 1).All() + gtest.AssertNil(err) + gtest.AssertEQ(len(data), 2) +} + +func TestDriverClickhouse_Exec_OPTIMIZE(t *testing.T) { + connect := clickhouseConfigDB() + gtest.AssertNil(createClickhouseTableVisits(connect)) + defer dropClickhouseTableVisits(connect) sqlStr := "OPTIMIZE table visits" _, err := connect.Exec(context.Background(), sqlStr) gtest.AssertNil(err) } -func TestDriver_DoFilter(t *testing.T) { - rawSQL := "select * from visits where 1 = 1" - this := Driver{} - replaceSQL, _, err := this.DoFilter(nil, nil, rawSQL, nil) +func TestDriverClickhouse_ExecInsert(t *testing.T) { + connect := clickhouseConfigDB() + gtest.AssertEQ(createClickhouseTableDim(connect), nil) + defer dropClickhouseTableDim(connect) + _, err := connect.Exec(context.Background(), dimSqlDML) gtest.AssertNil(err) - gtest.AssertEQ(rawSQL, replaceSQL) - rawSQL = "update visit set url = '1'" - replaceSQL, _, err = this.DoFilter(nil, nil, rawSQL, nil) - gtest.AssertNil(err) - // this SQL can't run ,clickhouse will report an error because there is no WHERE statement - gtest.AssertEQ(replaceSQL, "ALTER TABLE visit update url = '1'") - rawSQL = "delete from visit" - replaceSQL, _, err = this.DoFilter(nil, nil, rawSQL, nil) - gtest.AssertNil(err) - // this SQL can't run ,clickhouse will report an error because there is no WHERE statement - gtest.AssertEQ(replaceSQL, "ALTER TABLE visit delete") - - rawSQL = "update visit set url = '1' where url = '0'" - replaceSQL, _, err = this.DoFilter(nil, nil, rawSQL, nil) - gtest.AssertNil(err) - // this SQL can't run ,clickhouse will report an error because there is no WHERE statement - gtest.AssertEQ(replaceSQL, "ALTER TABLE visit update url = '1' where url = '0'") - rawSQL = "delete from visit where url='0'" - replaceSQL, _, err = this.DoFilter(nil, nil, rawSQL, nil) - gtest.AssertNil(err) - // this SQL can't run ,clickhouse will report an error because there is no WHERE statement - gtest.AssertEQ(replaceSQL, "ALTER TABLE visit delete where url='0'") } -func TestDriver_TableFields(t *testing.T) { - connect := InitClickhouse() - gtest.AssertNil(createClickhouseTable(connect)) - defer dropClickhouseTable(connect) - field, err := connect.TableFields(context.Background(), "visits") +func TestDriverClickhouse_NilTime(t *testing.T) { + connect := clickhouseConfigDB() + gtest.AssertNil(createClickhouseExampleTable(connect)) + defer dropClickhouseExampleTable(connect) + type testNilTime struct { + Col1 uint8 + Col2 string + Col3 string + Col4 string + Col5 map[string]uint8 + Col6 []string + Col7 []interface{} + Col8 *time.Time + Col9 uuid.UUID + Col10 *gtime.Time + } + insertData := []*testNilTime{} + for i := 0; i < 10000; i++ { + insertData = append(insertData, &testNilTime{ + Col4: "Inc.", + Col9: uuid.New(), + Col7: []interface{}{ // Tuple(String, UInt8, Array(Map(String, String))) + "String Value", uint8(5), []map[string]string{ + map[string]string{"key": "value"}, + map[string]string{"key": "value"}, + map[string]string{"key": "value"}, + }}, + }) + } + _, err := connect.Model("data_type").Data(insertData).Insert() gtest.AssertNil(err) - gtest.AssertEQ(len(field), 4) - gtest.AssertNQ(field, nil) + count, err := connect.Model("data_type").Where("Col4", "Inc.").Count() + gtest.AssertNil(err) + gtest.AssertEQ(count, 10000) } -func TestDriver_OpenLink(t *testing.T) { - connect, err := gdb.New(gdb.ConfigNode{ - Link: "clickhouse://default@127.0.0.1:9000/default?dial_timeout=200ms&max_execution_time=60&skip_verify=true&secure=false&compress=true", +func TestDriverClickhouse_BatchInsert(t *testing.T) { + // example from + // https://github.com/ClickHouse/clickhouse-go/blob/v2/examples/std/batch/main.go + connect := clickhouseConfigDB() + gtest.AssertNil(createClickhouseExampleTable(connect)) + defer dropClickhouseExampleTable(connect) + insertData := []g.Map{} + for i := 0; i < 10000; i++ { + insertData = append(insertData, g.Map{ + "Col1": uint8(42), + "Col2": "ClickHouse", + "Col3": "Inc", + "Col4": guid.S(), + "Col5": map[string]uint8{"key": 1}, // Map(String, UInt8) + "Col6": []string{"Q", "W", "E", "R", "T", "Y"}, // Array(String) + "Col7": []interface{}{ // Tuple(String, UInt8, Array(Map(String, String))) + "String Value", uint8(5), []map[string]string{ + map[string]string{"key": "value"}, + map[string]string{"key": "value"}, + map[string]string{"key": "value"}, + }, + }, + "Col8": gtime.Now(), + "Col9": uuid.New(), + "Col10": nil, + }) + } + _, err := connect.Model("data_type").Data(insertData).Insert() + gtest.AssertNil(err) + count, err := connect.Model("data_type").Where("Col2", "ClickHouse").Where("Col3", "Inc").Count() + gtest.AssertNil(err) + gtest.AssertEQ(count, 10000) +} + +func TestDriverClickhouse_Open(t *testing.T) { + // link + // DSM + // clickhouse://username:password@host1:9000,host2:9000/database?dial_timeout=200ms&max_execution_time=60 + link := "clickhouse://default@127.0.0.1:9000,127.0.0.1:9000/default?dial_timeout=200ms&max_execution_time=60" + db, err := gdb.New(gdb.ConfigNode{ + Link: link, Type: "clickhouse", }) gtest.AssertNil(err) - gtest.AssertNE(connect, nil) - gtest.AssertNil(connect.PingMaster()) + gtest.AssertNil(db.PingMaster()) +} + +func TestDriverClickhouse_ReplaceConfig(t *testing.T) { + db := &Driver{} + // parse link's name set to config + c1 := &gdb.ConfigNode{} + c1.Link = "clickhouse://default@127.0.0.1:9000,127.0.0.1:9000/default?dial_timeout=200ms&max_execution_time=60" + _, _ = db.Open(c1) + gtest.AssertEQ(c1.Name, "default") + // replace link's name from config + c2 := &gdb.ConfigNode{} + c2.Name = "clickhouseJohn" + c2.Link = "clickhouse://default@127.0.0.1:9000,127.0.0.1:9000/default?dial_timeout=200ms&max_execution_time=60" + _, _ = db.Open(c2) + gtest.AssertEQ(strings.Contains(c2.Link, "clickhouseJohn"), true) +} + +func TestDriverClickhouse_TableFields(t *testing.T) { + connect := clickhouseConfigDB() + gtest.AssertNil(createClickhouseExampleTable(connect)) + defer dropClickhouseExampleTable(connect) + dataTypeTable, err := connect.TableFields(context.Background(), "data_type") + gtest.AssertNil(err) + gtest.AssertNE(dataTypeTable, nil) + + var result = map[string][]interface{}{ + "Col1": {1, "Col1", "UInt8", false, "", "", "", "列1"}, + "Col2": {2, "Col2", "String", true, "", "", "", "列2"}, + "Col3": {3, "Col3", "FixedString(3)", false, "", "", "", "列3"}, + "Col4": {4, "Col4", "String", false, "", "", "", "列4"}, + "Col5": {5, "Col5", "Map(String, UInt8)", false, "", "", "", "列5"}, + "Col6": {6, "Col6", "Array(String)", false, "", "", "", "列6"}, + "Col7": {7, "Col7", "Tuple(String, UInt8, Array(Map(String, String)))", false, "", "", "", "列7"}, + "Col8": {8, "Col8", "DateTime", false, "", "", "", "列8"}, + "Col9": {9, "Col9", "UUID", false, "", "", "", "列9"}, + "Col10": {10, "Col10", "DateTime", false, "", "", "", "列10"}, + } + for k, v := range result { + _, ok := dataTypeTable[k] + gtest.AssertEQ(ok, true) + gtest.AssertEQ(dataTypeTable[k].Index, v[0]) + gtest.AssertEQ(dataTypeTable[k].Name, v[1]) + gtest.AssertEQ(dataTypeTable[k].Type, v[2]) + gtest.AssertEQ(dataTypeTable[k].Null, v[3]) + gtest.AssertEQ(dataTypeTable[k].Key, v[4]) + gtest.AssertEQ(dataTypeTable[k].Default, v[5]) + gtest.AssertEQ(dataTypeTable[k].Comment, v[7]) + } } diff --git a/contrib/drivers/clickhouse/go.mod b/contrib/drivers/clickhouse/go.mod index 4fd91373a..dc2dbc48d 100644 --- a/contrib/drivers/clickhouse/go.mod +++ b/contrib/drivers/clickhouse/go.mod @@ -3,8 +3,13 @@ module github.com/gogf/gf/contrib/drivers/clickhouse/v2 go 1.15 require ( - github.com/ClickHouse/clickhouse-go v1.5.2 + github.com/ClickHouse/clickhouse-go/v2 v2.0.14 github.com/gogf/gf/v2 v2.0.0 + github.com/google/uuid v1.3.0 + github.com/mattn/go-isatty v0.0.14 // indirect ) -replace github.com/gogf/gf/v2 => ../../../ +replace ( + github.com/ClickHouse/clickhouse-go/v2 => github.com/gogf/clickhouse-go/v2 v2.0.14-compatible + github.com/gogf/gf/v2 => ../../../ +) diff --git a/contrib/drivers/clickhouse/go.sum b/contrib/drivers/clickhouse/go.sum index 0b199c3d7..613e1f6e7 100644 --- a/contrib/drivers/clickhouse/go.sum +++ b/contrib/drivers/clickhouse/go.sum @@ -1,8 +1,8 @@ github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/ClickHouse/clickhouse-go v1.5.2 h1:yXgaOZ8WEHrd+okvZXjzulSt1zS33nM4ujfx9lVncl8= -github.com/ClickHouse/clickhouse-go v1.5.2/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI= -github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk= +github.com/ClickHouse/clickhouse-go v1.5.4 h1:cKjXeYLNWVJIx2J1K6H2CqyRmfwVJVY1OV1coaaFcI0= +github.com/ClickHouse/clickhouse-go v1.5.4/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI= +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -11,7 +11,6 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E= github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= -github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg= github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -29,10 +28,15 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gogf/clickhouse-go/v2 v2.0.14-compatible h1:eTT+USRgOZyTXyHyIFzJU+utFUsNVPmrzmQaKS9zdoM= +github.com/gogf/clickhouse-go/v2 v2.0.14-compatible/go.mod h1:NdPxn4Kfffa6Tv14otrFtbV+zH6v2xHVfDf4KICt/0s= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -50,6 +54,10 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0= @@ -57,6 +65,8 @@ github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= @@ -68,6 +78,7 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615/go.mod h1:Ad7oeElCZqA1Ufj0U9/liOF4BtVepxRcTvr2ey7zTvM= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -85,17 +96,32 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/paulmach/orb v0.7.0 h1:l6uxkg+vRU9QJkBHtzvYpkVb09tCIRwnEHbY5MNMNqo= +github.com/paulmach/orb v0.7.0/go.mod h1:FWRlTgl88VI1RBx/MkrwWDRhQ96ctqMCh8boXhmqB/A= +github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY= github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= +github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= +github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= +github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM= go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0= @@ -105,11 +131,13 @@ go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= @@ -118,15 +146,18 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220220014-0732a990476f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -138,8 +169,12 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32 h1:Js08h5hqB5xyWR789+QqueR6sDE8mk+YvpETZ+F6X9Y= +golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba h1:AyHWHCBVlIYI5rgEM3o+1PLd0sLPcIAoaUckGQMaWtw= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -148,7 +183,9 @@ golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 h1:GLw7MR8AfAG2GmGcmVgObF golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -162,8 +199,9 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= From 6aa5c2b2ef7683c63d3f9b9521e58899a52e4446 Mon Sep 17 00:00:00 2001 From: houseme Date: Mon, 23 May 2022 22:09:11 +0800 Subject: [PATCH 3/3] Fix/1748 issues #1748 (#1817) --- .golangci.yml | 2 +- net/ghttp/ghttp_request_param_file.go | 6 ++++ .../ghttp_z_unit_feature_request_file_test.go | 36 +++++++++++++++++++ util/gconv/gconv.go | 4 +-- util/gconv/gconv_scan.go | 1 - util/gutil/gutil.go | 2 +- 6 files changed, 46 insertions(+), 5 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index cb39e8053..af6a88165 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,6 +1,6 @@ ## This file contains all available configuration options ## with their default values. -# + # See https://github.com/golangci/golangci-lint#config-file run: issues-exit-code: 1 #Default diff --git a/net/ghttp/ghttp_request_param_file.go b/net/ghttp/ghttp_request_param_file.go index 3e1b33966..d32ea9c71 100644 --- a/net/ghttp/ghttp_request_param_file.go +++ b/net/ghttp/ghttp_request_param_file.go @@ -16,6 +16,7 @@ import ( "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/internal/intlog" + "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/os/gfile" "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/grand" @@ -27,6 +28,11 @@ type UploadFile struct { ctx context.Context } +// MarshalJSON implements the interface MarshalJSON for json.Marshal. +func (f UploadFile) MarshalJSON() ([]byte, error) { + return json.Marshal(f.FileHeader) +} + // UploadFiles is an array type of *UploadFile. type UploadFiles []*UploadFile diff --git a/net/ghttp/ghttp_z_unit_feature_request_file_test.go b/net/ghttp/ghttp_z_unit_feature_request_file_test.go index 53f020045..44dac9815 100644 --- a/net/ghttp/ghttp_z_unit_feature_request_file_test.go +++ b/net/ghttp/ghttp_z_unit_feature_request_file_test.go @@ -216,3 +216,39 @@ func Test_Params_Strict_Route_File_Single(t *testing.T) { t.Assert(gfile.GetContents(dstPath), gfile.GetContents(srcPath)) }) } + +func Test_Params_File_Upload_Required(t *testing.T) { + type Req struct { + gmeta.Meta `method:"post" mime:"multipart/form-data"` + File *ghttp.UploadFile `type:"file" v:"required#upload file is required"` + } + type Res struct{} + + dstDirPath := gfile.Temp(gtime.TimestampNanoStr()) + s := g.Server(guid.S()) + s.BindHandler("/upload/required", func(ctx context.Context, req *Req) (res *Res, err error) { + var ( + r = g.RequestFromCtx(ctx) + ) + + file := req.File + if name, err := file.Save(dstDirPath); err == nil { + r.Response.WriteExit(name) + } + r.Response.WriteExit("upload failed") + return + }) + s.SetDumpRouterMap(false) + s.Start() + defer s.Shutdown() + time.Sleep(100 * time.Millisecond) + // file is empty + gtest.C(t, func(t *gtest.T) { + client := g.Client() + client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())) + _, err := client.Post(ctx, "/upload/required") + if err != nil { + t.Assert(err.Error(), "upload file is required") + } + }) +} diff --git a/util/gconv/gconv.go b/util/gconv/gconv.go index b2de0d507..1b4d753ed 100644 --- a/util/gconv/gconv.go +++ b/util/gconv/gconv.go @@ -79,7 +79,7 @@ func Bytes(any interface{}) []byte { ok = true bytes = make([]byte, originValueAndKind.OriginValue.Len()) ) - for i, _ := range bytes { + for i := range bytes { int32Value := Int32(originValueAndKind.OriginValue.Index(i).Interface()) if int32Value < 0 || int32Value > math.MaxUint8 { ok = false @@ -112,7 +112,7 @@ func Runes(any interface{}) []rune { } // String converts `any` to string. -// It's most commonly used converting function. +// It's most commonly used converting function func String(any interface{}) string { if any == nil { return "" diff --git a/util/gconv/gconv_scan.go b/util/gconv/gconv_scan.go index 426b699e8..fcad56616 100644 --- a/util/gconv/gconv_scan.go +++ b/util/gconv/gconv_scan.go @@ -53,7 +53,6 @@ func Scan(params interface{}, pointer interface{}, mapping ...map[string]string) pointerType, ) } - } // Direct assignment checks! var ( diff --git a/util/gutil/gutil.go b/util/gutil/gutil.go index 09c5046be..c140c2e5b 100644 --- a/util/gutil/gutil.go +++ b/util/gutil/gutil.go @@ -66,7 +66,7 @@ func IsEmpty(value interface{}) bool { func Keys(mapOrStruct interface{}) (keysOrAttrs []string) { keysOrAttrs = make([]string, 0) if m, ok := mapOrStruct.(map[string]interface{}); ok { - for k, _ := range m { + for k := range m { keysOrAttrs = append(keysOrAttrs, k) } return