Select all fields in SQL queries avoiding the SELECT * FROM

This commit is contained in:
Luis Gómez 2020-11-09 14:46:14 -05:00
parent 832abda7a4
commit 5696a223eb
4 changed files with 40 additions and 43 deletions

View File

@ -72,23 +72,13 @@ func BuildQuerySQL(db *gorm.DB) {
} }
} }
} else if db.Statement.Schema != nil && db.Statement.ReflectValue.IsValid() { } else if db.Statement.Schema != nil && db.Statement.ReflectValue.IsValid() {
smallerStruct := false stmt := gorm.Statement{DB: db}
switch db.Statement.ReflectValue.Kind() { // smaller struct
case reflect.Struct: if err := stmt.Parse(db.Statement.Dest); err == nil {
smallerStruct = db.Statement.ReflectValue.Type() != db.Statement.Schema.ModelType clauseSelect.Columns = make([]clause.Column, len(stmt.Schema.DBNames))
case reflect.Slice:
smallerStruct = db.Statement.ReflectValue.Type().Elem() != db.Statement.Schema.ModelType
}
if smallerStruct { for idx, dbName := range stmt.Schema.DBNames {
stmt := gorm.Statement{DB: db} clauseSelect.Columns[idx] = clause.Column{Name: dbName}
// smaller struct
if err := stmt.Parse(db.Statement.Dest); err == nil && stmt.Schema.ModelType != db.Statement.Schema.ModelType {
clauseSelect.Columns = make([]clause.Column, len(stmt.Schema.DBNames))
for idx, dbName := range stmt.Schema.DBNames {
clauseSelect.Columns[idx] = clause.Column{Name: dbName}
}
} }
} }
} }

View File

@ -140,7 +140,7 @@ func TestManyToManyWithCustomizedForeignKeys(t *testing.T) {
} }
if name := DB.Dialector.Name(); name == "postgres" { if name := DB.Dialector.Name(); name == "postgres" {
t.Skip("skip postgers due to it only allow unique constraint matching given keys") t.Skip("skip postgres due to it only allow unique constraint matching given keys")
} }
DB.Migrator().DropTable(&Blog{}, &Tag{}, "blog_tags", "locale_blog_tags", "shared_blog_tags") DB.Migrator().DropTable(&Blog{}, &Tag{}, "blog_tags", "locale_blog_tags", "shared_blog_tags")
@ -265,7 +265,7 @@ func TestManyToManyWithCustomizedForeignKeys2(t *testing.T) {
} }
if name := DB.Dialector.Name(); name == "postgres" { if name := DB.Dialector.Name(); name == "postgres" {
t.Skip("skip postgers due to it only allow unique constraint matching given keys") t.Skip("skip postgres due to it only allow unique constraint matching given keys")
} }
DB.Migrator().DropTable(&Blog{}, &Tag{}, "blog_tags", "locale_blog_tags", "shared_blog_tags") DB.Migrator().DropTable(&Blog{}, &Tag{}, "blog_tags", "locale_blog_tags", "shared_blog_tags")

View File

@ -317,82 +317,86 @@ func TestFillSmallerStruct(t *testing.T) {
result = DB.Session(&gorm.Session{DryRun: true}).Model(&User{}).Find(&User{}, user.ID) result = DB.Session(&gorm.Session{DryRun: true}).Model(&User{}).Find(&User{}, user.ID)
if regexp.MustCompile("SELECT .*name.* FROM .*users").MatchString(result.Statement.SQL.String()) { if regexp.MustCompile("SELECT \\* FROM .*users").MatchString(result.Statement.SQL.String()) {
t.Fatalf("SQL should not include selected names, but got %v", result.Statement.SQL.String()) t.Fatalf("SQL should not include a * wildcard, but got %v", result.Statement.SQL.String())
} }
result = DB.Session(&gorm.Session{DryRun: true}).Model(&User{}).Find(&[]User{}, user.ID) result = DB.Session(&gorm.Session{DryRun: true}).Model(&User{}).Find(&[]User{}, user.ID)
if regexp.MustCompile("SELECT .*name.* FROM .*users").MatchString(result.Statement.SQL.String()) { if regexp.MustCompile("SELECT \\* FROM .*users").MatchString(result.Statement.SQL.String()) {
t.Fatalf("SQL should not include selected names, but got %v", result.Statement.SQL.String()) t.Fatalf("SQL should not include a * wildcard, but got %v", result.Statement.SQL.String())
} }
result = DB.Session(&gorm.Session{DryRun: true}).Model(&User{}).Find(&[]*User{}, user.ID) result = DB.Session(&gorm.Session{DryRun: true}).Model(&User{}).Find(&[]*User{}, user.ID)
if regexp.MustCompile("SELECT .*name.* FROM .*users").MatchString(result.Statement.SQL.String()) { if regexp.MustCompile("SELECT \\* FROM .*users").MatchString(result.Statement.SQL.String()) {
t.Fatalf("SQL should not include selected names, but got %v", result.Statement.SQL.String()) t.Fatalf("SQL should not include a * wildcard, but got %v", result.Statement.SQL.String())
} }
} }
func TestNot(t *testing.T) { func TestNot(t *testing.T) {
dryDB := DB.Session(&gorm.Session{DryRun: true}) dryDB := DB.Session(&gorm.Session{DryRun: true})
userQuery := "SELECT .*id.*created_at.*updated_at.*deleted_at.*name.*age.*birthday.*company_id.*manager_id.*active.* FROM .*users.* "
result := dryDB.Not(map[string]interface{}{"name": "jinzhu"}).Find(&User{}) result := dryDB.Not(map[string]interface{}{"name": "jinzhu"}).Find(&User{})
if !regexp.MustCompile("SELECT \\* FROM .*users.* WHERE .*name.* <> .+").MatchString(result.Statement.SQL.String()) {
if !regexp.MustCompile(userQuery + "WHERE .*name.* <> .+").MatchString(result.Statement.SQL.String()) {
t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String()) t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String())
} }
result = dryDB.Where("name = ?", "jinzhu1").Not("name = ?", "jinzhu2").Find(&User{}) result = dryDB.Where("name = ?", "jinzhu1").Not("name = ?", "jinzhu2").Find(&User{})
if !regexp.MustCompile("SELECT \\* FROM .*users.* WHERE .*name.* = .+ AND NOT.*name.* = .+").MatchString(result.Statement.SQL.String()) { if !regexp.MustCompile(userQuery + "WHERE .*name.* = .+ AND NOT.*name.* = .+").MatchString(result.Statement.SQL.String()) {
t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String()) t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String())
} }
result = dryDB.Where(map[string]interface{}{"name": []string{"jinzhu", "jinzhu 2"}}).Find(&User{}) result = dryDB.Where(map[string]interface{}{"name": []string{"jinzhu", "jinzhu 2"}}).Find(&User{})
if !regexp.MustCompile("SELECT \\* FROM .*users.* WHERE .*name.* IN \\(.+,.+\\)").MatchString(result.Statement.SQL.String()) { if !regexp.MustCompile(userQuery + "WHERE .*name.* IN \\(.+,.+\\)").MatchString(result.Statement.SQL.String()) {
t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String()) t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String())
} }
result = dryDB.Not("name = ?", "jinzhu").Find(&User{}) result = dryDB.Not("name = ?", "jinzhu").Find(&User{})
if !regexp.MustCompile("SELECT \\* FROM .*users.* WHERE NOT.*name.* = .+").MatchString(result.Statement.SQL.String()) { if !regexp.MustCompile(userQuery + "WHERE NOT.*name.* = .+").MatchString(result.Statement.SQL.String()) {
t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String()) t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String())
} }
result = dryDB.Not(map[string]interface{}{"name": []string{"jinzhu", "jinzhu 2"}}).Find(&User{}) result = dryDB.Not(map[string]interface{}{"name": []string{"jinzhu", "jinzhu 2"}}).Find(&User{})
if !regexp.MustCompile("SELECT \\* FROM .*users.* WHERE .*name.* NOT IN \\(.+,.+\\)").MatchString(result.Statement.SQL.String()) { if !regexp.MustCompile(userQuery + "WHERE .*name.* NOT IN \\(.+,.+\\)").MatchString(result.Statement.SQL.String()) {
t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String()) t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String())
} }
result = dryDB.Not([]int64{1, 2}).First(&User{}) result = dryDB.Not([]int64{1, 2}).First(&User{})
if !regexp.MustCompile("SELECT \\* FROM .*users.* WHERE .*id.* NOT IN \\(.+,.+\\)").MatchString(result.Statement.SQL.String()) { if !regexp.MustCompile(userQuery + "WHERE .*id.* NOT IN \\(.+,.+\\)").MatchString(result.Statement.SQL.String()) {
t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String()) t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String())
} }
result = dryDB.Not([]int64{}).First(&User{}) result = dryDB.Not([]int64{}).First(&User{})
if !regexp.MustCompile("SELECT \\* FROM .*users.* WHERE .users.\\..deleted_at. IS NULL ORDER BY").MatchString(result.Statement.SQL.String()) { if !regexp.MustCompile(userQuery + "WHERE .users.\\..deleted_at. IS NULL ORDER BY").MatchString(result.Statement.SQL.String()) {
t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String()) t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String())
} }
result = dryDB.Not(User{Name: "jinzhu", Age: 18}).First(&User{}) result = dryDB.Not(User{Name: "jinzhu", Age: 18}).First(&User{})
if !regexp.MustCompile("SELECT \\* FROM .*users.* WHERE .*users.*..*name.* <> .+ AND .*users.*..*age.* <> .+").MatchString(result.Statement.SQL.String()) { if !regexp.MustCompile(userQuery + "WHERE .*users.*..*name.* <> .+ AND .*users.*..*age.* <> .+").MatchString(result.Statement.SQL.String()) {
t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String()) t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String())
} }
} }
func TestOr(t *testing.T) { func TestOr(t *testing.T) {
dryDB := DB.Session(&gorm.Session{DryRun: true}) dryDB := DB.Session(&gorm.Session{DryRun: true})
userQuery := "SELECT .*id.*created_at.*updated_at.*deleted_at.*name.*age.*birthday.*company_id.*manager_id.*active.* FROM .*users.* "
result := dryDB.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&User{}) result := dryDB.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&User{})
if !regexp.MustCompile("SELECT \\* FROM .*users.* WHERE .*role.* = .+ OR .*role.* = .+").MatchString(result.Statement.SQL.String()) {
if !regexp.MustCompile(userQuery + "WHERE .*role.* = .+ OR .*role.* = .+").MatchString(result.Statement.SQL.String()) {
t.Fatalf("Build OR condition, but got %v", result.Statement.SQL.String()) t.Fatalf("Build OR condition, but got %v", result.Statement.SQL.String())
} }
result = dryDB.Where("name = ?", "jinzhu").Or(User{Name: "jinzhu 2", Age: 18}).Find(&User{}) result = dryDB.Where("name = ?", "jinzhu").Or(User{Name: "jinzhu 2", Age: 18}).Find(&User{})
if !regexp.MustCompile("SELECT \\* FROM .*users.* WHERE .*name.* = .+ OR \\(.*name.* AND .*age.*\\)").MatchString(result.Statement.SQL.String()) { if !regexp.MustCompile(userQuery + "WHERE .*name.* = .+ OR \\(.*name.* AND .*age.*\\)").MatchString(result.Statement.SQL.String()) {
t.Fatalf("Build OR condition, but got %v", result.Statement.SQL.String()) t.Fatalf("Build OR condition, but got %v", result.Statement.SQL.String())
} }
result = dryDB.Where("name = ?", "jinzhu").Or(map[string]interface{}{"name": "jinzhu 2", "age": 18}).Find(&User{}) result = dryDB.Where("name = ?", "jinzhu").Or(map[string]interface{}{"name": "jinzhu 2", "age": 18}).Find(&User{})
if !regexp.MustCompile("SELECT \\* FROM .*users.* WHERE .*name.* = .+ OR \\(.*age.* AND .*name.*\\)").MatchString(result.Statement.SQL.String()) { if !regexp.MustCompile(userQuery + "WHERE .*name.* = .+ OR \\(.*age.* AND .*name.*\\)").MatchString(result.Statement.SQL.String()) {
t.Fatalf("Build OR condition, but got %v", result.Statement.SQL.String()) t.Fatalf("Build OR condition, but got %v", result.Statement.SQL.String())
} }
} }
@ -650,14 +654,15 @@ func TestSearchWithEmptyChain(t *testing.T) {
func TestOrder(t *testing.T) { func TestOrder(t *testing.T) {
dryDB := DB.Session(&gorm.Session{DryRun: true}) dryDB := DB.Session(&gorm.Session{DryRun: true})
userQuery := "SELECT .*id.*created_at.*updated_at.*deleted_at.*name.*age.*birthday.*company_id.*manager_id.*active.* FROM .*users.* "
result := dryDB.Order("age desc, name").Find(&User{}) result := dryDB.Order("age desc, name").Find(&User{})
if !regexp.MustCompile("SELECT \\* FROM .*users.* ORDER BY age desc, name").MatchString(result.Statement.SQL.String()) { if !regexp.MustCompile(userQuery + "ORDER BY age desc, name").MatchString(result.Statement.SQL.String()) {
t.Fatalf("Build Order condition, but got %v", result.Statement.SQL.String()) t.Fatalf("Build Order condition, but got %v", result.Statement.SQL.String())
} }
result = dryDB.Order("age desc").Order("name").Find(&User{}) result = dryDB.Order("age desc").Order("name").Find(&User{})
if !regexp.MustCompile("SELECT \\* FROM .*users.* ORDER BY age desc,name").MatchString(result.Statement.SQL.String()) { if !regexp.MustCompile(userQuery + "ORDER BY age desc,name").MatchString(result.Statement.SQL.String()) {
t.Fatalf("Build Order condition, but got %v", result.Statement.SQL.String()) t.Fatalf("Build Order condition, but got %v", result.Statement.SQL.String())
} }
@ -666,7 +671,7 @@ func TestOrder(t *testing.T) {
}).Find(&User{}).Statement }).Find(&User{}).Statement
explainedSQL := dryDB.Dialector.Explain(stmt.SQL.String(), stmt.Vars...) explainedSQL := dryDB.Dialector.Explain(stmt.SQL.String(), stmt.Vars...)
if !regexp.MustCompile("SELECT \\* FROM .*users.* ORDER BY FIELD\\(id,1,2,3\\)").MatchString(explainedSQL) { if !regexp.MustCompile(userQuery + "ORDER BY FIELD\\(id,1,2,3\\)").MatchString(explainedSQL) {
t.Fatalf("Build Order condition, but got %v", explainedSQL) t.Fatalf("Build Order condition, but got %v", explainedSQL)
} }
} }
@ -873,8 +878,9 @@ func TestScanNullValue(t *testing.T) {
func TestQueryWithTableAndConditions(t *testing.T) { func TestQueryWithTableAndConditions(t *testing.T) {
result := DB.Session(&gorm.Session{DryRun: true}).Table("user").Find(&User{}, User{Name: "jinzhu"}) result := DB.Session(&gorm.Session{DryRun: true}).Table("user").Find(&User{}, User{Name: "jinzhu"})
userQuery := "SELECT .*id.*created_at.*updated_at.*deleted_at.*name.*age.*birthday.*company_id.*manager_id.*active.* FROM .user. "
if !regexp.MustCompile(`SELECT \* FROM .user. WHERE .user.\..name. = .+ AND .user.\..deleted_at. IS NULL`).MatchString(result.Statement.SQL.String()) { if !regexp.MustCompile(userQuery + `WHERE .user.\..name. = .+ AND .user.\..deleted_at. IS NULL`).MatchString(result.Statement.SQL.String()) {
t.Errorf("invalid query SQL, got %v", result.Statement.SQL.String()) t.Errorf("invalid query SQL, got %v", result.Statement.SQL.String())
} }
} }

View File

@ -19,9 +19,10 @@ func (UserWithTable) TableName() string {
func TestTable(t *testing.T) { func TestTable(t *testing.T) {
dryDB := DB.Session(&gorm.Session{DryRun: true}) dryDB := DB.Session(&gorm.Session{DryRun: true})
userQuery := "SELECT .*id.*created_at.*updated_at.*deleted_at.*name.*age.*birthday.*company_id.*manager_id.*active.* "
r := dryDB.Table("`user`").Find(&User{}).Statement r := dryDB.Table("`user`").Find(&User{}).Statement
if !regexp.MustCompile("SELECT \\* FROM `user`").MatchString(r.Statement.SQL.String()) { if !regexp.MustCompile(userQuery + "FROM `user`").MatchString(r.Statement.SQL.String()) {
t.Errorf("Table with escape character, got %v", r.Statement.SQL.String()) t.Errorf("Table with escape character, got %v", r.Statement.SQL.String())
} }
@ -52,17 +53,17 @@ func TestTable(t *testing.T) {
} }
r = dryDB.Table("(?) as u", DB.Model(&User{}).Select("name")).Find(&User{}).Statement r = dryDB.Table("(?) as u", DB.Model(&User{}).Select("name")).Find(&User{}).Statement
if !regexp.MustCompile("SELECT \\* FROM \\(SELECT .name. FROM .users. WHERE .users.\\..deleted_at. IS NULL\\) as u WHERE .u.\\..deleted_at. IS NULL").MatchString(r.Statement.SQL.String()) { if !regexp.MustCompile(userQuery + "FROM \\(SELECT .name. FROM .users. WHERE .users.\\..deleted_at. IS NULL\\) as u WHERE .u.\\..deleted_at. IS NULL").MatchString(r.Statement.SQL.String()) {
t.Errorf("Table with escape character, got %v", r.Statement.SQL.String()) t.Errorf("Table with escape character, got %v", r.Statement.SQL.String())
} }
r = dryDB.Table("(?) as u, (?) as p", DB.Model(&User{}).Select("name"), DB.Model(&Pet{}).Select("name")).Find(&User{}).Statement r = dryDB.Table("(?) as u, (?) as p", DB.Model(&User{}).Select("name"), DB.Model(&Pet{}).Select("name")).Find(&User{}).Statement
if !regexp.MustCompile("SELECT \\* FROM \\(SELECT .name. FROM .users. WHERE .users.\\..deleted_at. IS NULL\\) as u, \\(SELECT .name. FROM .pets. WHERE .pets.\\..deleted_at. IS NULL\\) as p WHERE .u.\\..deleted_at. IS NULL").MatchString(r.Statement.SQL.String()) { if !regexp.MustCompile(userQuery + "FROM \\(SELECT .name. FROM .users. WHERE .users.\\..deleted_at. IS NULL\\) as u, \\(SELECT .name. FROM .pets. WHERE .pets.\\..deleted_at. IS NULL\\) as p WHERE .u.\\..deleted_at. IS NULL").MatchString(r.Statement.SQL.String()) {
t.Errorf("Table with escape character, got %v", r.Statement.SQL.String()) t.Errorf("Table with escape character, got %v", r.Statement.SQL.String())
} }
r = dryDB.Where("name = ?", 1).Table("(?) as u, (?) as p", DB.Model(&User{}).Select("name").Where("name = ?", 2), DB.Model(&Pet{}).Where("name = ?", 4).Select("name")).Where("name = ?", 3).Find(&User{}).Statement r = dryDB.Where("name = ?", 1).Table("(?) as u, (?) as p", DB.Model(&User{}).Select("name").Where("name = ?", 2), DB.Model(&Pet{}).Where("name = ?", 4).Select("name")).Where("name = ?", 3).Find(&User{}).Statement
if !regexp.MustCompile("SELECT \\* FROM \\(SELECT .name. FROM .users. WHERE name = .+ AND .users.\\..deleted_at. IS NULL\\) as u, \\(SELECT .name. FROM .pets. WHERE name = .+ AND .pets.\\..deleted_at. IS NULL\\) as p WHERE name = .+ AND name = .+ AND .u.\\..deleted_at. IS NULL").MatchString(r.Statement.SQL.String()) { if !regexp.MustCompile(userQuery + "FROM \\(SELECT .name. FROM .users. WHERE name = .+ AND .users.\\..deleted_at. IS NULL\\) as u, \\(SELECT .name. FROM .pets. WHERE name = .+ AND .pets.\\..deleted_at. IS NULL\\) as p WHERE name = .+ AND name = .+ AND .u.\\..deleted_at. IS NULL").MatchString(r.Statement.SQL.String()) {
t.Errorf("Table with escape character, got %v", r.Statement.SQL.String()) t.Errorf("Table with escape character, got %v", r.Statement.SQL.String())
} }