Ejemplo n.º 1
0
func TestCodexBuildSecondaryList(t *testing.T) {
	pk1 := "pk1"
	pk2 := "pk2"
	tableInfo := createTableInfo("Table",
		[]string{"pk1", "pk2", "col1"},
		[]string{"int", "varbinary(128)", "int"},
		[]string{pk1, pk2})

	// set pk2 = 'xyz' where pk1=1 and pk2 = 'abc'
	bindVars := map[string]interface{}{}
	pk1Val, _ := sqltypes.BuildValue(1)
	pk2Val, _ := sqltypes.BuildValue("abc")
	pkValues := []interface{}{pk1Val, pk2Val}
	pkList, _ := buildValueList(&tableInfo, pkValues, bindVars)
	pk2SecVal, _ := sqltypes.BuildValue("xyz")
	secondaryPKValues := []interface{}{nil, pk2SecVal}
	// want [[1 xyz]]
	want := [][]sqltypes.Value{
		[]sqltypes.Value{pk1Val, pk2SecVal}}
	got, _ := buildSecondaryList(&tableInfo, pkList, secondaryPKValues, bindVars)
	if !reflect.DeepEqual(got, want) {
		t.Fatalf("case 1 failed, got %v, want %v", got, want)
	}

	secondaryPKValues = []interface{}{"invalid_type", 1}
	_, err := buildSecondaryList(&tableInfo, pkList, secondaryPKValues, bindVars)
	if err == nil {
		t.Fatalf("should get an error, column 0 is int type, but secondary list provides a string")
	}
}
Ejemplo n.º 2
0
func TestSplitQueryFractionalColumn(t *testing.T) {
	schemaInfo := getSchemaInfo()
	query := &proto.BoundQuery{
		Sql: "select * from test_table where count > :count",
	}
	splitter := NewQuerySplitter(query, "", 3, schemaInfo)
	splitter.validateQuery()
	min, _ := sqltypes.BuildValue(10.5)
	max, _ := sqltypes.BuildValue(490.5)
	minField := &pbq.Field{
		Name: "min",
		Type: sqltypes.Float32,
	}
	maxField := &pbq.Field{
		Name: "max",
		Type: sqltypes.Float32,
	}
	fields := []*pbq.Field{minField, maxField}
	pkMinMax := &sqltypes.Result{
		Fields: fields,
		Rows:   [][]sqltypes.Value{[]sqltypes.Value{min, max}},
	}

	splits, err := splitter.split(sqltypes.Float32, pkMinMax)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	got := []proto.BoundQuery{}
	for _, split := range splits {
		if split.RowCount != 160 {
			t.Errorf("wrong RowCount, got: %v, want: %v", split.RowCount, 160)
		}
		got = append(got, split.Query)
	}
	want := []proto.BoundQuery{
		{
			Sql:           "select * from test_table where (count > :count) and (id < :" + endBindVarName + ")",
			BindVariables: map[string]interface{}{endBindVarName: 170.5},
		},
		{
			Sql: fmt.Sprintf("select * from test_table where (count > :count) and (id >= :%s and id < :%s)", startBindVarName, endBindVarName),
			BindVariables: map[string]interface{}{
				startBindVarName: 170.5,
				endBindVarName:   330.5,
			},
		},
		{
			Sql:           "select * from test_table where (count > :count) and (id >= :" + startBindVarName + ")",
			BindVariables: map[string]interface{}{startBindVarName: 330.5},
		},
	}
	if !reflect.DeepEqual(got, want) {
		t.Errorf("wrong splits, got: %v, want: %v", got, want)
	}
}
Ejemplo n.º 3
0
func (qs *QuerySplitter) splitBoundariesIntColumn(pkMinMax *mproto.QueryResult) ([]sqltypes.Value, error) {
	boundaries := []sqltypes.Value{}
	if pkMinMax == nil || len(pkMinMax.Rows) != 1 || pkMinMax.Rows[0][0].IsNull() || pkMinMax.Rows[0][1].IsNull() {
		return boundaries, nil
	}
	minNumeric := sqltypes.MakeNumeric(pkMinMax.Rows[0][0].Raw())
	maxNumeric := sqltypes.MakeNumeric(pkMinMax.Rows[0][1].Raw())
	if pkMinMax.Rows[0][0].Raw()[0] == '-' {
		// signed values, use int64
		min, err := minNumeric.ParseInt64()
		if err != nil {
			return nil, err
		}
		max, err := maxNumeric.ParseInt64()
		if err != nil {
			return nil, err
		}
		interval := (max - min) / int64(qs.splitCount)
		if interval == 0 {
			return nil, err
		}
		qs.rowCount = interval
		for i := int64(1); i < int64(qs.splitCount); i++ {
			v, err := sqltypes.BuildValue(min + interval*i)
			if err != nil {
				return nil, err
			}
			boundaries = append(boundaries, v)
		}
		return boundaries, nil
	}
	// unsigned values, use uint64
	min, err := minNumeric.ParseUint64()
	if err != nil {
		return nil, err
	}
	max, err := maxNumeric.ParseUint64()
	if err != nil {
		return nil, err
	}
	interval := (max - min) / uint64(qs.splitCount)
	if interval == 0 {
		return nil, err
	}
	qs.rowCount = int64(interval)
	for i := uint64(1); i < uint64(qs.splitCount); i++ {
		v, err := sqltypes.BuildValue(min + interval*i)
		if err != nil {
			return nil, err
		}
		boundaries = append(boundaries, v)
	}
	return boundaries, nil
}
Ejemplo n.º 4
0
func toChunk(start, end interface{}, number, total int) (chunk, error) {
	startValue, err := sqltypes.BuildValue(start)
	if err != nil {
		return chunk{}, fmt.Errorf("Failed to convert calculated start value (%v) into internal sqltypes.Value: %v", start, err)
	}
	endValue, err := sqltypes.BuildValue(end)
	if err != nil {
		return chunk{}, fmt.Errorf("Failed to convert calculated end value (%v) into internal sqltypes.Value: %v", end, err)
	}
	return chunk{startValue, endValue, number, total}, nil
}
Ejemplo n.º 5
0
// populateLocalMetadata creates and fills the _vt.local_metadata table,
// which is a per-tablet table that is never replicated. This allows queries
// against local_metadata to return different values on different tablets,
// which is used for communicating between Vitess and MySQL-level tools like
// Orchestrator (http://github.com/outbrain/orchestrator).
func populateLocalMetadata(mysqld MysqlDaemon, localMetadata map[string]string) error {
	log.Infof("Populating _vt.local_metadata table...")

	// Get a non-pooled DBA connection.
	conn, err := mysqld.GetDbaConnection()
	if err != nil {
		return err
	}
	defer conn.Close()

	// Disable replication on this session. We close the connection after using
	// it, so there's no need to re-enable replication when we're done.
	if _, err := conn.ExecuteFetch("SET @@session.sql_log_bin = 0", 0, false); err != nil {
		return err
	}

	// Create the database and table if necessary.
	if _, err := conn.ExecuteFetch("CREATE DATABASE IF NOT EXISTS _vt", 0, false); err != nil {
		return err
	}
	if _, err := conn.ExecuteFetch(sqlCreateLocalMetadataTable, 0, false); err != nil {
		return err
	}

	if _, err := conn.ExecuteFetch("BEGIN", 0, false); err != nil {
		return err
	}
	for name, val := range localMetadata {
		nameValue, err := sqltypes.BuildValue(name)
		if err != nil {
			return err
		}
		valValue, err := sqltypes.BuildValue(val)
		if err != nil {
			return err
		}

		queryBuf := bytes.Buffer{}
		queryBuf.WriteString("INSERT INTO _vt.local_metadata (name,value) VALUES (")
		nameValue.EncodeSQL(&queryBuf)
		queryBuf.WriteByte(',')
		valValue.EncodeSQL(&queryBuf)
		queryBuf.WriteString(") ON DUPLICATE KEY UPDATE value = ")
		valValue.EncodeSQL(&queryBuf)

		if _, err := conn.ExecuteFetch(queryBuf.String(), 0, false); err != nil {
			return err
		}
	}
	_, err = conn.ExecuteFetch("COMMIT", 0, false)
	return err
}
Ejemplo n.º 6
0
func createRowMultiPk(id int) []sqltypes.Value {
	// Map id from the one dimensional space to a two-dimensional space.
	// Examples: 0, 1, 2, 3, 4 => (0, 0), (0, 1), (1, 0), (1, 1), (2, 0)
	newID := id / 2
	subID := id % 2
	idValue, _ := sqltypes.BuildValue(int32(newID))
	subIDValue, _ := sqltypes.BuildValue(int32(subID))
	return []sqltypes.Value{
		idValue,
		subIDValue,
		sqltypes.MakeString([]byte(fmt.Sprintf("msg %d", id))),
	}
}
Ejemplo n.º 7
0
func TestSplitQuery(t *testing.T) {
	schemaInfo := getSchemaInfo()
	query := &proto.BoundQuery{
		Sql: "select * from test_table where count > :count",
	}
	splitter := NewQuerySplitter(query, "", 3, schemaInfo)
	splitter.validateQuery()
	min, _ := sqltypes.BuildValue(0)
	max, _ := sqltypes.BuildValue(300)
	minField := mproto.Field{
		Name: "min",
		Type: mproto.VT_LONGLONG,
	}
	maxField := mproto.Field{
		Name: "min",
		Type: mproto.VT_LONGLONG,
	}
	fields := []mproto.Field{minField, maxField}
	pkMinMax := &mproto.QueryResult{
		Fields: fields,
	}

	// Ensure that empty min max does not cause panic or return any error
	splits, err := splitter.split(pkMinMax)
	if err != nil {
		t.Errorf("unexpected error while splitting on empty pkMinMax, %s", err)
	}

	pkMinMax.Rows = [][]sqltypes.Value{[]sqltypes.Value{min, max}}
	splits, err = splitter.split(pkMinMax)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	got := []string{}
	for _, split := range splits {
		if split.RowCount != 100 {
			t.Errorf("wrong RowCount, got: %v, want: %v", split.RowCount, 100)
		}
		got = append(got, split.Query.Sql)
	}
	want := []string{
		"select * from test_table where count > :count and id < 100",
		"select * from test_table where count > :count and id >= 100 and id < 200",
		"select * from test_table where count > :count and id >= 200",
	}
	if !reflect.DeepEqual(got, want) {
		t.Errorf("wrong splits, got: %v, want: %v", got, want)
	}
}
Ejemplo n.º 8
0
func (rci *RowcacheInvalidator) handleDMLEvent(event *blproto.StreamEvent) {
	invalidations := int64(0)
	tableInfo := rci.qe.schemaInfo.GetTable(event.TableName)
	if tableInfo == nil {
		panic(NewTabletError(ErrFail, "Table %s not found", event.TableName))
	}
	if tableInfo.CacheType == schema.CACHE_NONE {
		return
	}

	sqlTypeKeys := make([]sqltypes.Value, 0, len(event.PKColNames))
	for _, pkTuple := range event.PKValues {
		sqlTypeKeys = sqlTypeKeys[:0]
		for _, pkVal := range pkTuple {
			key, err := sqltypes.BuildValue(pkVal)
			if err != nil {
				log.Errorf("Error building invalidation key for %#v: '%v'", event, err)
				rci.qe.queryServiceStats.InternalErrors.Add("Invalidation", 1)
				return
			}
			sqlTypeKeys = append(sqlTypeKeys, key)
		}
		newKey := validateKey(tableInfo, buildKey(sqlTypeKeys), rci.qe.queryServiceStats)
		if newKey == "" {
			continue
		}
		tableInfo.Cache.Delete(context.Background(), newKey)
		invalidations++
	}
	tableInfo.invalidations.Add(invalidations)
}
Ejemplo n.º 9
0
func EncodeValue(buf *bytes.Buffer, value interface{}) error {
	switch bindVal := value.(type) {
	case nil:
		buf.WriteString("null")
	case []sqltypes.Value:
		for i := 0; i < len(bindVal); i++ {
			if i != 0 {
				buf.WriteString(", ")
			}
			if err := EncodeValue(buf, bindVal[i]); err != nil {
				return err
			}
		}
	case [][]sqltypes.Value:
		for i := 0; i < len(bindVal); i++ {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteByte('(')
			if err := EncodeValue(buf, bindVal[i]); err != nil {
				return err
			}
			buf.WriteByte(')')
		}
	default:
		v, err := sqltypes.BuildValue(bindVal)
		if err != nil {
			return err
		}
		v.EncodeSql(buf)
	}
	return nil
}
Ejemplo n.º 10
0
func resolveValue(col *schema.TableColumn, value interface{}, bindVars map[string]interface{}) (result sqltypes.Value, err error) {
	switch v := value.(type) {
	case string:
		lookup, ok := bindVars[v[1:]]
		if !ok {
			return result, NewTabletError(FAIL, "missing bind var %s", v)
		}
		if sqlval, err := sqltypes.BuildValue(lookup); err != nil {
			return result, NewTabletError(FAIL, err.Error())
		} else {
			result = sqlval
		}
	case sqltypes.Value:
		result = v
	case nil:
		// no op
	default:
		panic(fmt.Sprintf("incompatible value type %v", v))
	}

	if err = validateValue(col, result); err != nil {
		return result, err
	}
	return result, nil
}
Ejemplo n.º 11
0
// addGeneratedRows will add from-to generated rows. The rows (their primary
// key) will be in the range [from, to).
func (sq *testQueryService) addGeneratedRows(from, to int) {
	var rows [][]sqltypes.Value
	// ksids has keyspace ids which are covered by the shard key ranges -40 and 40-80.
	ksids := []uint64{0x2000000000000000, 0x6000000000000000}

	for id := from; id < to; id++ {
		// Only return the rows which are covered by this shard.
		shardIndex := id % 2
		if sq.shardCount == 1 || shardIndex == sq.shardIndex {
			idValue, _ := sqltypes.BuildValue(int64(id))

			row := []sqltypes.Value{
				idValue,
				sqltypes.MakeString([]byte(fmt.Sprintf("Text for %v", id))),
			}
			if !sq.omitKeyspaceID {
				row = append(row, sqltypes.MakeString([]byte(fmt.Sprintf("%v", ksids[shardIndex]))))
			}
			rows = append(rows, row)
		}
	}

	if sq.rows == nil {
		sq.rows = rows
	} else {
		sq.rows = append(sq.rows, rows...)
	}
}
Ejemplo n.º 12
0
func (qs *QuerySplitter) splitBoundariesUintColumn(pkMinMax *sqltypes.Result) ([]sqltypes.Value, error) {
	boundaries := []sqltypes.Value{}
	if pkMinMax == nil || len(pkMinMax.Rows) != 1 || pkMinMax.Rows[0][0].IsNull() || pkMinMax.Rows[0][1].IsNull() {
		return boundaries, nil
	}
	minNumeric := pkMinMax.Rows[0][0]
	maxNumeric := pkMinMax.Rows[0][1]
	min, err := minNumeric.ParseUint64()
	if err != nil {
		return nil, err
	}
	max, err := maxNumeric.ParseUint64()
	if err != nil {
		return nil, err
	}
	interval := (max - min) / uint64(qs.splitCount)
	if interval == 0 {
		return nil, err
	}
	qs.rowCount = int64(interval)
	for i := uint64(1); i < uint64(qs.splitCount); i++ {
		v, err := sqltypes.BuildValue(min + interval*i)
		if err != nil {
			return nil, err
		}
		boundaries = append(boundaries, v)
	}
	return boundaries, nil
}
Ejemplo n.º 13
0
func createRowSinglePk(id int) []sqltypes.Value {
	idValue, _ := sqltypes.BuildValue(int32(id))
	return []sqltypes.Value{
		idValue,
		sqltypes.MakeString([]byte(fmt.Sprintf("msg %d", id))),
	}
}
Ejemplo n.º 14
0
func (qs *QuerySplitter) splitBoundariesFloatColumn(pkMinMax *sqltypes.Result) ([]sqltypes.Value, error) {
	boundaries := []sqltypes.Value{}
	if pkMinMax == nil || len(pkMinMax.Rows) != 1 || pkMinMax.Rows[0][0].IsNull() || pkMinMax.Rows[0][1].IsNull() {
		return boundaries, nil
	}
	min, err := strconv.ParseFloat(pkMinMax.Rows[0][0].String(), 64)
	if err != nil {
		return nil, err
	}
	max, err := strconv.ParseFloat(pkMinMax.Rows[0][1].String(), 64)
	if err != nil {
		return nil, err
	}
	interval := (max - min) / float64(qs.splitCount)
	if interval == 0 {
		return nil, err
	}
	qs.rowCount = int64(interval)
	for i := 1; i < int(qs.splitCount); i++ {
		boundary := min + interval*float64(i)
		v, err := sqltypes.BuildValue(boundary)
		if err != nil {
			return nil, err
		}
		boundaries = append(boundaries, v)
	}
	return boundaries, nil
}
Ejemplo n.º 15
0
func (rowCache *InvalidationProcessor) buildDmlData(event *mysqlctl.UpdateResponse) (*proto.DmlType, error) {
	if !isDmlEvent(event.SqlType) {
		rowCache.updateErrCounters(NewInvalidationError(INVALID_EVENT, fmt.Sprintf("Bad Dml type, '%v'", event.SqlType), event.BinlogPosition.String()))
		return nil, nil
	}
	dml := new(proto.DmlType)
	dml.Table = event.TableName
	dml.Keys = make([]interface{}, 0, len(event.PkValues))
	sqlTypeKeys := make([]sqltypes.Value, 0, len(event.PkColNames))
	for _, pkTuple := range event.PkValues {
		sqlTypeKeys = sqlTypeKeys[:0]
		if len(pkTuple) == 0 {
			continue
		}
		for _, pkVal := range pkTuple {
			key, err := sqltypes.BuildValue(pkVal)
			if err != nil {
				rowCache.updateErrCounters(NewInvalidationError(INVALID_EVENT, fmt.Sprintf("Error building invalidation key '%v'", err), event.BinlogPosition.String()))
				return nil, nil
			}
			sqlTypeKeys = append(sqlTypeKeys, key)
		}
		invalidateKey := buildKey(sqlTypeKeys)
		if invalidateKey != "" {
			dml.Keys = append(dml.Keys, invalidateKey)
		}
	}
	return dml, nil
}
Ejemplo n.º 16
0
// Returns an escaped literal string
func Literal(v interface{}) Expression {
	value, err := sqltypes.BuildValue(v)
	if err != nil {
		panic("sqlbuilder: invalid literal value: " + err.Error())
	}
	return &literalExpression{value: value}
}
Ejemplo n.º 17
0
// writeStartedSwap registers in the _vt.shard_metadata table in the database the information
// about the new schema swap process being started.
func (shardSwap *shardSchemaSwap) writeStartedSwap(sql string) error {
	tablet, err := shardSwap.getMasterTablet()
	if err != nil {
		return err
	}
	query := fmt.Sprintf(
		"INSERT INTO _vt.shard_metadata (name, value) VALUES ('%s', '%d') ON DUPLICATE KEY UPDATE value = '%d'",
		lastStartedMetadataName, shardSwap.parent.swapID, shardSwap.parent.swapID)
	_, err = shardSwap.executeAdminQuery(tablet, query, 0 /* maxRows */)
	if err != nil {
		return err
	}
	queryBuf := bytes.Buffer{}
	queryBuf.WriteString("INSERT INTO _vt.shard_metadata (name, value) VALUES ('")
	queryBuf.WriteString(currentSQLMetadataName)
	queryBuf.WriteString("',")
	sqlValue, err := sqltypes.BuildValue(sql)
	if err != nil {
		return err
	}
	sqlValue.EncodeSQL(&queryBuf)
	queryBuf.WriteString(") ON DUPLICATE KEY UPDATE value = ")
	sqlValue.EncodeSQL(&queryBuf)
	_, err = shardSwap.executeAdminQuery(tablet, queryBuf.String(), 0 /* maxRows */)
	return err
}
Ejemplo n.º 18
0
func getSchemaInfo() *SchemaInfo {
	table := &schema.Table{
		Name: "test_table",
	}
	zero, _ := sqltypes.BuildValue(0)
	table.AddColumn("id", sqltypes.Int64, zero, "")
	table.AddColumn("id2", sqltypes.Int64, zero, "")
	table.AddColumn("count", sqltypes.Int64, zero, "")
	table.PKColumns = []int{0}
	primaryIndex := table.AddIndex("PRIMARY")
	primaryIndex.AddColumn("id", 12345)

	id2Index := table.AddIndex("idx_id2")
	id2Index.AddColumn("id2", 1234)

	tables := make(map[string]*TableInfo, 1)
	tables["test_table"] = &TableInfo{Table: table}

	tableNoPK := &schema.Table{
		Name: "test_table_no_pk",
	}
	tableNoPK.AddColumn("id", sqltypes.Int64, zero, "")
	tableNoPK.PKColumns = []int{}
	tables["test_table_no_pk"] = &TableInfo{Table: tableNoPK}

	return &SchemaInfo{tables: tables}
}
Ejemplo n.º 19
0
func (qs *QuerySplitter) parseFloat(pkMinMax *mproto.QueryResult) ([]sqltypes.Value, error) {
	boundaries := []sqltypes.Value{}
	min, err := strconv.ParseFloat(pkMinMax.Rows[0][0].String(), 64)
	if err != nil {
		return nil, err
	}
	max, err := strconv.ParseFloat(pkMinMax.Rows[0][1].String(), 64)
	if err != nil {
		return nil, err
	}
	interval := (max - min) / float64(qs.splitCount)
	if interval == 0 {
		return nil, err
	}
	qs.rowCount = int64(interval)
	for i := 1; i < qs.splitCount; i++ {
		boundary := min + interval*float64(i)
		v, err := sqltypes.BuildValue(boundary)
		if err != nil {
			return nil, err
		}
		boundaries = append(boundaries, v)
	}
	return boundaries, nil
}
Ejemplo n.º 20
0
func TestSplitQuery(t *testing.T) {
	schemaInfo := getSchemaInfo()
	query := &proto.BoundQuery{
		Sql: "select * from test_table where count > :count",
	}
	splitter := NewQuerySplitter(query, 3, schemaInfo)
	splitter.validateQuery()
	min, _ := sqltypes.BuildValue(0)
	max, _ := sqltypes.BuildValue(300)
	minField := mproto.Field{
		Name: "min",
		Type: mproto.VT_LONGLONG,
	}
	maxField := mproto.Field{
		Name: "min",
		Type: mproto.VT_LONGLONG,
	}
	fields := []mproto.Field{minField, maxField}
	row := []sqltypes.Value{min, max}
	rows := [][]sqltypes.Value{row}
	pkMinMax := &mproto.QueryResult{
		Rows:   rows,
		Fields: fields,
	}
	splits := splitter.split(pkMinMax)
	got := []string{}
	for _, split := range splits {
		if split.RowCount != 100 {
			t.Errorf("wrong RowCount, got: %v, want: %v", split.RowCount, 100)
		}
		got = append(got, split.Query.Sql)
	}
	want := []string{
		"select * from test_table where count > :count and id < 100",
		"select * from test_table where count > :count and id >= 100 and id < 200",
		"select * from test_table where count > :count and id >= 200",
	}
	if !reflect.DeepEqual(got, want) {
		t.Errorf("wrong splits, got: %v, want: %v", got, want)
	}
}
Ejemplo n.º 21
0
func TestBuildStreamComment(t *testing.T) {
	pk1 := "pk1"
	pk2 := "pk2"
	tableInfo := createTableInfo("Table",
		map[string]string{pk1: "int", pk2: "varchar(128)", "col1": "int"},
		[]string{pk1, pk2})

	// set pk2 = 'xyz' where pk1=1 and pk2 = 'abc'
	bindVars := map[string]interface{}{}
	pk1Val, _ := sqltypes.BuildValue(1)
	pk2Val, _ := sqltypes.BuildValue("abc")
	pkValues := []interface{}{pk1Val, pk2Val}
	pkList, _ := buildValueList(&tableInfo, pkValues, bindVars)
	pk2SecVal, _ := sqltypes.BuildValue("xyz")
	secondaryPKValues := []interface{}{nil, pk2SecVal}
	secondaryList, _ := buildSecondaryList(&tableInfo, pkList, secondaryPKValues, bindVars)
	want := []byte(" /* _stream Table (pk1 pk2 ) (1 'YWJj' ) (1 'eHl6' ); */")
	got := buildStreamComment(&tableInfo, pkList, secondaryList)
	if !reflect.DeepEqual(got, want) {
		t.Errorf("case 1 failed, got %v, want %v", got, want)
	}
}
Ejemplo n.º 22
0
func TestBuildSecondaryList(t *testing.T) {
	pk1 := "pk1"
	pk2 := "pk2"
	tableInfo := createTableInfo("Table",
		map[string]string{pk1: "int", pk2: "varchar(128)", "col1": "int"},
		[]string{pk1, pk2})

	// set pk2 = 'xyz' where pk1=1 and pk2 = 'abc'
	bindVars := map[string]interface{}{}
	pk1Val, _ := sqltypes.BuildValue(1)
	pk2Val, _ := sqltypes.BuildValue("abc")
	pkValues := []interface{}{pk1Val, pk2Val}
	pkList, _ := buildValueList(&tableInfo, pkValues, bindVars)
	pk2SecVal, _ := sqltypes.BuildValue("xyz")
	secondaryPKValues := []interface{}{nil, pk2SecVal}
	// want [[1 xyz]]
	want := [][]sqltypes.Value{
		[]sqltypes.Value{pk1Val, pk2SecVal}}
	got, _ := buildSecondaryList(&tableInfo, pkList, secondaryPKValues, bindVars)
	if !reflect.DeepEqual(got, want) {
		t.Errorf("case 1 failed, got %v, want %v", got, want)
	}
}
Ejemplo n.º 23
0
func TestBuildINValueList(t *testing.T) {
	pk1 := "pk1"
	tableInfo := createTableInfo("Table",
		map[string]string{pk1: "int", "col1": "int"},
		[]string{pk1})

	// case 1: single PK IN clause
	// e.g. where pk1 in(1, 2, 3)
	bindVars := map[string]interface{}{}
	pk1Val, _ := sqltypes.BuildValue(1)
	pk1Val2, _ := sqltypes.BuildValue(2)
	pk1Val3, _ := sqltypes.BuildValue(3)
	pkValues := []interface{}{pk1Val, pk1Val2, pk1Val3}
	// want [[1][2][3]]
	want := [][]sqltypes.Value{
		[]sqltypes.Value{pk1Val},
		[]sqltypes.Value{pk1Val2},
		[]sqltypes.Value{pk1Val3}}
	got, _ := buildINValueList(&tableInfo, pkValues, bindVars)
	if !reflect.DeepEqual(got, want) {
		t.Errorf("case 1 failed, got %v, want %v", got, want)
	}
}
Ejemplo n.º 24
0
func TestCodexBuildStreamComment(t *testing.T) {
	pk1 := "pk1"
	pk2 := "pk2"
	tableInfo := createTableInfo("Table",
		[]string{"pk1", "pk2", "col1"},
		[]querypb.Type{sqltypes.Int64, sqltypes.VarBinary, sqltypes.Int32},
		[]string{pk1, pk2})

	// set pk2 = 'xyz' where pk1=1 and pk2 = 'abc'
	bindVars := map[string]interface{}{}
	pk1Val, _ := sqltypes.BuildValue(1)
	pk2Val, _ := sqltypes.BuildValue("abc")
	pkValues := []interface{}{pk1Val, pk2Val}
	pkList, _ := buildValueList(&tableInfo, pkValues, bindVars)
	pk2SecVal, _ := sqltypes.BuildValue("xyz")
	secondaryPKValues := []interface{}{nil, pk2SecVal}
	secondaryList, _ := buildSecondaryList(&tableInfo, pkList, secondaryPKValues, bindVars)
	want := []byte(" /* _stream Table (pk1 pk2 ) (1 'YWJj' ) (1 'eHl6' ); */")
	got := buildStreamComment(&tableInfo, pkList, secondaryList)
	if !reflect.DeepEqual(got, want) {
		t.Fatalf("case 1 failed, got %v, want %v", got, want)
	}
}
Ejemplo n.º 25
0
// EncodeValue encodes one bind variable value into the query.
func EncodeValue(buf *bytes.Buffer, value interface{}) error {
	switch bindVal := value.(type) {
	case nil:
		buf.WriteString("null")
	case []sqltypes.Value:
		for i := 0; i < len(bindVal); i++ {
			if i != 0 {
				buf.WriteString(", ")
			}
			if err := EncodeValue(buf, bindVal[i]); err != nil {
				return err
			}
		}
	case [][]sqltypes.Value:
		for i := 0; i < len(bindVal); i++ {
			if i != 0 {
				buf.WriteString(", ")
			}
			buf.WriteByte('(')
			if err := EncodeValue(buf, bindVal[i]); err != nil {
				return err
			}
			buf.WriteByte(')')
		}
	case []interface{}:
		buf.WriteByte('(')
		for i, v := range bindVal {
			if i != 0 {
				buf.WriteString(", ")
			}
			if err := EncodeValue(buf, v); err != nil {
				return err
			}
		}
		buf.WriteByte(')')
	case TupleEqualityList:
		if err := bindVal.Encode(buf); err != nil {
			return err
		}
	default:
		v, err := sqltypes.BuildValue(bindVal)
		if err != nil {
			return err
		}
		v.EncodeSQL(buf)
	}
	return nil
}
Ejemplo n.º 26
0
func TestGetSplitBoundaries(t *testing.T) {
	min, _ := sqltypes.BuildValue(10)
	max, _ := sqltypes.BuildValue(60)
	row := []sqltypes.Value{min, max}
	rows := [][]sqltypes.Value{row}

	minField := mproto.Field{Name: "min", Type: mproto.VT_LONGLONG}
	maxField := mproto.Field{Name: "max", Type: mproto.VT_LONGLONG}
	fields := []mproto.Field{minField, maxField}

	pkMinMax := &mproto.QueryResult{
		Fields: fields,
		Rows:   rows,
	}

	splitter := &QuerySplitter{}
	splitter.splitCount = 5
	boundaries := splitter.getSplitBoundaries(pkMinMax)
	if len(boundaries) != splitter.splitCount-1 {
		t.Errorf("wrong number of boundaries got: %v, want: %v", len(boundaries), splitter.splitCount-1)
	}
	got := splitter.getSplitBoundaries(pkMinMax)
	want := []sqltypes.Value{buildVal(20), buildVal(30), buildVal(40), buildVal(50)}
	if !reflect.DeepEqual(got, want) {
		t.Errorf("incorrect boundaries, got: %v, want: %v", got, want)
	}

	// Test negative min value
	min, _ = sqltypes.BuildValue(-100)
	max, _ = sqltypes.BuildValue(100)
	row = []sqltypes.Value{min, max}
	rows = [][]sqltypes.Value{row}
	pkMinMax.Rows = rows
	got = splitter.getSplitBoundaries(pkMinMax)
	want = []sqltypes.Value{buildVal(-60), buildVal(-20), buildVal(20), buildVal(60)}
	if !reflect.DeepEqual(got, want) {
		t.Errorf("incorrect boundaries, got: %v, want: %v", got, want)
	}

	// Test float min max
	min, _ = sqltypes.BuildValue(10.5)
	max, _ = sqltypes.BuildValue(60.5)
	row = []sqltypes.Value{min, max}
	rows = [][]sqltypes.Value{row}
	minField = mproto.Field{Name: "min", Type: mproto.VT_DOUBLE}
	maxField = mproto.Field{Name: "max", Type: mproto.VT_DOUBLE}
	fields = []mproto.Field{minField, maxField}
	pkMinMax.Rows = rows
	pkMinMax.Fields = fields
	got = splitter.getSplitBoundaries(pkMinMax)
	want = []sqltypes.Value{buildVal(20.5), buildVal(30.5), buildVal(40.5), buildVal(50.5)}
	if !reflect.DeepEqual(got, want) {
		t.Errorf("incorrect boundaries, got: %v, want: %v", got, want)
	}
}
Ejemplo n.º 27
0
// TODO(shengzhe): support split based on min, max from the string column.
func (qs *QuerySplitter) splitBoundariesStringColumn() ([]sqltypes.Value, error) {
	splitRange := int64(0xFFFFFFFF) + 1
	splitSize := splitRange / int64(qs.splitCount)
	//TODO(shengzhe): have a better estimated row count based on table size.
	qs.rowCount = int64(splitSize)
	var boundaries []sqltypes.Value
	for i := 1; i < int(qs.splitCount); i++ {
		buf := make([]byte, 4)
		binary.BigEndian.PutUint32(buf, uint32(splitSize)*uint32(i))
		val, err := sqltypes.BuildValue(buf)
		if err != nil {
			return nil, err
		}
		boundaries = append(boundaries, val)
	}
	return boundaries, nil
}
Ejemplo n.º 28
0
// getSchema returns a fake schema object that can be given to SplitParams
func getTestSchema() map[string]*schema.Table {
	table := schema.Table{
		Name: "test_table",
	}
	zero, _ := sqltypes.BuildValue(0)
	table.AddColumn("id", sqltypes.Int64, zero, "")
	table.AddColumn("int32_col", sqltypes.Int32, zero, "")
	table.AddColumn("uint32_col", sqltypes.Uint32, zero, "")
	table.AddColumn("int64_col", sqltypes.Int64, zero, "")
	table.AddColumn("uint64_col", sqltypes.Uint64, zero, "")
	table.AddColumn("float32_col", sqltypes.Float32, zero, "")
	table.AddColumn("float64_col", sqltypes.Float64, zero, "")
	table.AddColumn("user_id", sqltypes.Int64, zero, "")
	table.AddColumn("user_id2", sqltypes.Int64, zero, "")
	table.AddColumn("id2", sqltypes.Int64, zero, "")
	table.AddColumn("count", sqltypes.Int64, zero, "")
	table.PKColumns = []int{0, 7}
	addIndexToTable(&table, "PRIMARY", "id", "user_id")
	addIndexToTable(&table, "idx_id2", "id2")
	addIndexToTable(&table, "idx_int64_col", "int64_col")
	addIndexToTable(&table, "idx_uint64_col", "uint64_col")
	addIndexToTable(&table, "idx_float64_col", "float64_col")
	addIndexToTable(&table, "idx_id_user_id", "id", "user_id")
	addIndexToTable(&table, "idx_id_user_id_user_id_2", "id", "user_id", "user_id2")

	table.SetMysqlStats(
		int64Value(1000), /* TableRows */
		int64Value(100),  /* DataLength */
		int64Value(123),  /* IndexLength */
		int64Value(456),  /* DataFree */
	)

	result := make(map[string]*schema.Table)
	result["test_table"] = &table

	tableNoPK := schema.Table{
		Name: "test_table_no_pk",
	}
	tableNoPK.AddColumn("id", sqltypes.Int64, zero, "")
	tableNoPK.PKColumns = []int{}
	result["test_table_no_pk"] = &tableNoPK

	return result
}
Ejemplo n.º 29
0
func resolveListArg(col *schema.TableColumn, key string, bindVars map[string]interface{}) ([]sqltypes.Value, error) {
	val, _, err := sqlparser.FetchBindVar(key, bindVars)
	if err != nil {
		return nil, NewTabletError(ErrFail, vtrpc.ErrorCode_BAD_INPUT, "%v", err)
	}
	list := val.([]interface{})
	resolved := make([]sqltypes.Value, len(list))
	for i, v := range list {
		sqlval, err := sqltypes.BuildValue(v)
		if err != nil {
			return nil, NewTabletError(ErrFail, vtrpc.ErrorCode_BAD_INPUT, "%v", err)
		}
		if err = validateValue(col, sqlval); err != nil {
			return nil, err
		}
		resolved[i] = sqlval
	}
	return resolved, nil
}
Ejemplo n.º 30
0
func getSchemaInfo() *SchemaInfo {
	table := &schema.Table{
		Name: "test_table",
	}
	zero, _ := sqltypes.BuildValue(0)
	table.AddColumn("id", "int", zero, "")
	table.AddColumn("count", "int", zero, "")
	table.PKColumns = []int{0}

	tables := make(map[string]*TableInfo, 1)
	tables["test_table"] = &TableInfo{Table: table}

	tableNoPK := &schema.Table{
		Name: "test_table_no_pk",
	}
	tableNoPK.AddColumn("id", "int", zero, "")
	tableNoPK.PKColumns = []int{}
	tables["test_table_no_pk"] = &TableInfo{Table: tableNoPK}

	return &SchemaInfo{tables: tables}
}