// split splits the query into multiple queries. validateQuery() must return // nil error before split() is called. func (qs *QuerySplitter) split(pkMinMax *mproto.QueryResult) []proto.QuerySplit { boundaries := qs.getSplitBoundaries(pkMinMax) splits := []proto.QuerySplit{} // No splits, return the original query as a single split if len(boundaries) == 0 { split := &proto.QuerySplit{ Query: *qs.query, } splits = append(splits, *split) } else { // Loop through the boundaries and generated modified where clauses start := sqltypes.Value{} clauses := []*sqlparser.Where{} for _, end := range boundaries { clauses = append(clauses, qs.getWhereClause(start, end)) start.Inner = end.Inner } clauses = append(clauses, qs.getWhereClause(start, sqltypes.Value{})) // Generate one split per clause for _, clause := range clauses { sel := qs.sel sel.Where = clause q := &proto.BoundQuery{ Sql: sqlparser.String(sel), BindVariables: qs.query.BindVariables, } split := &proto.QuerySplit{ Query: *q, RowCount: qs.rowCount, } splits = append(splits, *split) } } return splits }
// getWhereClause returns a whereClause based on desired upper and lower // bounds for primary key. func (qs *QuerySplitter) getWhereClause(start, end sqltypes.Value) *sqlparser.Where { var startClause *sqlparser.ComparisonExpr var endClause *sqlparser.ComparisonExpr var clauses sqlparser.BoolExpr // No upper or lower bound, just return the where clause of original query if start.IsNull() && end.IsNull() { return qs.sel.Where } pk := &sqlparser.ColName{ Name: []byte(qs.pkCol), } // pkCol >= start if !start.IsNull() { startClause = &sqlparser.ComparisonExpr{ Operator: sqlparser.AST_GE, Left: pk, Right: sqlparser.NumVal((start).Raw()), } } // pkCol < end if !end.IsNull() { endClause = &sqlparser.ComparisonExpr{ Operator: sqlparser.AST_LT, Left: pk, Right: sqlparser.NumVal((end).Raw()), } } if startClause == nil { clauses = endClause } else { if endClause == nil { clauses = startClause } else { // pkCol >= start AND pkCol < end clauses = &sqlparser.AndExpr{ Left: startClause, Right: endClause, } } } if qs.sel.Where != nil { clauses = &sqlparser.AndExpr{ Left: qs.sel.Where.Expr, Right: clauses, } } return &sqlparser.Where{ Type: sqlparser.AST_WHERE, Expr: clauses, } }
// Convert takes a type and a value, and returns the type: // - nil for NULL value // - int64 if possible, otherwise, uint64 // - float64 for floating point values that fit in a float // - []byte for everything else func Convert(mysqlType int64, val sqltypes.Value) (interface{}, error) { if val.IsNull() { return nil, nil } switch mysqlType { case VT_TINY, VT_SHORT, VT_LONG, VT_LONGLONG, VT_INT24: val := val.String() signed, err := strconv.ParseInt(val, 0, 64) if err == nil { return signed, nil } unsigned, err := strconv.ParseUint(val, 0, 64) if err == nil { return unsigned, nil } return nil, err case VT_FLOAT, VT_DOUBLE: return strconv.ParseFloat(val.String(), 64) } return val.Raw(), nil }
func validateValue(col *schema.TableColumn, value sqltypes.Value) error { if value.IsNull() { return nil } switch col.Category { case schema.CAT_NUMBER: if !value.IsNumeric() { return NewTabletError(FAIL, "type mismatch, expecting numeric type for %v", value) } case schema.CAT_VARBINARY: if !value.IsString() { return NewTabletError(FAIL, "type mismatch, expecting string type for %v", value) } } return nil }
func (ta *Table) AddColumn(name string, columnType string, defval sqltypes.Value, extra string) { index := len(ta.Columns) ta.Columns = append(ta.Columns, TableColumn{Name: name}) if strings.Contains(columnType, "int") { ta.Columns[index].Category = CAT_NUMBER } else if strings.HasPrefix(columnType, "varbinary") { ta.Columns[index].Category = CAT_VARBINARY } else { ta.Columns[index].Category = CAT_OTHER } if extra == "auto_increment" { ta.Columns[index].IsAuto = true // Ignore default value, if any return } if defval.IsNull() { return } if ta.Columns[index].Category == CAT_NUMBER { ta.Columns[index].Default = sqltypes.MakeNumeric(defval.Raw()) } else { ta.Columns[index].Default = sqltypes.MakeString(defval.Raw()) } }
// UnmarshalBson bson-decodes into QueryResult. func (queryResult *QueryResult) UnmarshalBson(buf *bytes.Buffer, kind byte) { switch kind { case bson.EOO, bson.Object: // valid case bson.Null: return default: panic(bson.NewBsonError("unexpected kind %v for QueryResult", kind)) } bson.Next(buf, 4) for kind := bson.NextByte(buf); kind != bson.EOO; kind = bson.NextByte(buf) { switch bson.ReadCString(buf) { case "Fields": // []Field if kind != bson.Null { if kind != bson.Array { panic(bson.NewBsonError("unexpected kind %v for queryResult.Fields", kind)) } bson.Next(buf, 4) queryResult.Fields = make([]Field, 0, 8) for kind := bson.NextByte(buf); kind != bson.EOO; kind = bson.NextByte(buf) { bson.SkipIndex(buf) var _v1 Field _v1.UnmarshalBson(buf, kind) queryResult.Fields = append(queryResult.Fields, _v1) } } case "RowsAffected": queryResult.RowsAffected = bson.DecodeUint64(buf, kind) case "InsertId": queryResult.InsertId = bson.DecodeUint64(buf, kind) case "Rows": // [][]sqltypes.Value if kind != bson.Null { if kind != bson.Array { panic(bson.NewBsonError("unexpected kind %v for queryResult.Rows", kind)) } bson.Next(buf, 4) queryResult.Rows = make([][]sqltypes.Value, 0, 8) for kind := bson.NextByte(buf); kind != bson.EOO; kind = bson.NextByte(buf) { bson.SkipIndex(buf) var _v2 []sqltypes.Value // []sqltypes.Value if kind != bson.Null { if kind != bson.Array { panic(bson.NewBsonError("unexpected kind %v for _v2", kind)) } bson.Next(buf, 4) _v2 = make([]sqltypes.Value, 0, 8) for kind := bson.NextByte(buf); kind != bson.EOO; kind = bson.NextByte(buf) { bson.SkipIndex(buf) var _v3 sqltypes.Value _v3.UnmarshalBson(buf, kind) _v2 = append(_v2, _v3) } } queryResult.Rows = append(queryResult.Rows, _v2) } } default: bson.Skip(buf, kind) } } }