From 57c10046c0f5b4966db36a699d7283a12d0e00d1 Mon Sep 17 00:00:00 2001 From: joe Date: Fri, 10 Jun 2022 09:09:43 +0800 Subject: [PATCH] display time offset --- logger/sql.go | 31 +++++++++++++++---------------- logger/sql_test.go | 31 +++++++++++++++++++++++-------- tests/sql_builder_test.go | 8 ++++---- 3 files changed, 42 insertions(+), 28 deletions(-) diff --git a/logger/sql.go b/logger/sql.go index c8b194c3c..80989695c 100644 --- a/logger/sql.go +++ b/logger/sql.go @@ -14,7 +14,7 @@ import ( ) const ( - tmFmtWithMS = "2006-01-02 15:04:05.999" + tmFmtWithMS = "2006-01-02 15:04:05.999 Z0700" tmFmtZero = "0000-00-00 00:00:00" nullStr = "NULL" ) @@ -30,7 +30,7 @@ func isPrintable(s string) bool { var convertibleTypes = []reflect.Type{reflect.TypeOf(time.Time{}), reflect.TypeOf(false), reflect.TypeOf([]byte{})} -// ExplainSQL generate SQL string with given parameters, the generated SQL is expected to be used in logger, execute it might introduce a SQL injection vulnerability +// ExplainSQL generate SQL strings with given parameters, the generated SQL is expected to be used in logger, execute it might introduce a SQL injection vulnerability func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, avars ...interface{}) string { var ( convertParams func(interface{}, int) @@ -42,21 +42,9 @@ func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, a case bool: vars[idx] = strconv.FormatBool(v) case time.Time: - if v.IsZero() { - vars[idx] = escaper + tmFmtZero + escaper - } else { - vars[idx] = escaper + v.Format(tmFmtWithMS) + escaper - } + vars[idx] = formatTime(&v, escaper) case *time.Time: - if v != nil { - if v.IsZero() { - vars[idx] = escaper + tmFmtZero + escaper - } else { - vars[idx] = escaper + v.Format(tmFmtWithMS) + escaper - } - } else { - vars[idx] = nullStr - } + vars[idx] = formatTime(v, escaper) case driver.Valuer: reflectValue := reflect.ValueOf(v) if v != nil && reflectValue.IsValid() && ((reflectValue.Kind() == reflect.Ptr && !reflectValue.IsNil()) || reflectValue.Kind() != reflect.Ptr) { @@ -145,3 +133,14 @@ func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, a return sql } + +func formatTime(v *time.Time, escaper string) string { + if v == nil { + return nullStr + } + if v.IsZero() { + return escaper + tmFmtZero + escaper + } else { + return escaper + v.Format(tmFmtWithMS) + escaper + } +} diff --git a/logger/sql_test.go b/logger/sql_test.go index c5b181a9c..10347342c 100644 --- a/logger/sql_test.go +++ b/logger/sql_test.go @@ -7,6 +7,7 @@ import ( "regexp" "strings" "testing" + "time" "github.com/jinzhu/now" "gorm.io/gorm/logger" @@ -38,7 +39,9 @@ func TestExplainSQL(t *testing.T) { type role string type password []byte var ( - tt = now.MustParse("2020-02-23 11:10:10") + tt = now.MustParseInLocation(time.UTC, "2020-02-23 11:10:10") + pst, _ = time.LoadLocation("America/Los_Angeles") + est, _ = time.LoadLocation("America/New_York") myrole = role("admin") pwd = password([]byte("pass")) jsVal = []byte(`{"Name":"test","Val":"test"}`) @@ -57,43 +60,55 @@ func TestExplainSQL(t *testing.T) { SQL: "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", NumericRegexp: nil, Vars: []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd}, - Result: `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass")`, + Result: `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10 Z", "2020-02-23 11:10:10 Z", NULL, "w@g.\"com", "admin", "pass")`, }, { SQL: "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", NumericRegexp: nil, Vars: []interface{}{"jinzhu?", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd}, - Result: `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu?", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass")`, + Result: `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu?", 1, 999.990000, true, "12345", "2020-02-23 11:10:10 Z", "2020-02-23 11:10:10 Z", NULL, "w@g.\"com", "admin", "pass")`, }, { SQL: "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values (@p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11)", NumericRegexp: regexp.MustCompile(`@p(\d+)`), Vars: []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.com", myrole, pwd}, - Result: `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.com", "admin", "pass")`, + Result: `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10 Z", "2020-02-23 11:10:10 Z", NULL, "w@g.com", "admin", "pass")`, }, { SQL: "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ($3, $4, $1, $2, $7, $8, $5, $6, $9, $10, $11)", NumericRegexp: regexp.MustCompile(`\$(\d+)`), Vars: []interface{}{999.99, true, "jinzhu", 1, &tt, nil, []byte("12345"), tt, "w@g.com", myrole, pwd}, - Result: `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.com", "admin", "pass")`, + Result: `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10 Z", "2020-02-23 11:10:10 Z", NULL, "w@g.com", "admin", "pass")`, }, { SQL: "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values (@p1, @p11, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10)", NumericRegexp: regexp.MustCompile(`@p(\d+)`), Vars: []interface{}{"jinzhu", 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.com", myrole, pwd, 1}, - Result: `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.com", "admin", "pass")`, + Result: `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10 Z", "2020-02-23 11:10:10 Z", NULL, "w@g.com", "admin", "pass")`, }, { SQL: "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", NumericRegexp: nil, Vars: []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd, js, es}, - Result: fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)), + Result: fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10 Z", "2020-02-23 11:10:10 Z", NULL, "w@g.\"com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)), }, { SQL: "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", NumericRegexp: nil, Vars: []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd, &js, &es}, - Result: fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)), + Result: fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10 Z", "2020-02-23 11:10:10 Z", NULL, "w@g.\"com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)), + }, + { + SQL: "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + NumericRegexp: nil, + Vars: []interface{}{"jinzhu?", 1, 999.99, true, []byte("12345"), tt.In(pst), &tt, nil, "w@g.\"com", myrole, pwd}, + Result: `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu?", 1, 999.990000, true, "12345", "2020-02-23 03:10:10 -0800", "2020-02-23 11:10:10 Z", NULL, "w@g.\"com", "admin", "pass")`, + }, + { + SQL: "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + NumericRegexp: nil, + Vars: []interface{}{"jinzhu?", 1, 999.99, true, []byte("12345"), tt.In(est), &tt, nil, "w@g.\"com", myrole, pwd}, + Result: `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu?", 1, 999.990000, true, "12345", "2020-02-23 06:10:10 -0500", "2020-02-23 11:10:10 Z", NULL, "w@g.\"com", "admin", "pass")`, }, } diff --git a/tests/sql_builder_test.go b/tests/sql_builder_test.go index a9b920dcc..988506178 100644 --- a/tests/sql_builder_test.go +++ b/tests/sql_builder_test.go @@ -403,7 +403,7 @@ func TestToSQL(t *testing.T) { sql = DB.ToSQL(func(tx *gorm.DB) *gorm.DB { return tx.Model(&User{}).Create(user) }) - assertEqualSQL(t, `INSERT INTO "users" ("created_at","updated_at","deleted_at","name","age","birthday","company_id","manager_id","active") VALUES ('2021-10-18 00:00:00','2021-10-18 00:00:00',NULL,'foo',20,NULL,NULL,NULL,false) RETURNING "id"`, sql) + assertEqualSQL(t, `INSERT INTO "users" ("created_at","updated_at","deleted_at","name","age","birthday","company_id","manager_id","active") VALUES ('2021-10-18 00:00:00 Z','2021-10-18 00:00:00 Z',NULL,'foo',20,NULL,NULL,NULL,false) RETURNING "id"`, sql) // save user = &User{Name: "foo", Age: 20} @@ -412,7 +412,7 @@ func TestToSQL(t *testing.T) { sql = DB.ToSQL(func(tx *gorm.DB) *gorm.DB { return tx.Model(&User{}).Save(user) }) - assertEqualSQL(t, `INSERT INTO "users" ("created_at","updated_at","deleted_at","name","age","birthday","company_id","manager_id","active") VALUES ('2021-10-18 00:00:00','2021-10-18 00:00:00',NULL,'foo',20,NULL,NULL,NULL,false) RETURNING "id"`, sql) + assertEqualSQL(t, `INSERT INTO "users" ("created_at","updated_at","deleted_at","name","age","birthday","company_id","manager_id","active") VALUES ('2021-10-18 00:00:00 Z','2021-10-18 00:00:00 Z',NULL,'foo',20,NULL,NULL,NULL,false) RETURNING "id"`, sql) // updates user = &User{Name: "bar", Age: 22} @@ -421,13 +421,13 @@ func TestToSQL(t *testing.T) { sql = DB.ToSQL(func(tx *gorm.DB) *gorm.DB { return tx.Model(&User{}).Where("id = ?", 100).Updates(user) }) - assertEqualSQL(t, `UPDATE "users" SET "created_at"='2021-10-18 00:00:00',"updated_at"='2021-10-18 19:50:09.438',"name"='bar',"age"=22 WHERE id = 100 AND "users"."deleted_at" IS NULL`, sql) + assertEqualSQL(t, `UPDATE "users" SET "created_at"='2021-10-18 00:00:00 Z',"updated_at"='2021-10-18 19:50:09.438 Z',"name"='bar',"age"=22 WHERE id = 100 AND "users"."deleted_at" IS NULL`, sql) // update sql = DB.ToSQL(func(tx *gorm.DB) *gorm.DB { return tx.Model(&User{}).Where("id = ?", 100).Update("name", "Foo bar") }) - assertEqualSQL(t, `UPDATE "users" SET "name"='Foo bar',"updated_at"='2021-10-18 19:50:09.438' WHERE id = 100 AND "users"."deleted_at" IS NULL`, sql) + assertEqualSQL(t, `UPDATE "users" SET "name"='Foo bar',"updated_at"='2021-10-18 19:50:09.438 Z' WHERE id = 100 AND "users"."deleted_at" IS NULL`, sql) // UpdateColumn sql = DB.ToSQL(func(tx *gorm.DB) *gorm.DB {