// 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)
	}
}
Beispiel #2
0
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)
		}
	}
}
Beispiel #4
0
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())
		}
	}
}
Beispiel #5
0
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")
		}
	}
}
Beispiel #10
0
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)
		}
	}
}