// 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) } }
func (ev *evaluator) eval(row sqlbase.EncDatumRow) (sqlbase.EncDatumRow, error) { outRow := ev.rowAlloc.AllocRow(len(ev.exprs)) for i := range ev.exprs { datum, err := ev.exprs[i].eval(row) if err != nil { return nil, err } outRow[i] = sqlbase.DatumToEncDatum(ev.exprTypes[i], datum) } return outRow, nil }
func TestMergeJoiner(t *testing.T) { defer leaktest.AfterTest(t)() v := [6]sqlbase.EncDatum{} for i := range v { v[i] = sqlbase.DatumToEncDatum(sqlbase.ColumnType_INT, parser.NewDInt(parser.DInt(i))) } null := sqlbase.EncDatum{Datum: parser.DNull} testCases := []struct { spec MergeJoinerSpec inputs []sqlbase.EncDatumRows expected sqlbase.EncDatumRows }{ { spec: MergeJoinerSpec{ LeftOrdering: convertToSpecOrdering( sqlbase.ColumnOrdering{ {ColIdx: 0, Direction: encoding.Ascending}, }), LeftTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, RightOrdering: convertToSpecOrdering( sqlbase.ColumnOrdering{ {ColIdx: 0, Direction: encoding.Ascending}, }), RightTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, Type: JoinType_INNER, OutputColumns: []uint32{0, 3, 4}, // Implicit @1 = @3 constraint. }, inputs: []sqlbase.EncDatumRows{ { {v[0], v[0]}, {v[1], v[4]}, {v[2], v[4]}, {v[3], v[1]}, {v[4], v[5]}, {v[5], v[5]}, }, { {v[1], v[0], v[4]}, {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, }, }, expected: sqlbase.EncDatumRows{ {v[1], v[0], v[4]}, {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, }, }, { spec: MergeJoinerSpec{ LeftOrdering: convertToSpecOrdering( sqlbase.ColumnOrdering{ {ColIdx: 0, Direction: encoding.Ascending}, }), LeftTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, RightOrdering: convertToSpecOrdering( sqlbase.ColumnOrdering{ {ColIdx: 0, Direction: encoding.Ascending}, }), RightTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, Type: JoinType_INNER, OutputColumns: []uint32{0, 1, 3}, // Implicit @1 = @3 constraint. }, inputs: []sqlbase.EncDatumRows{ { {v[0], v[0]}, {v[0], v[1]}, }, { {v[0], v[4]}, {v[0], v[1]}, {v[0], v[0]}, {v[0], v[5]}, {v[0], v[4]}, }, }, expected: sqlbase.EncDatumRows{ {v[0], v[0], v[4]}, {v[0], v[0], v[1]}, {v[0], v[0], v[0]}, {v[0], v[0], v[5]}, {v[0], v[0], v[4]}, {v[0], v[1], v[4]}, {v[0], v[1], v[1]}, {v[0], v[1], v[0]}, {v[0], v[1], v[5]}, {v[0], v[1], v[4]}, }, }, { spec: MergeJoinerSpec{ LeftOrdering: convertToSpecOrdering( sqlbase.ColumnOrdering{ {ColIdx: 0, Direction: encoding.Ascending}, }), LeftTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, RightOrdering: convertToSpecOrdering( sqlbase.ColumnOrdering{ {ColIdx: 0, Direction: encoding.Ascending}, }), RightTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, Type: JoinType_INNER, OutputColumns: []uint32{0, 1, 3}, Expr: Expression{Expr: "@4 >= 4"}, // Implicit AND @1 = @3 constraint. }, inputs: []sqlbase.EncDatumRows{ { {v[0], v[0]}, {v[0], v[1]}, {v[1], v[0]}, {v[1], v[1]}, }, { {v[0], v[4]}, {v[0], v[1]}, {v[0], v[0]}, {v[0], v[5]}, {v[0], v[4]}, {v[1], v[4]}, {v[1], v[1]}, {v[1], v[0]}, {v[1], v[5]}, {v[1], v[4]}, }, }, expected: sqlbase.EncDatumRows{ {v[0], v[0], v[4]}, {v[0], v[0], v[5]}, {v[0], v[0], v[4]}, {v[0], v[1], v[4]}, {v[0], v[1], v[5]}, {v[0], v[1], v[4]}, {v[1], v[0], v[4]}, {v[1], v[0], v[5]}, {v[1], v[0], v[4]}, {v[1], v[1], v[4]}, {v[1], v[1], v[5]}, {v[1], v[1], v[4]}, }, }, { spec: MergeJoinerSpec{ LeftOrdering: convertToSpecOrdering( sqlbase.ColumnOrdering{ {ColIdx: 0, Direction: encoding.Ascending}, }), LeftTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, RightOrdering: convertToSpecOrdering( sqlbase.ColumnOrdering{ {ColIdx: 0, Direction: encoding.Ascending}, }), RightTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, Type: JoinType_LEFT_OUTER, OutputColumns: []uint32{0, 3, 4}, // Implicit @1 = @3 constraint. }, inputs: []sqlbase.EncDatumRows{ { {v[0], v[0]}, {v[1], v[4]}, {v[2], v[4]}, {v[3], v[1]}, {v[4], v[5]}, {v[5], v[5]}, }, { {v[1], v[0], v[4]}, {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, }, }, expected: sqlbase.EncDatumRows{ {v[0], null, null}, {v[1], v[0], v[4]}, {v[2], null, null}, {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, {v[5], null, null}, }, }, { spec: MergeJoinerSpec{ LeftOrdering: convertToSpecOrdering( sqlbase.ColumnOrdering{ {ColIdx: 0, Direction: encoding.Ascending}, }), LeftTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, RightOrdering: convertToSpecOrdering( sqlbase.ColumnOrdering{ {ColIdx: 0, Direction: encoding.Ascending}, }), RightTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, Type: JoinType_RIGHT_OUTER, OutputColumns: []uint32{3, 1, 2}, // Implicit @1 = @3 constraint. }, inputs: []sqlbase.EncDatumRows{ { {v[1], v[0], v[4]}, {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, }, { {v[0], v[0]}, {v[1], v[4]}, {v[2], v[4]}, {v[3], v[1]}, {v[4], v[5]}, {v[5], v[5]}, }, }, expected: sqlbase.EncDatumRows{ {v[0], null, null}, {v[1], v[0], v[4]}, {v[2], null, null}, {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, {v[5], null, null}, }, }, { spec: MergeJoinerSpec{ LeftOrdering: convertToSpecOrdering( sqlbase.ColumnOrdering{ {ColIdx: 0, Direction: encoding.Ascending}, }), LeftTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, RightOrdering: convertToSpecOrdering( sqlbase.ColumnOrdering{ {ColIdx: 0, Direction: encoding.Ascending}, }), RightTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, Type: JoinType_FULL_OUTER, OutputColumns: []uint32{0, 3, 4}, // Implicit @1 = @3 constraint. }, inputs: []sqlbase.EncDatumRows{ { {v[0], v[0]}, {v[1], v[4]}, {v[2], v[4]}, {v[3], v[1]}, {v[4], v[5]}, }, { {v[1], v[0], v[4]}, {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, {v[5], v[5], v[1]}, }, }, expected: sqlbase.EncDatumRows{ {v[0], null, null}, {v[1], v[0], v[4]}, {v[2], null, null}, {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, {null, v[5], v[1]}, }, }, } for _, c := range testCases { ms := c.spec inputs := []RowSource{&RowBuffer{rows: c.inputs[0]}, &RowBuffer{rows: c.inputs[1]}} out := &RowBuffer{} flowCtx := FlowCtx{Context: context.Background(), evalCtx: &parser.EvalContext{}} m, err := newMergeJoiner(&flowCtx, &ms, inputs, out) if err != nil { t.Fatal(err) } m.Run(nil) var retRows sqlbase.EncDatumRows for { row, err := out.NextRow() if err != nil { t.Fatal(err) } if row == nil { break } retRows = append(retRows, row) } expStr := c.expected.String() retStr := retRows.String() if expStr != retStr { t.Errorf("invalid results; expected:\n %s\ngot:\n %s", expStr, retStr) } } }
func TestDistinct(t *testing.T) { defer leaktest.AfterTest(t)() v := [15]sqlbase.EncDatum{} for i := range v { v[i] = sqlbase.DatumToEncDatum(sqlbase.ColumnType{Kind: sqlbase.ColumnType_INT}, parser.NewDInt(parser.DInt(i))) } testCases := []struct { spec DistinctSpec input sqlbase.EncDatumRows expected sqlbase.EncDatumRows }{ { spec: DistinctSpec{}, input: sqlbase.EncDatumRows{ {v[2], v[3]}, {v[5], v[6]}, {v[2], v[3]}, {v[5], v[6]}, {v[2], v[6]}, {v[3], v[5]}, {v[2], v[9]}, }, expected: sqlbase.EncDatumRows{ {v[2], v[3]}, {v[5], v[6]}, {v[2], v[6]}, {v[3], v[5]}, {v[2], v[9]}, }, }, { spec: DistinctSpec{ OrderedColumns: []uint32{1}, }, input: sqlbase.EncDatumRows{ {v[2], v[3]}, {v[2], v[3]}, {v[2], v[6]}, {v[2], v[9]}, {v[3], v[5]}, {v[5], v[6]}, {v[5], v[6]}, }, expected: sqlbase.EncDatumRows{ {v[2], v[3]}, {v[2], v[6]}, {v[2], v[9]}, {v[3], v[5]}, {v[5], v[6]}, }, }, } for _, c := range testCases { ds := c.spec in := NewRowBuffer(nil, c.input) out := &RowBuffer{} flowCtx := FlowCtx{ Context: context.Background(), } d, err := newDistinct(&flowCtx, &ds, in, out) if err != nil { t.Fatal(err) } d.Run(nil) if out.Err != nil { t.Fatal(out.Err) } if !out.Closed { t.Fatalf("output RowReceiver not closed") } if result := out.Rows.String(); result != c.expected.String() { t.Errorf("invalid results: %s, expected %s'", result, c.expected.String()) } } }
func TestHashJoiner(t *testing.T) { defer leaktest.AfterTest(t)() v := [10]sqlbase.EncDatum{} for i := range v { v[i] = sqlbase.DatumToEncDatum(sqlbase.ColumnType_INT, parser.NewDInt(parser.DInt(i))) } null := sqlbase.EncDatum{Datum: parser.DNull} testCases := []struct { spec HashJoinerSpec inputs []sqlbase.EncDatumRows expected sqlbase.EncDatumRows }{ { spec: HashJoinerSpec{ LeftEqColumns: []uint32{0}, LeftTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, RightEqColumns: []uint32{0}, RightTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, Type: JoinType_INNER, OutputColumns: []uint32{0, 3, 4}, // Implicit @1 = @3 constraint. }, inputs: []sqlbase.EncDatumRows{ { {v[0], v[0]}, {v[1], v[4]}, {v[2], v[4]}, {v[3], v[1]}, {v[4], v[5]}, {v[5], v[5]}, }, { {v[1], v[0], v[4]}, {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, }, }, expected: sqlbase.EncDatumRows{ {v[1], v[0], v[4]}, {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, }, }, { spec: HashJoinerSpec{ LeftEqColumns: []uint32{0}, LeftTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, RightEqColumns: []uint32{0}, RightTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, Type: JoinType_INNER, OutputColumns: []uint32{0, 1, 3}, // Implicit @1 = @3 constraint. }, inputs: []sqlbase.EncDatumRows{ { {v[0], v[0]}, {v[0], v[1]}, }, { {v[0], v[4]}, {v[0], v[1]}, {v[0], v[0]}, {v[0], v[5]}, {v[0], v[4]}, }, }, expected: sqlbase.EncDatumRows{ {v[0], v[0], v[4]}, {v[0], v[0], v[1]}, {v[0], v[0], v[0]}, {v[0], v[0], v[5]}, {v[0], v[0], v[4]}, {v[0], v[1], v[4]}, {v[0], v[1], v[1]}, {v[0], v[1], v[0]}, {v[0], v[1], v[5]}, {v[0], v[1], v[4]}, }, }, { spec: HashJoinerSpec{ LeftEqColumns: []uint32{0}, LeftTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, RightEqColumns: []uint32{0}, RightTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, Type: JoinType_INNER, OutputColumns: []uint32{0, 1, 3}, Expr: Expression{Expr: "@4 >= 4"}, // Implicit AND @1 = @3 constraint. }, inputs: []sqlbase.EncDatumRows{ { {v[0], v[0]}, {v[0], v[1]}, {v[1], v[0]}, {v[1], v[1]}, }, { {v[0], v[4]}, {v[0], v[1]}, {v[0], v[0]}, {v[0], v[5]}, {v[0], v[4]}, {v[1], v[4]}, {v[1], v[1]}, {v[1], v[0]}, {v[1], v[5]}, {v[1], v[4]}, }, }, expected: sqlbase.EncDatumRows{ {v[0], v[0], v[4]}, {v[0], v[0], v[5]}, {v[0], v[0], v[4]}, {v[0], v[1], v[4]}, {v[0], v[1], v[5]}, {v[0], v[1], v[4]}, {v[1], v[0], v[4]}, {v[1], v[0], v[5]}, {v[1], v[0], v[4]}, {v[1], v[1], v[4]}, {v[1], v[1], v[5]}, {v[1], v[1], v[4]}, }, }, { spec: HashJoinerSpec{ LeftEqColumns: []uint32{0}, LeftTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, RightEqColumns: []uint32{0}, RightTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, Type: JoinType_LEFT_OUTER, OutputColumns: []uint32{0, 3, 4}, // Implicit @1 = @3 constraint. }, inputs: []sqlbase.EncDatumRows{ { {v[0], v[0]}, {v[1], v[4]}, {v[2], v[4]}, {v[3], v[1]}, {v[4], v[5]}, {v[5], v[5]}, }, { {v[1], v[0], v[4]}, {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, }, }, expected: sqlbase.EncDatumRows{ {v[0], null, null}, {v[1], v[0], v[4]}, {v[2], null, null}, {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, {v[5], null, null}, }, }, { spec: HashJoinerSpec{ LeftEqColumns: []uint32{0}, LeftTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, RightEqColumns: []uint32{0}, RightTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, Type: JoinType_RIGHT_OUTER, OutputColumns: []uint32{3, 1, 2}, // Implicit @1 = @3 constraint. }, inputs: []sqlbase.EncDatumRows{ { {v[1], v[0], v[4]}, {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, }, { {v[0], v[0]}, {v[1], v[4]}, {v[2], v[4]}, {v[3], v[1]}, {v[4], v[5]}, {v[5], v[5]}, }, }, expected: sqlbase.EncDatumRows{ {v[0], null, null}, {v[1], v[0], v[4]}, {v[2], null, null}, {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, {v[5], null, null}, }, }, { spec: HashJoinerSpec{ LeftEqColumns: []uint32{0}, LeftTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, RightEqColumns: []uint32{0}, RightTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, Type: JoinType_FULL_OUTER, OutputColumns: []uint32{0, 3, 4}, // Implicit @1 = @3 constraint. }, inputs: []sqlbase.EncDatumRows{ { {v[0], v[0]}, {v[1], v[4]}, {v[2], v[4]}, {v[3], v[1]}, {v[4], v[5]}, }, { {v[1], v[0], v[4]}, {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, {v[5], v[5], v[1]}, }, }, expected: sqlbase.EncDatumRows{ {v[0], null, null}, {v[1], v[0], v[4]}, {v[2], null, null}, {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, {null, v[5], v[1]}, }, }, { spec: HashJoinerSpec{ LeftEqColumns: []uint32{0}, LeftTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, RightEqColumns: []uint32{0}, RightTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, Type: JoinType_INNER, OutputColumns: []uint32{0, 3, 4}, // Implicit @1 = @3 constraint. }, inputs: []sqlbase.EncDatumRows{ { {v[0], v[0]}, {v[2], v[4]}, {v[3], v[1]}, {v[4], v[5]}, {v[5], v[5]}, }, { {v[1], v[0], v[4]}, {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, }, }, expected: sqlbase.EncDatumRows{ {v[3], v[4], v[1]}, {v[4], v[4], v[5]}, }, }, // Tests for behavior when input contains NULLs. { spec: HashJoinerSpec{ LeftEqColumns: []uint32{0, 1}, LeftTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, RightEqColumns: []uint32{0, 1}, RightTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, Type: JoinType_INNER, OutputColumns: []uint32{0, 1, 2, 3, 4}, // Implicit @1,@2 = @3,@4 constraint. }, inputs: []sqlbase.EncDatumRows{ { {v[0], v[0]}, {v[1], null}, {null, v[2]}, {null, null}, }, { {v[0], v[0], v[4]}, {v[1], null, v[5]}, {null, v[2], v[6]}, {null, null, v[7]}, }, }, expected: sqlbase.EncDatumRows{ {v[0], v[0], v[0], v[0], v[4]}, }, }, { spec: HashJoinerSpec{ LeftEqColumns: []uint32{0, 1}, LeftTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, RightEqColumns: []uint32{0, 1}, RightTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, Type: JoinType_LEFT_OUTER, OutputColumns: []uint32{0, 1, 2, 3, 4}, // Implicit @1,@2 = @3,@4 constraint. }, inputs: []sqlbase.EncDatumRows{ { {v[0], v[0]}, {v[1], null}, {null, v[2]}, {null, null}, }, { {v[0], v[0], v[4]}, {v[1], null, v[5]}, {null, v[2], v[6]}, {null, null, v[7]}, }, }, expected: sqlbase.EncDatumRows{ {v[0], v[0], v[0], v[0], v[4]}, {v[1], null, null, null, null}, {null, v[2], null, null, null}, {null, null, null, null, null}, }, }, { spec: HashJoinerSpec{ LeftEqColumns: []uint32{0, 1}, LeftTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, RightEqColumns: []uint32{0, 1}, RightTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, Type: JoinType_RIGHT_OUTER, OutputColumns: []uint32{0, 1, 2, 3, 4}, // Implicit @1,@2 = @3,@4 constraint. }, inputs: []sqlbase.EncDatumRows{ { {v[0], v[0]}, {v[1], null}, {null, v[2]}, {null, null}, }, { {v[0], v[0], v[4]}, {v[1], null, v[5]}, {null, v[2], v[6]}, {null, null, v[7]}, }, }, expected: sqlbase.EncDatumRows{ {v[0], v[0], v[0], v[0], v[4]}, {null, null, v[1], null, v[5]}, {null, null, null, v[2], v[6]}, {null, null, null, null, v[7]}, }, }, { spec: HashJoinerSpec{ LeftEqColumns: []uint32{0, 1}, LeftTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, RightEqColumns: []uint32{0, 1}, RightTypes: []sqlbase.ColumnType_Kind{ sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, sqlbase.ColumnType_INT, }, Type: JoinType_FULL_OUTER, OutputColumns: []uint32{0, 1, 2, 3, 4}, // Implicit @1,@2 = @3,@4 constraint. }, inputs: []sqlbase.EncDatumRows{ { {v[0], v[0]}, {v[1], null}, {null, v[2]}, {null, null}, }, { {v[0], v[0], v[4]}, {v[1], null, v[5]}, {null, v[2], v[6]}, {null, null, v[7]}, }, }, expected: sqlbase.EncDatumRows{ {v[0], v[0], v[0], v[0], v[4]}, {null, null, v[1], null, v[5]}, {null, null, null, v[2], v[6]}, {null, null, null, null, v[7]}, {v[1], null, null, null, null}, {null, v[2], null, null, null}, {null, null, null, null, null}, }, }, } for _, c := range testCases { hs := c.spec inputs := []RowSource{&RowBuffer{rows: c.inputs[0]}, &RowBuffer{rows: c.inputs[1]}} out := &RowBuffer{} flowCtx := FlowCtx{Context: context.Background(), evalCtx: &parser.EvalContext{}} h, err := newHashJoiner(&flowCtx, &hs, inputs, out) if err != nil { t.Fatal(err) } h.Run(nil) if out.err != nil { t.Fatal(out.err) } if !out.closed { t.Fatalf("output RowReceiver not closed") } var expected []string for _, row := range c.expected { expected = append(expected, row.String()) } sort.Strings(expected) expStr := strings.Join(expected, "") var rets []string for { row, err := out.NextRow() if err != nil { t.Fatal(err) } if row == nil { break } rets = append(rets, row.String()) } sort.Strings(rets) retStr := strings.Join(rets, "") if expStr != retStr { t.Errorf("invalid results; expected:\n %s\ngot:\n %s", expStr, retStr) } } }
func TestJoinReader(t *testing.T) { defer leaktest.AfterTest(t)() s, sqlDB, kvDB := serverutils.StartServer(t, base.TestServerArgs{}) defer s.Stopper().Stop() // Create a table where each row is: // // | a | b | sum | s | // |-----------------------------------------------------------------| // | rowId/10 | rowId%10 | rowId/10 + rowId%10 | IntToEnglish(rowId) | aFn := func(row int) parser.Datum { return parser.NewDInt(parser.DInt(row / 10)) } bFn := func(row int) parser.Datum { return parser.NewDInt(parser.DInt(row % 10)) } sumFn := func(row int) parser.Datum { return parser.NewDInt(parser.DInt(row/10 + row%10)) } sqlutils.CreateTable(t, sqlDB, "t", "a INT, b INT, sum INT, s STRING, PRIMARY KEY (a,b), INDEX bs (b,s)", 99, sqlutils.ToRowFn(aFn, bFn, sumFn, sqlutils.RowEnglishFn)) td := sqlbase.GetTableDescriptor(kvDB, "test", "t") testCases := []struct { spec JoinReaderSpec input [][]parser.Datum expected string }{ { spec: JoinReaderSpec{ OutputColumns: []uint32{0, 1, 2}, }, input: [][]parser.Datum{ {aFn(2), bFn(2)}, {aFn(5), bFn(5)}, {aFn(10), bFn(10)}, {aFn(15), bFn(15)}, }, expected: "[[0 2 2] [0 5 5] [1 0 1] [1 5 6]]", }, { spec: JoinReaderSpec{ Filter: Expression{Expr: "@3 <= 5"}, // sum <= 5 OutputColumns: []uint32{3}, }, input: [][]parser.Datum{ {aFn(1), bFn(1)}, {aFn(25), bFn(25)}, {aFn(5), bFn(5)}, {aFn(21), bFn(21)}, {aFn(34), bFn(34)}, {aFn(13), bFn(13)}, {aFn(51), bFn(51)}, {aFn(50), bFn(50)}, }, expected: "[['one'] ['five'] ['two-one'] ['one-three'] ['five-zero']]", }, } for _, c := range testCases { js := c.spec js.Table = *td flowCtx := FlowCtx{ Context: context.Background(), evalCtx: &parser.EvalContext{}, txnProto: &roachpb.Transaction{}, clientDB: kvDB, } in := &RowBuffer{} for _, row := range c.input { encRow := make(sqlbase.EncDatumRow, len(row)) for i, d := range row { encRow[i] = sqlbase.DatumToEncDatum(sqlbase.ColumnType{Kind: sqlbase.ColumnType_INT}, d) } in.rows = append(in.rows, encRow) } out := &RowBuffer{} jr, err := newJoinReader(&flowCtx, &js, in, out) if err != nil { t.Fatal(err) } jr.Run(nil) if out.err != nil { t.Fatal(out.err) } if !in.done { t.Fatal("joinReader stopped accepting rows") } if !out.closed { t.Fatalf("output RowReceiver not closed") } if result := out.rows.String(); result != c.expected { t.Errorf("invalid results: %s, expected %s'", result, c.expected) } } }
func TestSorter(t *testing.T) { defer leaktest.AfterTest(t)() columnTypeInt := &sqlbase.ColumnType{Kind: sqlbase.ColumnType_INT} v := [6]sqlbase.EncDatum{} for i := range v { v[i] = sqlbase.DatumToEncDatum(*columnTypeInt, parser.NewDInt(parser.DInt(i))) } asc := encoding.Ascending desc := encoding.Descending testCases := []struct { spec SorterSpec input sqlbase.EncDatumRows expected sqlbase.EncDatumRows }{ { // No specified input ordering and unspecified limit. spec: SorterSpec{ OutputOrdering: convertToSpecOrdering( sqlbase.ColumnOrdering{ {ColIdx: 0, Direction: asc}, {ColIdx: 1, Direction: desc}, {ColIdx: 2, Direction: asc}, }), }, input: sqlbase.EncDatumRows{ {v[1], v[0], v[4]}, {v[3], v[4], v[1]}, {v[4], v[4], v[4]}, {v[3], v[2], v[0]}, {v[4], v[4], v[5]}, {v[3], v[3], v[0]}, {v[0], v[0], v[0]}, }, expected: sqlbase.EncDatumRows{ {v[0], v[0], v[0]}, {v[1], v[0], v[4]}, {v[3], v[4], v[1]}, {v[3], v[3], v[0]}, {v[3], v[2], v[0]}, {v[4], v[4], v[4]}, {v[4], v[4], v[5]}, }, }, { // No specified input ordering but specified limit. spec: SorterSpec{ Limit: 4, OutputOrdering: convertToSpecOrdering( sqlbase.ColumnOrdering{ {ColIdx: 0, Direction: asc}, {ColIdx: 1, Direction: asc}, {ColIdx: 2, Direction: asc}, }), }, input: sqlbase.EncDatumRows{ {v[3], v[3], v[0]}, {v[3], v[4], v[1]}, {v[1], v[0], v[4]}, {v[0], v[0], v[0]}, {v[4], v[4], v[4]}, {v[4], v[4], v[5]}, {v[3], v[2], v[0]}, }, expected: sqlbase.EncDatumRows{ {v[0], v[0], v[0]}, {v[1], v[0], v[4]}, {v[3], v[2], v[0]}, {v[3], v[3], v[0]}, }, }, { // Specified match ordering length but no specified limit. spec: SorterSpec{ OrderingMatchLen: 2, OutputOrdering: convertToSpecOrdering( sqlbase.ColumnOrdering{ {ColIdx: 0, Direction: asc}, {ColIdx: 1, Direction: asc}, {ColIdx: 2, Direction: asc}, }), }, input: sqlbase.EncDatumRows{ {v[0], v[1], v[2]}, {v[0], v[1], v[0]}, {v[1], v[0], v[5]}, {v[1], v[1], v[5]}, {v[1], v[1], v[4]}, {v[3], v[4], v[3]}, {v[3], v[4], v[2]}, {v[3], v[5], v[1]}, {v[4], v[4], v[5]}, {v[4], v[4], v[4]}, }, expected: sqlbase.EncDatumRows{ {v[0], v[1], v[0]}, {v[0], v[1], v[2]}, {v[1], v[0], v[5]}, {v[1], v[1], v[4]}, {v[1], v[1], v[5]}, {v[3], v[4], v[2]}, {v[3], v[4], v[3]}, {v[3], v[5], v[1]}, {v[4], v[4], v[4]}, {v[4], v[4], v[5]}, }, }, { // Specified input ordering but no specified limit. spec: SorterSpec{ OrderingMatchLen: 2, OutputOrdering: convertToSpecOrdering( sqlbase.ColumnOrdering{ {ColIdx: 1, Direction: asc}, {ColIdx: 2, Direction: asc}, {ColIdx: 3, Direction: asc}, }), }, input: sqlbase.EncDatumRows{ {v[1], v[1], v[2], v[5]}, {v[0], v[1], v[2], v[4]}, {v[0], v[1], v[2], v[3]}, {v[1], v[1], v[2], v[2]}, {v[1], v[2], v[2], v[5]}, {v[0], v[2], v[2], v[4]}, {v[0], v[2], v[2], v[3]}, {v[1], v[2], v[2], v[2]}, }, expected: sqlbase.EncDatumRows{ {v[1], v[1], v[2], v[2]}, {v[0], v[1], v[2], v[3]}, {v[0], v[1], v[2], v[4]}, {v[1], v[1], v[2], v[5]}, {v[1], v[2], v[2], v[2]}, {v[0], v[2], v[2], v[3]}, {v[0], v[2], v[2], v[4]}, {v[1], v[2], v[2], v[5]}, }, }, } for _, c := range testCases { ss := c.spec in := &RowBuffer{rows: c.input} out := &RowBuffer{} flowCtx := FlowCtx{Context: context.Background()} s := newSorter(&flowCtx, &ss, in, out) s.Run(nil) if out.err != nil { t.Fatal(out.err) } if !out.closed { t.Fatalf("output RowReceiver not closed") } var retRows sqlbase.EncDatumRows for { row, err := out.NextRow() if err != nil { t.Fatal(err) } if row == nil { break } retRows = append(retRows, row) } expStr := c.expected.String() retStr := retRows.String() if expStr != retStr { t.Errorf("invalid results; expected:\n %s\ngot:\n %s", expStr, retStr) } } }
func TestOrderedSync(t *testing.T) { defer leaktest.AfterTest(t)() columnTypeInt := &sqlbase.ColumnType{Kind: sqlbase.ColumnType_INT} v := [6]sqlbase.EncDatum{} for i := range v { v[i] = sqlbase.DatumToEncDatum(*columnTypeInt, parser.NewDInt(parser.DInt(i))) } asc := encoding.Ascending desc := encoding.Descending testCases := []struct { sources []sqlbase.EncDatumRows ordering sqlbase.ColumnOrdering expected sqlbase.EncDatumRows }{ { sources: []sqlbase.EncDatumRows{ { {v[0], v[1], v[4]}, {v[0], v[1], v[2]}, {v[0], v[2], v[3]}, {v[1], v[1], v[3]}, }, { {v[1], v[0], v[4]}, }, { {v[0], v[0], v[0]}, {v[4], v[4], v[4]}, }, }, ordering: sqlbase.ColumnOrdering{ {ColIdx: 0, Direction: asc}, {ColIdx: 1, Direction: asc}, }, expected: sqlbase.EncDatumRows{ {v[0], v[0], v[0]}, {v[0], v[1], v[4]}, {v[0], v[1], v[2]}, {v[0], v[2], v[3]}, {v[1], v[0], v[4]}, {v[1], v[1], v[3]}, {v[4], v[4], v[4]}, }, }, { sources: []sqlbase.EncDatumRows{ {}, { {v[1], v[0], v[4]}, }, { {v[3], v[4], v[1]}, {v[4], v[4], v[4]}, {v[3], v[2], v[0]}, }, { {v[4], v[4], v[5]}, {v[3], v[3], v[0]}, {v[0], v[0], v[0]}, }, }, ordering: sqlbase.ColumnOrdering{ {ColIdx: 1, Direction: desc}, {ColIdx: 0, Direction: asc}, {ColIdx: 2, Direction: asc}, }, expected: sqlbase.EncDatumRows{ {v[3], v[4], v[1]}, {v[4], v[4], v[4]}, {v[4], v[4], v[5]}, {v[3], v[3], v[0]}, {v[3], v[2], v[0]}, {v[0], v[0], v[0]}, {v[1], v[0], v[4]}, }, }, } for testIdx, c := range testCases { var sources []RowSource for _, srcRows := range c.sources { rowBuf := &RowBuffer{rows: srcRows} sources = append(sources, rowBuf) } src, err := makeOrderedSync(c.ordering, sources) if err != nil { t.Fatal(err) } var retRows sqlbase.EncDatumRows for { row, err := src.NextRow() if err != nil { t.Fatal(err) } if row == nil { break } retRows = append(retRows, row) } expStr := c.expected.String() retStr := retRows.String() if expStr != retStr { t.Errorf("invalid results for case %d; expected:\n %s\ngot:\n %s", testIdx, expStr, retStr) } } }
func TestUnorderedSync(t *testing.T) { defer leaktest.AfterTest(t)() columnTypeInt := &sqlbase.ColumnType{Kind: sqlbase.ColumnType_INT} mrc := &MultiplexedRowChannel{} mrc.Init(5) for i := 1; i <= 5; i++ { go func(i int) { for j := 1; j <= 100; j++ { a := sqlbase.DatumToEncDatum(*columnTypeInt, parser.NewDInt(parser.DInt(i))) b := sqlbase.DatumToEncDatum(*columnTypeInt, parser.NewDInt(parser.DInt(j))) row := sqlbase.EncDatumRow{a, b} mrc.PushRow(row) } mrc.Close(nil) }(i) } var retRows sqlbase.EncDatumRows for { row, err := mrc.NextRow() if err != nil { t.Fatal(err) } if row == nil { break } retRows = append(retRows, row) } // Verify all elements. for i := 1; i <= 5; i++ { j := 1 for _, row := range retRows { if int(*(row[0].Datum.(*parser.DInt))) == i { if int(*(row[1].Datum.(*parser.DInt))) != j { t.Errorf("Expected [%d %d], got %s", i, j, row) } j++ } } if j != 101 { t.Errorf("Missing [%d %d]", i, j) } } // Test case when one source closes with an error. mrc = &MultiplexedRowChannel{} mrc.Init(5) for i := 1; i <= 5; i++ { go func(i int) { for j := 1; j <= 100; j++ { a := sqlbase.DatumToEncDatum(*columnTypeInt, parser.NewDInt(parser.DInt(i))) b := sqlbase.DatumToEncDatum(*columnTypeInt, parser.NewDInt(parser.DInt(j))) row := sqlbase.EncDatumRow{a, b} mrc.PushRow(row) } var err error if i == 3 { err = fmt.Errorf("Test error") } mrc.Close(err) }(i) } for { row, err := mrc.NextRow() if err != nil { if err.Error() != "Test error" { t.Error(err) } break } if row == nil { t.Error("Did not receive expected error") } } }
func TestEvaluator(t *testing.T) { defer leaktest.AfterTest(t)() columnTypeInt := &sqlbase.ColumnType{Kind: sqlbase.ColumnType_INT} columnTypeBool := &sqlbase.ColumnType{Kind: sqlbase.ColumnType_BOOL} v := [15]sqlbase.EncDatum{} for i := range v { v[i] = sqlbase.DatumToEncDatum(*columnTypeInt, parser.NewDInt(parser.DInt(i))) } b := [2]sqlbase.EncDatum{} b[0] = sqlbase.DatumToEncDatum(*columnTypeBool, parser.DBoolTrue) b[1] = sqlbase.DatumToEncDatum(*columnTypeBool, parser.DBoolFalse) nullInt := sqlbase.DatumToEncDatum(*columnTypeInt, parser.DNull) testCases := []struct { spec EvaluatorSpec input sqlbase.EncDatumRows expected sqlbase.EncDatumRows }{ { spec: EvaluatorSpec{ Exprs: []Expression{{Expr: "@2"}, {Expr: "(((@1)))"}}, }, input: sqlbase.EncDatumRows{ {v[1], v[2]}, {v[3], v[4]}, {v[6], v[2]}, {v[7], v[2]}, {v[8], v[4]}, {nullInt, nullInt}, }, expected: sqlbase.EncDatumRows{ {v[2], v[1]}, {v[4], v[3]}, {v[2], v[6]}, {v[2], v[7]}, {v[4], v[8]}, {nullInt, nullInt}, }, }, { spec: EvaluatorSpec{ Exprs: []Expression{ {Expr: "@1 + @2"}, {Expr: "@1 - @2"}, {Expr: "@1 >= 8"}, }, }, input: sqlbase.EncDatumRows{ {v[10], v[0]}, {v[9], v[1]}, {v[8], v[2]}, {v[7], v[3]}, {v[6], v[4]}, }, expected: sqlbase.EncDatumRows{ {v[10], v[10], b[0]}, {v[10], v[8], b[0]}, {v[10], v[6], b[0]}, {v[10], v[4], b[1]}, {v[10], v[2], b[1]}, }, }, { spec: EvaluatorSpec{ Exprs: []Expression{ {Expr: "@1 AND @1"}, {Expr: "@1 AND @2"}, {Expr: "NOT @1"}, }, }, input: sqlbase.EncDatumRows{ {b[0], b[1]}, }, expected: sqlbase.EncDatumRows{ {b[0], b[1], b[1]}, }, }, { spec: EvaluatorSpec{ Exprs: []Expression{{Expr: "1"}}, }, input: sqlbase.EncDatumRows{ {v[1], v[2]}, {v[3], v[4]}, {v[6], v[2]}, {v[7], v[2]}, {v[8], v[4]}, }, expected: sqlbase.EncDatumRows{ {v[1]}, {v[1]}, {v[1]}, {v[1]}, {v[1]}, }, }, } for _, c := range testCases { es := c.spec in := &RowBuffer{rows: c.input} out := &RowBuffer{} flowCtx := FlowCtx{ Context: context.Background(), evalCtx: &parser.EvalContext{}, } ev, err := newEvaluator(&flowCtx, &es, in, out) if err != nil { t.Fatal(err) } ev.Run(nil) if out.err != nil { t.Fatal(out.err) } if !out.closed { t.Fatalf("output RowReceiver not closed") } if result := out.rows.String(); result != c.expected.String() { t.Errorf("invalid results: %s, expected %s'", result, c.expected.String()) } } }
// TODO(irfansharif): Add tests to verify the following aggregation functions: // AVG // BOOL_AND // BOOL_OR // CONCAT_AGG // STDDEV // VARIANCE func TestAggregator(t *testing.T) { defer leaktest.AfterTest(t)() columnTypeInt := &sqlbase.ColumnType{Kind: sqlbase.ColumnType_INT} v := [15]sqlbase.EncDatum{} null := sqlbase.EncDatum{Datum: parser.DNull} for i := range v { v[i] = sqlbase.DatumToEncDatum(*columnTypeInt, parser.NewDInt(parser.DInt(i))) } testCases := []struct { spec AggregatorSpec input sqlbase.EncDatumRows expected sqlbase.EncDatumRows }{ { // SELECT MIN(@0), MAX(@0), COUNT(@0), AVG(@0), SUM(@0), STDDEV(@0), // VARIANCE(@0) GROUP BY [] (no rows). spec: AggregatorSpec{ Types: []*sqlbase.ColumnType{columnTypeInt}, Exprs: []AggregatorSpec_Expr{ { Func: AggregatorSpec_MIN, ColIdx: 0, }, { Func: AggregatorSpec_MAX, ColIdx: 0, }, { Func: AggregatorSpec_COUNT, ColIdx: 0, }, { Func: AggregatorSpec_AVG, ColIdx: 0, }, { Func: AggregatorSpec_SUM, ColIdx: 0, }, { Func: AggregatorSpec_STDDEV, ColIdx: 0, }, { Func: AggregatorSpec_VARIANCE, ColIdx: 0, }, }, }, input: sqlbase.EncDatumRows{}, expected: sqlbase.EncDatumRows{ {null, null, v[0], null, null, null, null}, }, }, { // SELECT @2, COUNT(@1), GROUP BY @2. spec: AggregatorSpec{ Types: []*sqlbase.ColumnType{columnTypeInt, columnTypeInt}, GroupCols: []uint32{1}, Exprs: []AggregatorSpec_Expr{ { Func: AggregatorSpec_IDENT, ColIdx: 1, }, { Func: AggregatorSpec_COUNT, ColIdx: 0, }, }, }, input: sqlbase.EncDatumRows{ {v[1], v[2]}, {v[3], null}, {v[6], v[2]}, {v[7], v[2]}, {v[8], v[4]}, }, expected: sqlbase.EncDatumRows{ {null, v[1]}, {v[4], v[1]}, {v[2], v[3]}, }, }, { // SELECT @2, COUNT(@1), GROUP BY @2. spec: AggregatorSpec{ Types: []*sqlbase.ColumnType{columnTypeInt, columnTypeInt}, GroupCols: []uint32{1}, Exprs: []AggregatorSpec_Expr{ { Func: AggregatorSpec_IDENT, ColIdx: 1, }, { Func: AggregatorSpec_COUNT, ColIdx: 0, }, }, }, input: sqlbase.EncDatumRows{ {v[1], v[2]}, {v[3], v[4]}, {v[6], v[2]}, {v[7], v[2]}, {v[8], v[4]}, }, expected: sqlbase.EncDatumRows{ {v[4], v[2]}, {v[2], v[3]}, }, }, { // SELECT @2, SUM(@1), GROUP BY @2. spec: AggregatorSpec{ Types: []*sqlbase.ColumnType{columnTypeInt, columnTypeInt}, GroupCols: []uint32{1}, Exprs: []AggregatorSpec_Expr{ { Func: AggregatorSpec_IDENT, ColIdx: 1, }, { Func: AggregatorSpec_SUM, ColIdx: 0, }, }, }, input: sqlbase.EncDatumRows{ {v[1], v[2]}, {v[3], v[4]}, {v[6], v[2]}, {v[7], v[2]}, {v[8], v[4]}, }, expected: sqlbase.EncDatumRows{ {v[2], v[14]}, {v[4], v[11]}, }, }, { // SELECT COUNT(@1), SUM(@1), GROUP BY [] (empty group key). spec: AggregatorSpec{ Types: []*sqlbase.ColumnType{columnTypeInt, columnTypeInt}, Exprs: []AggregatorSpec_Expr{ { Func: AggregatorSpec_COUNT, ColIdx: 0, }, { Func: AggregatorSpec_SUM, ColIdx: 0, }, }, }, input: sqlbase.EncDatumRows{ {v[1], v[2]}, {v[1], v[4]}, {v[3], v[2]}, {v[4], v[2]}, {v[5], v[4]}, }, expected: sqlbase.EncDatumRows{ {v[5], v[14]}, }, }, { // SELECT SUM DISTINCT (@1), GROUP BY [] (empty group key). spec: AggregatorSpec{ Types: []*sqlbase.ColumnType{columnTypeInt}, Exprs: []AggregatorSpec_Expr{ { Func: AggregatorSpec_SUM, Distinct: true, ColIdx: 0, }, }, }, input: sqlbase.EncDatumRows{ {v[2]}, {v[4]}, {v[2]}, {v[2]}, {v[4]}, }, expected: sqlbase.EncDatumRows{ {v[6]}, }, }, { // SELECT @1, GROUP BY [] (empty group key). spec: AggregatorSpec{ Types: []*sqlbase.ColumnType{columnTypeInt}, Exprs: []AggregatorSpec_Expr{ { Func: AggregatorSpec_IDENT, ColIdx: 0, }, }, }, input: sqlbase.EncDatumRows{ {v[1]}, {v[1]}, {v[1]}, }, expected: sqlbase.EncDatumRows{ {v[1]}, }, }, { // SELECT MAX(@1), MIN(@2), COUNT(@2), COUNT DISTINCT (@2), GROUP BY [] (empty group key). spec: AggregatorSpec{ Types: []*sqlbase.ColumnType{columnTypeInt, columnTypeInt}, Exprs: []AggregatorSpec_Expr{ { Func: AggregatorSpec_MAX, ColIdx: 0, }, { Func: AggregatorSpec_MIN, ColIdx: 1, }, { Func: AggregatorSpec_COUNT, ColIdx: 1, }, { Func: AggregatorSpec_COUNT, Distinct: true, ColIdx: 1, }, }, }, input: sqlbase.EncDatumRows{ {v[2], v[2]}, {v[1], v[4]}, {v[3], v[2]}, {v[4], v[2]}, {v[5], v[4]}, }, expected: sqlbase.EncDatumRows{ {v[5], v[2], v[5], v[2]}, }, }, } for _, c := range testCases { ags := c.spec in := &RowBuffer{rows: c.input} out := &RowBuffer{} flowCtx := FlowCtx{ Context: context.Background(), evalCtx: &parser.EvalContext{}, } ag, err := newAggregator(&flowCtx, &ags, in, out) if err != nil { t.Fatal(err) } ag.Run(nil) var expected []string for _, row := range c.expected { expected = append(expected, row.String()) } sort.Strings(expected) expStr := strings.Join(expected, "") var rets []string for { row, err := out.NextRow() if err != nil { t.Fatal(err) } if row == nil { break } rets = append(rets, row.String()) } sort.Strings(rets) retStr := strings.Join(rets, "") if expStr != retStr { t.Errorf("invalid results; expected:\n %s\ngot:\n %s", expStr, retStr) } } }