func unmarshalValue(col structured.ColumnDescriptor, kv client.KeyValue) sqlwire.Datum { var d sqlwire.Datum if !kv.Exists() { return d } switch col.Type.Kind { case structured.ColumnType_BIT, structured.ColumnType_INT: tmp := kv.ValueInt() d.IntVal = &tmp case structured.ColumnType_FLOAT: tmp := math.Float64frombits(uint64(kv.ValueInt())) d.FloatVal = &tmp case structured.ColumnType_CHAR, structured.ColumnType_TEXT, structured.ColumnType_BLOB: // TODO(pmattis): The conversion to string isn't strictly necessary, but // makes log messages more readable right now. tmp := string(kv.ValueBytes()) d.StringVal = &tmp } return d }
// Prepare the arguments for a binary operation. The returned arguments will // have the same type. The typ parameter specifies the allowed types for the // operation. For example, bit-operations should specify intOp or uintOp to // indicate that they do not operate on floating point arguments. Float // operations may still reduce to intOp or uintOp if the operands support it. func prepareBinaryArgs(typ opType, left, right sqlwire.Datum) (opType, sqlwire.Datum, sqlwire.Datum, error) { var err error switch typ { case intOp, uintOp: if left.UintVal != nil || right.UintVal != nil { left, err = left.ToUint() if err != nil { return uintOp, null, null, err } right, err = right.ToUint() if err != nil { return uintOp, null, null, err } return uintOp, left, right, nil } left, err = left.ToInt() if err != nil { return intOp, null, null, err } right, err = right.ToInt() if err != nil { return intOp, null, null, err } return intOp, left, right, nil case floatOp: if (left.UintVal != nil && (right.IntVal != nil || right.UintVal != nil)) || (right.UintVal != nil && (left.IntVal != nil || left.UintVal != nil)) { left, err = left.ToUint() if err != nil { return uintOp, null, null, err } right, err = right.ToUint() if err != nil { return uintOp, null, null, err } return uintOp, left, right, nil } if left.IntVal != nil && right.IntVal != nil { return intOp, left, right, nil } } left, err = left.ToFloat() if err != nil { return floatOp, null, null, err } right, err = right.ToFloat() if err != nil { return floatOp, null, null, err } return floatOp, left, right, nil }
// Prepare the arguments for a comparison operation. The returned arguments // will have the same type. func prepareComparisonArgs(left, right sqlwire.Datum) (opType, sqlwire.Datum, sqlwire.Datum, error) { // If both arguments are strings (or string-like), compare as strings. if (left.BytesVal != nil || left.StringVal != nil) && (right.BytesVal != nil || right.StringVal != nil) { return stringOp, left.ToString(), right.ToString(), nil } // If both arguments are uints, compare as unsigned. if left.UintVal != nil && right.UintVal != nil { return uintOp, left, right, nil } var err error // If both arguments are integers (signed or unsigned), compare as integers. if (left.BoolVal != nil || left.IntVal != nil || left.UintVal != nil) && (right.BoolVal != nil || right.IntVal != nil || right.UintVal != nil) { left, err = left.ToInt() if err != nil { return intOp, null, null, err } right, err = right.ToInt() if err != nil { return intOp, null, null, err } return intOp, left, right, nil } // In all other cases, compare as floats. left, err = left.ToFloat() if err != nil { return intOp, null, null, err } right, err = right.ToFloat() if err != nil { return intOp, null, null, err } return floatOp, left, right, nil }