// TestStreamEncodeDecode generates random streams of EncDatums and passes them // through a StreamEncoder and a StreamDecoder func TestStreamEncodeDecode(t *testing.T) { defer leaktest.AfterTest(t)() rng, _ := randutil.NewPseudoRand() for test := 0; test < 100; test++ { rowLen := 1 + rng.Intn(20) info := make([]DatumInfo, rowLen) for i := range info { info[i].Type = sqlbase.RandColumnType(rng) info[i].Encoding = sqlbase.RandDatumEncoding(rng) } numRows := rng.Intn(100) rows := make(sqlbase.EncDatumRows, numRows) for i := range rows { rows[i] = make(sqlbase.EncDatumRow, rowLen) for j := range rows[i] { rows[i][j] = sqlbase.DatumToEncDatum(info[j].Type, sqlbase.RandDatum(rng, info[j].Type, true)) } } var trailerErr error if rng.Intn(10) == 0 { trailerErr = fmt.Errorf("test error %d", rng.Intn(100)) } testRowStream(t, rng, rows, trailerErr) } }
// TestCopyRandom inserts 100 random rows using COPY and ensures the SELECT'd // data is the same. func TestCopyRandom(t *testing.T) { defer leaktest.AfterTest(t)() params, _ := createTestServerParams() s, db, _ := serverutils.StartServer(t, params) defer s.Stopper().Stop() if _, err := db.Exec(` CREATE DATABASE d; CREATE TABLE IF NOT EXISTS d.t ( id INT PRIMARY KEY, n INTERVAL, o BOOL, i INT, f FLOAT, e DECIMAL, t TIMESTAMP, s STRING, b BYTES, tz TIMESTAMP WITH TIME ZONE ); `); err != nil { t.Fatal(err) } txn, err := db.Begin() if err != nil { t.Fatal(err) } stmt, err := txn.Prepare(pq.CopyInSchema("d", "t", "id", "n", "o", "i", "f", "e", "t", "s", "b", "tz")) if err != nil { t.Fatal(err) } rng := rand.New(rand.NewSource(0)) types := []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_BOOL, sqlbase.ColumnType_INT, sqlbase.ColumnType_FLOAT, sqlbase.ColumnType_DECIMAL, sqlbase.ColumnType_TIMESTAMP, sqlbase.ColumnType_STRING, sqlbase.ColumnType_BYTES, sqlbase.ColumnType_TIMESTAMPTZ, } var inputs [][]interface{} for i := 0; i < 100; i++ { row := make([]interface{}, len(types)+2) row[0] = strconv.Itoa(i) row[1] = time.Duration(rng.Int63()).String() for j, t := range types { d := sqlbase.RandDatum(rng, sqlbase.ColumnType{Kind: t}, false) ds := parser.AsStringWithFlags(d, parser.FmtBareStrings) switch t { case sqlbase.ColumnType_DECIMAL: // Trailing 0s aren't represented below, so truncate here. ds = strings.TrimRight(ds, "0") } row[j+2] = ds } _, err = stmt.Exec(row...) if err != nil { t.Fatal(err) } inputs = append(inputs, row) } err = stmt.Close() if err != nil { t.Fatal(err) } err = txn.Commit() if err != nil { t.Fatal(err) } rows, err := db.Query("SELECT * FROM d.t ORDER BY id") if err != nil { t.Fatal(err) } for row, in := range inputs { if !rows.Next() { t.Fatal("expected more results") } data := make([]interface{}, len(in)) for i := range data { data[i] = new(interface{}) } if err := rows.Scan(data...); err != nil { t.Fatal(err) } for i, d := range data { v := d.(*interface{}) d := *v ds := fmt.Sprint(d) switch d := d.(type) { case []byte: ds = string(d) case time.Time: dt := parser.MakeDTimestamp(d, time.Microsecond) ds = parser.AsStringWithFlags(dt, parser.FmtBareStrings) } if !reflect.DeepEqual(in[i], ds) { t.Fatalf("row %v, col %v: got %#v (%T), expected %#v", row, i, ds, d, in[i]) } } } }
// Test that distributing agg functions according to DistAggregationTable // yields correct results. We're going to run each aggregation as either the // two-stage process described by the DistAggregationTable or as a single global // process, and verify that the results are the same. func TestDistAggregationTable(t *testing.T) { defer leaktest.AfterTest(t)() const numRows = 100 tc := serverutils.StartTestCluster(t, 1, base.TestClusterArgs{}) defer tc.Stopper().Stop() // Create a table with a few columns: // - random integer values from 0 to numRows // - random integer values (with some NULLs) // - random bool value (mostly false) // - random bool value (mostly true) // - random decimals // - random decimals (with some NULLs) rng, _ := randutil.NewPseudoRand() sqlutils.CreateTable( t, tc.ServerConn(0), "t", "k INT PRIMARY KEY, int1 INT, int2 INT, bool1 BOOL, bool2 BOOL, dec1 DECIMAL, dec2 DECIMAL", numRows, func(row int) []parser.Datum { return []parser.Datum{ parser.NewDInt(parser.DInt(row)), parser.NewDInt(parser.DInt(rng.Intn(numRows))), sqlbase.RandDatum(rng, sqlbase.ColumnType{Kind: sqlbase.ColumnType_INT}, true), parser.MakeDBool(parser.DBool(rng.Intn(10) == 0)), parser.MakeDBool(parser.DBool(rng.Intn(10) != 0)), sqlbase.RandDatum(rng, sqlbase.ColumnType{Kind: sqlbase.ColumnType_DECIMAL}, false), sqlbase.RandDatum(rng, sqlbase.ColumnType{Kind: sqlbase.ColumnType_DECIMAL}, true), } }, ) kvDB := tc.Server(0).KVClient().(*client.DB) desc := sqlbase.GetTableDescriptor(kvDB, "test", "t") for fn, info := range DistAggregationTable { if info.LocalStage == distsqlrun.AggregatorSpec_IDENT && info.FinalStage == distsqlrun.AggregatorSpec_IDENT { // IDENT only works as expected if all rows have the same value on the // relevant column; skip testing this trivial case. continue } // We're going to test each aggregation function on every column that can be // used as input for it. foundCol := false for colIdx := 1; colIdx < len(desc.Columns); colIdx++ { // See if this column works with this function. _, _, err := distsqlrun.GetAggregateInfo(fn, desc.Columns[colIdx].Type) if err != nil { continue } foundCol = true for _, numRows := range []int{5, numRows / 10, numRows / 2, numRows} { name := fmt.Sprintf("%s/%s/%d", fn, desc.Columns[colIdx].Name, numRows) t.Run(name, func(t *testing.T) { checkDistAggregationInfo(t, tc.Server(0), desc, colIdx, numRows, fn, info) }) } } if !foundCol { t.Errorf("aggregation function %s was not tested (no suitable column)", fn) } } }