func CleanDB(x *xorm.Engine) { if x.DriverName() == "postgres" { sess := x.NewSession() defer sess.Close() if _, err := sess.Exec("DROP SCHEMA public CASCADE;"); err != nil { panic("Failed to drop schema public") } if _, err := sess.Exec("CREATE SCHEMA public;"); err != nil { panic("Failed to create schema public") } } else if x.DriverName() == "mysql" { tables, _ := x.DBMetas() sess := x.NewSession() defer sess.Close() for _, table := range tables { if _, err := sess.Exec("set foreign_key_checks = 0"); err != nil { panic("failed to disable foreign key checks") } if _, err := sess.Exec("drop table " + table.Name + " ;"); err != nil { panic(fmt.Sprintf("failed to delete table: %v, err: %v", table.Name, err)) } if _, err := sess.Exec("set foreign_key_checks = 1"); err != nil { panic("failed to disable foreign key checks") } } } }
func testNullValue(engine *xorm.Engine, t *testing.T) { err := engine.DropTables(&NullData{}) if err != nil { t.Error(err) panic(err) } err = engine.CreateTables(&NullData{}) if err != nil { t.Error(err) panic(err) } nullData := NullData{} cnt, err := engine.Insert(&nullData) fmt.Println(nullData.Id) if err != nil { t.Error(err) panic(err) } if cnt != 1 { err = errors.New("insert not returned 1") t.Error(err) panic(err) return } if nullData.Id <= 0 { err = errors.New("not return id error") t.Error(err) panic(err) } nullDataGet := NullData{} has, err := engine.Id(nullData.Id).Get(&nullDataGet) if err != nil { t.Error(err) panic(err) } else if !has { t.Error(errors.New("ID not found")) } if nullDataGet.StringPtr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.StringPtr))) } if nullDataGet.StringPtr2 != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.StringPtr2))) } if nullDataGet.BoolPtr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%t]", *nullDataGet.BoolPtr))) } if nullDataGet.UintPtr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.UintPtr))) } if nullDataGet.Uint8Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Uint8Ptr))) } if nullDataGet.Uint16Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Uint16Ptr))) } if nullDataGet.Uint32Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Uint32Ptr))) } if nullDataGet.Uint64Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Uint64Ptr))) } if nullDataGet.IntPtr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.IntPtr))) } if nullDataGet.Int8Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Int8Ptr))) } if nullDataGet.Int16Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Int16Ptr))) } if nullDataGet.Int32Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Int32Ptr))) } if nullDataGet.Int64Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Int64Ptr))) } if nullDataGet.RunePtr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.RunePtr))) } if nullDataGet.Float32Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Float32Ptr))) } if nullDataGet.Float64Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Float64Ptr))) } // if nullDataGet.Complex64Ptr != nil { // t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Complex64Ptr))) // } // if nullDataGet.Complex128Ptr != nil { // t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Complex128Ptr))) // } if nullDataGet.TimePtr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.TimePtr))) } nullDataUpdate := NullData{ StringPtr: new(string), StringPtr2: new(string), BoolPtr: new(bool), BytePtr: new(byte), UintPtr: new(uint), Uint8Ptr: new(uint8), Uint16Ptr: new(uint16), Uint32Ptr: new(uint32), Uint64Ptr: new(uint64), IntPtr: new(int), Int8Ptr: new(int8), Int16Ptr: new(int16), Int32Ptr: new(int32), Int64Ptr: new(int64), RunePtr: new(rune), Float32Ptr: new(float32), Float64Ptr: new(float64), // Complex64Ptr: new(complex64), // Complex128Ptr: new(complex128), TimePtr: new(time.Time), } *nullDataUpdate.StringPtr = "abc" *nullDataUpdate.StringPtr2 = "123" *nullDataUpdate.BoolPtr = true *nullDataUpdate.BytePtr = 1 *nullDataUpdate.UintPtr = 1 *nullDataUpdate.Uint8Ptr = 1 *nullDataUpdate.Uint16Ptr = 1 *nullDataUpdate.Uint32Ptr = 1 *nullDataUpdate.Uint64Ptr = 1 *nullDataUpdate.IntPtr = -1 *nullDataUpdate.Int8Ptr = -1 *nullDataUpdate.Int16Ptr = -1 *nullDataUpdate.Int32Ptr = -1 *nullDataUpdate.Int64Ptr = -1 *nullDataUpdate.RunePtr = 1 *nullDataUpdate.Float32Ptr = -1.2 *nullDataUpdate.Float64Ptr = -1.1 // *nullDataUpdate.Complex64Ptr = 123456789012345678901234567890 // *nullDataUpdate.Complex128Ptr = 123456789012345678901234567890123456789012345678901234567890 *nullDataUpdate.TimePtr = time.Now() cnt, err = engine.Id(nullData.Id).Update(&nullDataUpdate) if err != nil { t.Error(err) panic(err) } else if cnt != 1 { t.Error(errors.New("update count == 0, how can this happen!?")) return } // verify get values nullDataGet = NullData{} has, err = engine.Id(nullData.Id).Get(&nullDataGet) if err != nil { t.Error(err) return } else if !has { t.Error(errors.New("ID not found")) return } if *nullDataGet.StringPtr != *nullDataUpdate.StringPtr { t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.StringPtr))) } if *nullDataGet.StringPtr2 != *nullDataUpdate.StringPtr2 { t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.StringPtr2))) } if *nullDataGet.BoolPtr != *nullDataUpdate.BoolPtr { t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%t]", *nullDataGet.BoolPtr))) } if *nullDataGet.UintPtr != *nullDataUpdate.UintPtr { t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.UintPtr))) } if *nullDataGet.Uint8Ptr != *nullDataUpdate.Uint8Ptr { t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Uint8Ptr))) } if *nullDataGet.Uint16Ptr != *nullDataUpdate.Uint16Ptr { t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Uint16Ptr))) } if *nullDataGet.Uint32Ptr != *nullDataUpdate.Uint32Ptr { t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Uint32Ptr))) } if *nullDataGet.Uint64Ptr != *nullDataUpdate.Uint64Ptr { t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Uint64Ptr))) } if *nullDataGet.IntPtr != *nullDataUpdate.IntPtr { t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.IntPtr))) } if *nullDataGet.Int8Ptr != *nullDataUpdate.Int8Ptr { t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Int8Ptr))) } if *nullDataGet.Int16Ptr != *nullDataUpdate.Int16Ptr { t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Int16Ptr))) } if *nullDataGet.Int32Ptr != *nullDataUpdate.Int32Ptr { t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Int32Ptr))) } if *nullDataGet.Int64Ptr != *nullDataUpdate.Int64Ptr { t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Int64Ptr))) } if *nullDataGet.RunePtr != *nullDataUpdate.RunePtr { t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.RunePtr))) } if *nullDataGet.Float32Ptr != *nullDataUpdate.Float32Ptr { t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Float32Ptr))) } if *nullDataGet.Float64Ptr != *nullDataUpdate.Float64Ptr { t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Float64Ptr))) } // if *nullDataGet.Complex64Ptr != *nullDataUpdate.Complex64Ptr { // t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Complex64Ptr))) // } // if *nullDataGet.Complex128Ptr != *nullDataUpdate.Complex128Ptr { // t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]", *nullDataGet.Complex128Ptr))) // } // !nashtsai! skipped mymysql test due to driver will round up time caused inaccuracy comparison // skipped postgres test due to postgres driver doesn't read time.Time's timzezone info when stored in the db // mysql and sqlite3 seem have done this correctly by storing datatime in UTC timezone, I think postgres driver // prefer using timestamp with timezone to sovle the issue if engine.DriverName() != core.POSTGRES && engine.DriverName() != "mymysql" && engine.DriverName() != core.MYSQL { if (*nullDataGet.TimePtr).Unix() != (*nullDataUpdate.TimePtr).Unix() { t.Error(errors.New(fmt.Sprintf("inserted value unmatch: [%v]:[%v]", *nullDataGet.TimePtr, *nullDataUpdate.TimePtr))) } else { // !nashtsai! mymysql driver will failed this test case, due the time is roundup to nearest second, I would considered this is a bug in mymysql driver // inserted value unmatch: [2013-12-25 12:12:45 +0800 CST]:[2013-12-25 12:12:44.878903653 +0800 CST] fmt.Printf("time value: [%v]:[%v]", *nullDataGet.TimePtr, *nullDataUpdate.TimePtr) fmt.Println() } } // update to null values nullDataUpdate = NullData{} string_ptr := engine.ColumnMapper.Obj2Table("StringPtr") cnt, err = engine.Id(nullData.Id).Cols(string_ptr).Update(&nullDataUpdate) if err != nil { t.Error(err) panic(err) } else if cnt != 1 { t.Error(errors.New("update count == 0, how can this happen!?")) return } // verify get values nullDataGet = NullData{} has, err = engine.Id(nullData.Id).Get(&nullDataGet) if err != nil { t.Error(err) return } else if !has { t.Error(errors.New("ID not found")) return } fmt.Printf("%+v", nullDataGet) fmt.Println() if nullDataGet.StringPtr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.StringPtr))) } /* if nullDataGet.StringPtr2 != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.StringPtr2))) } if nullDataGet.BoolPtr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%t]", *nullDataGet.BoolPtr))) } if nullDataGet.UintPtr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.UintPtr))) } if nullDataGet.Uint8Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Uint8Ptr))) } if nullDataGet.Uint16Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Uint16Ptr))) } if nullDataGet.Uint32Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Uint32Ptr))) } if nullDataGet.Uint64Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Uint64Ptr))) } if nullDataGet.IntPtr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.IntPtr))) } if nullDataGet.Int8Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Int8Ptr))) } if nullDataGet.Int16Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Int16Ptr))) } if nullDataGet.Int32Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Int32Ptr))) } if nullDataGet.Int64Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Int64Ptr))) } if nullDataGet.RunePtr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.RunePtr))) } if nullDataGet.Float32Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Float32Ptr))) } if nullDataGet.Float64Ptr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Float64Ptr))) } // if nullDataGet.Complex64Ptr != nil { // t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Float64Ptr))) // } // if nullDataGet.Complex128Ptr != nil { // t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.Float64Ptr))) // } if nullDataGet.TimePtr != nil { t.Error(errors.New(fmt.Sprintf("not null value: [%v]", *nullDataGet.TimePtr))) }*/ // -- }
func testForUpdate(engine *xorm.Engine, t *testing.T) { if engine.DriverName() == "tidb" { return } err := setupForUpdate(engine) if err != nil { t.Error(err) return } session1 := engine.NewSession() session2 := engine.NewSession() session3 := engine.NewSession() defer session1.Close() defer session2.Close() defer session3.Close() // start transaction err = session1.Begin() if err != nil { t.Error(err) return } // use lock fList := make([]ForUpdate, 0) session1.ForUpdate() session1.Where("(id) = ?", 1) err = session1.Find(&fList) switch { case err != nil: t.Error(err) return case len(fList) != 1: t.Errorf("find not returned single row") return case fList[0].Name != "data1": t.Errorf("for_update.name must be `data1`") return } // wait for lock wg := &sync.WaitGroup{} // lock is used wg.Add(1) go func() { f2 := new(ForUpdate) session2.Where("(id) = ?", 1).ForUpdate() has, err := session2.Get(f2) // wait release lock switch { case err != nil: t.Error(err) case !has: t.Errorf("cannot find target row. for_update.id = 1") case f2.Name != "updated by session1": t.Errorf("read lock failed") } wg.Done() }() // lock is NOT used wg.Add(1) go func() { f3 := new(ForUpdate) session3.Where("(id) = ?", 1) has, err := session3.Get(f3) // wait release lock switch { case err != nil: t.Error(err) case !has: t.Errorf("cannot find target row. for_update.id = 1") case f3.Name != "data1": t.Errorf("read lock failed") } wg.Done() }() // wait for go rountines time.Sleep(50 * time.Millisecond) f := new(ForUpdate) f.Name = "updated by session1" session1.Where("(id) = ?", 1) session1.Update(f) // release lock err = session1.Commit() if err != nil { t.Error(err) return } wg.Wait() }