// Arg implements the parser.Args interface. func (p parameters) Arg(name string) (parser.Datum, bool) { i, err := processPositionalArgument(name) if err != nil { return nil, false } if i < 1 || int(i) > len(p) { return nil, false } arg := p[i-1].Payload if arg == nil { return parser.DNull, true } switch t := arg.(type) { case *driver.Datum_BoolVal: return parser.DBool(t.BoolVal), true case *driver.Datum_IntVal: return parser.DInt(t.IntVal), true case *driver.Datum_FloatVal: return parser.DFloat(t.FloatVal), true case *driver.Datum_BytesVal: return parser.DBytes(t.BytesVal), true case *driver.Datum_StringVal: return parser.DString(t.StringVal), true case *driver.Datum_DateVal: return parser.DDate(t.DateVal), true case *driver.Datum_TimeVal: return parser.DTimestamp{Time: t.TimeVal.GoTime()}, true case *driver.Datum_IntervalVal: return parser.DInterval{Duration: time.Duration(t.IntervalVal)}, true default: panic(fmt.Sprintf("unexpected type %T", t)) } }
func decodeTableKey(valType parser.Datum, key []byte) (parser.Datum, []byte, error) { var isNull bool if key, isNull = encoding.DecodeIfNull(key); isNull { return parser.DNull, key, nil } switch valType.(type) { case parser.DBool: rkey, i, err := encoding.DecodeVarint(key) return parser.DBool(i != 0), rkey, err case parser.DInt: rkey, i, err := encoding.DecodeVarint(key) return parser.DInt(i), rkey, err case parser.DFloat: rkey, f, err := encoding.DecodeFloat(key, nil) return parser.DFloat(f), rkey, err case parser.DString: rkey, r, err := encoding.DecodeString(key, nil) return parser.DString(r), rkey, err case parser.DBytes: rkey, r, err := encoding.DecodeString(key, nil) return parser.DBytes(r), rkey, err case parser.DDate: rkey, t, err := encoding.DecodeVarint(key) return parser.DDate(t), rkey, err case parser.DTimestamp: rkey, t, err := encoding.DecodeTime(key) return parser.DTimestamp{Time: t}, rkey, err case parser.DInterval: rkey, d, err := encoding.DecodeVarint(key) return parser.DInterval{Duration: time.Duration(d)}, rkey, err default: return nil, nil, util.Errorf("TODO(pmattis): decoded index key: %s", valType.Type()) } }
func datumFromProto(d driver.Datum) parser.Datum { arg := d.Payload if arg == nil { return parser.DNull } switch t := arg.(type) { case *driver.Datum_BoolVal: return parser.DBool(t.BoolVal) case *driver.Datum_IntVal: return parser.DInt(t.IntVal) case *driver.Datum_FloatVal: return parser.DFloat(t.FloatVal) case *driver.Datum_DecimalVal: dd := &parser.DDecimal{} if _, ok := dd.SetString(t.DecimalVal); !ok { panic(fmt.Sprintf("could not parse string %q as decimal", t.DecimalVal)) } return dd case *driver.Datum_BytesVal: return parser.DBytes(t.BytesVal) case *driver.Datum_StringVal: return parser.DString(t.StringVal) case *driver.Datum_DateVal: return parser.DDate(t.DateVal) case *driver.Datum_TimeVal: return parser.DTimestamp{Time: t.TimeVal.GoTime()} case *driver.Datum_IntervalVal: return parser.DInterval{Duration: time.Duration(t.IntervalVal)} default: panic(fmt.Sprintf("unexpected type %T", t)) } }
func datumFromProto(d driver.Datum) parser.Datum { arg := d.Payload if arg == nil { return parser.DNull } switch t := arg.(type) { case *driver.Datum_BoolVal: return parser.DBool(t.BoolVal) case *driver.Datum_IntVal: return parser.DInt(t.IntVal) case *driver.Datum_FloatVal: return parser.DFloat(t.FloatVal) case *driver.Datum_DecimalVal: dec, err := decimal.NewFromString(t.DecimalVal) if err != nil { panic(fmt.Sprintf("could not parse decimal: %v", err)) } return parser.DDecimal{Decimal: dec} case *driver.Datum_BytesVal: return parser.DBytes(t.BytesVal) case *driver.Datum_StringVal: return parser.DString(t.StringVal) case *driver.Datum_DateVal: return parser.DDate(t.DateVal) case *driver.Datum_TimeVal: return parser.DTimestamp{Time: t.TimeVal.GoTime()} case *driver.Datum_IntervalVal: return parser.DInterval{Duration: time.Duration(t.IntervalVal)} default: panic(fmt.Sprintf("unexpected type %T", t)) } }
// unmarshalColumnValue decodes the value from a key-value pair using the type // expected by the column. An error is returned if the value's type does not // match the column's type. func unmarshalColumnValue(kind ColumnType_Kind, value *roachpb.Value) (parser.Datum, *roachpb.Error) { if value == nil { return parser.DNull, nil } switch kind { case ColumnType_BOOL: v, err := value.GetInt() if err != nil { return nil, roachpb.NewError(err) } return parser.DBool(v != 0), nil case ColumnType_INT: v, err := value.GetInt() if err != nil { return nil, roachpb.NewError(err) } return parser.DInt(v), nil case ColumnType_FLOAT: v, err := value.GetFloat() if err != nil { return nil, roachpb.NewError(err) } return parser.DFloat(v), nil case ColumnType_STRING: v, err := value.GetBytes() if err != nil { return nil, roachpb.NewError(err) } return parser.DString(v), nil case ColumnType_BYTES: v, err := value.GetBytes() if err != nil { return nil, roachpb.NewError(err) } return parser.DBytes(v), nil case ColumnType_DATE: v, err := value.GetInt() if err != nil { return nil, roachpb.NewError(err) } return parser.DDate(v), nil case ColumnType_TIMESTAMP: v, err := value.GetTime() if err != nil { return nil, roachpb.NewError(err) } return parser.DTimestamp{Time: v}, nil case ColumnType_INTERVAL: v, err := value.GetInt() if err != nil { return nil, roachpb.NewError(err) } return parser.DInterval{Duration: time.Duration(v)}, nil default: return nil, roachpb.NewErrorf("unsupported column type: %s", kind) } }
// DecodeTableValue decodes a value encoded by EncodeTableValue. func DecodeTableValue(a *DatumAlloc, valType parser.Datum, b []byte) (parser.Datum, []byte, error) { // TODO(dan): Merge this and DecodeTableKey. if len(b) == 0 { return nil, nil, util.Errorf("empty slice") } if roachpb.ValueType(b[0]) == roachpb.ValueType_NULL { return parser.DNull, b[1:], nil } var err error switch valType.(type) { case *parser.DBool: var i int64 b, i, err = roachpb.DecodeIntValue(b) // No need to chunk allocate DBool as MakeDBool returns either // parser.DBoolTrue or parser.DBoolFalse. return parser.MakeDBool(parser.DBool(i != 0)), b, err case *parser.DInt: var i int64 b, i, err = roachpb.DecodeIntValue(b) return a.NewDInt(parser.DInt(i)), b, err case *parser.DFloat: var f float64 b, f, err = roachpb.DecodeFloatValue(b) return a.NewDFloat(parser.DFloat(f)), b, err case *parser.DDecimal: var d *inf.Dec b, d, err = roachpb.DecodeDecimalValue(b) dd := a.NewDDecimal(parser.DDecimal{}) dd.Set(d) return dd, b, err case *parser.DString: var data []byte b, data, err = roachpb.DecodeBytesValue(b) return a.NewDString(parser.DString(data)), b, err case *parser.DBytes: var data []byte b, data, err = roachpb.DecodeBytesValue(b) return a.NewDBytes(parser.DBytes(data)), b, err case *parser.DDate: var i int64 b, i, err = roachpb.DecodeIntValue(b) return a.NewDDate(parser.DDate(i)), b, err case *parser.DTimestamp: var t time.Time b, t, err = roachpb.DecodeTimeValue(b) return a.NewDTimestamp(parser.DTimestamp{Time: t}), b, err case *parser.DTimestampTZ: var t time.Time b, t, err = roachpb.DecodeTimeValue(b) return a.NewDTimestampTZ(parser.DTimestampTZ{Time: t}), b, err case *parser.DInterval: var d duration.Duration b, d, err = roachpb.DecodeDurationValue(b) return a.NewDInterval(parser.DInterval{Duration: d}), b, err default: return nil, nil, util.Errorf("TODO(pmattis): decoded index value: %s", valType.Type()) } }
// DecodeTableValue decodes a value encoded by EncodeTableValue. func DecodeTableValue(a *DatumAlloc, valType parser.Datum, b []byte) (parser.Datum, []byte, error) { _, dataOffset, _, typ, err := encoding.DecodeValueTag(b) if err != nil { return nil, b, err } if typ == encoding.Null { return parser.DNull, b[dataOffset:], nil } switch valType.(type) { case *parser.DBool: var x bool b, x, err = encoding.DecodeBoolValue(b) // No need to chunk allocate DBool as MakeDBool returns either // parser.DBoolTrue or parser.DBoolFalse. return parser.MakeDBool(parser.DBool(x)), b, err case *parser.DInt: var i int64 b, i, err = encoding.DecodeIntValue(b) return a.NewDInt(parser.DInt(i)), b, err case *parser.DFloat: var f float64 b, f, err = encoding.DecodeFloatValue(b) return a.NewDFloat(parser.DFloat(f)), b, err case *parser.DDecimal: var d *inf.Dec b, d, err = encoding.DecodeDecimalValue(b) dd := a.NewDDecimal(parser.DDecimal{}) dd.Set(d) return dd, b, err case *parser.DString: var data []byte b, data, err = encoding.DecodeBytesValue(b) return a.NewDString(parser.DString(data)), b, err case *parser.DBytes: var data []byte b, data, err = encoding.DecodeBytesValue(b) return a.NewDBytes(parser.DBytes(data)), b, err case *parser.DDate: var i int64 b, i, err = encoding.DecodeIntValue(b) return a.NewDDate(parser.DDate(i)), b, err case *parser.DTimestamp: var t time.Time b, t, err = encoding.DecodeTimeValue(b) return a.NewDTimestamp(parser.DTimestamp{Time: t}), b, err case *parser.DTimestampTZ: var t time.Time b, t, err = encoding.DecodeTimeValue(b) return a.NewDTimestampTZ(parser.DTimestampTZ{Time: t}), b, err case *parser.DInterval: var d duration.Duration b, d, err = encoding.DecodeDurationValue(b) return a.NewDInterval(parser.DInterval{Duration: d}), b, err default: return nil, nil, errors.Errorf("TODO(pmattis): decoded index value: %s", valType.Type()) } }
// Arg implements the parser.Args interface. func (p parameters) Arg(name string) (parser.Datum, bool) { if len(name) == 0 { // This shouldn't happen unless the parser let through an invalid parameter // specification. panic(fmt.Sprintf("invalid empty parameter name")) } if ch := name[0]; ch < '0' || ch > '9' { // TODO(pmattis): Add support for named parameters (vs the numbered // parameter support below). return nil, false } i, err := strconv.ParseInt(name, 10, 0) if err != nil { return nil, false } if i < 1 || int(i) > len(p) { return nil, false } arg := p[i-1].Payload if arg == nil { return parser.DNull, true } switch t := arg.(type) { case *driver.Datum_BoolVal: return parser.DBool(t.BoolVal), true case *driver.Datum_IntVal: return parser.DInt(t.IntVal), true case *driver.Datum_FloatVal: return parser.DFloat(t.FloatVal), true case *driver.Datum_BytesVal: return parser.DBytes(t.BytesVal), true case *driver.Datum_StringVal: return parser.DString(t.StringVal), true case *driver.Datum_DateVal: return parser.DDate(t.DateVal), true case *driver.Datum_TimeVal: return parser.DTimestamp{Time: t.TimeVal.GoTime()}, true case *driver.Datum_IntervalVal: return parser.DInterval{Duration: time.Duration(t.IntervalVal)}, true default: panic(fmt.Sprintf("unexpected type %T", t)) } }
// RandDatum generates a random Datum of the given type. // If null is true, the datum can be DNull. func RandDatum(rng *rand.Rand, typ ColumnType_Kind, null bool) parser.Datum { if null && rng.Intn(10) == 0 { return parser.DNull } switch typ { case ColumnType_BOOL: return parser.MakeDBool(rng.Intn(2) == 1) case ColumnType_INT: return parser.NewDInt(parser.DInt(rng.Int63())) case ColumnType_FLOAT: return parser.NewDFloat(parser.DFloat(rng.NormFloat64())) case ColumnType_DECIMAL: d := &parser.DDecimal{} d.Dec.SetScale(inf.Scale(rng.Intn(40) - 20)) d.Dec.SetUnscaled(rng.Int63()) return d case ColumnType_DATE: return parser.NewDDate(parser.DDate(rng.Intn(10000))) case ColumnType_TIMESTAMP: return &parser.DTimestamp{Time: time.Unix(rng.Int63n(1000000), rng.Int63n(1000000))} case ColumnType_INTERVAL: return &parser.DInterval{Duration: duration.Duration{Months: rng.Int63n(1000), Days: rng.Int63n(1000), Nanos: rng.Int63n(1000000), }} case ColumnType_STRING: // Generate a random ASCII string. p := make([]byte, rng.Intn(10)) for i := range p { p[i] = byte(1 + rng.Intn(127)) } return parser.NewDString(string(p)) case ColumnType_BYTES: p := make([]byte, rng.Intn(10)) _, _ = rng.Read(p) return parser.NewDBytes(parser.DBytes(p)) case ColumnType_TIMESTAMPTZ: return &parser.DTimestampTZ{Time: time.Unix(rng.Int63n(1000000), rng.Int63n(1000000))} default: panic(fmt.Sprintf("invalid type %s", typ)) } }
// decodeOidDatum decodes bytes with specified Oid and format code into // a datum. func decodeOidDatum(id oid.Oid, code formatCode, b []byte) (parser.Datum, error) { var d parser.Datum switch id { case oid.T_bool: switch code { case formatText: v, err := strconv.ParseBool(string(b)) if err != nil { return d, err } d = parser.DBool(v) default: return d, fmt.Errorf("unsupported bool format code: %d", code) } case oid.T_int2: switch code { case formatText: i, err := strconv.ParseInt(string(b), 10, 64) if err != nil { return d, err } d = parser.DInt(i) case formatBinary: var i int16 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &i) if err != nil { return d, err } d = parser.DInt(i) default: return d, fmt.Errorf("unsupported int2 format code: %d", code) } case oid.T_int4: switch code { case formatText: i, err := strconv.ParseInt(string(b), 10, 64) if err != nil { return d, err } d = parser.DInt(i) case formatBinary: var i int32 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &i) if err != nil { return d, err } d = parser.DInt(i) default: return d, fmt.Errorf("unsupported int4 format code: %d", code) } case oid.T_int8: switch code { case formatText: i, err := strconv.ParseInt(string(b), 10, 64) if err != nil { return d, err } d = parser.DInt(i) case formatBinary: var i int64 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &i) if err != nil { return d, err } d = parser.DInt(i) default: return d, fmt.Errorf("unsupported int8 format code: %d", code) } case oid.T_float4: switch code { case formatText: f, err := strconv.ParseFloat(string(b), 64) if err != nil { return d, err } d = parser.DFloat(f) case formatBinary: var f float32 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &f) if err != nil { return d, err } d = parser.DFloat(f) default: return d, fmt.Errorf("unsupported float4 format code: %d", code) } case oid.T_float8: switch code { case formatText: f, err := strconv.ParseFloat(string(b), 64) if err != nil { return d, err } d = parser.DFloat(f) case formatBinary: var f float64 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &f) if err != nil { return d, err } d = parser.DFloat(f) default: return d, fmt.Errorf("unsupported float8 format code: %d", code) } case oid.T_numeric: switch code { case formatText: dd := &parser.DDecimal{} if _, ok := dd.SetString(string(b)); !ok { return nil, fmt.Errorf("could not parse string %q as decimal", b) } d = dd default: return d, fmt.Errorf("unsupported numeric format code: %d", code) } case oid.T_text, oid.T_varchar: switch code { case formatText: d = parser.DString(b) default: return d, fmt.Errorf("unsupported text format code: %d", code) } case oid.T_bytea: switch code { case formatText: // http://www.postgresql.org/docs/current/static/datatype-binary.html#AEN5667 // Code cribbed from github.com/lib/pq. // We only support hex encoding. if len(b) >= 2 && bytes.Equal(b[:2], []byte("\\x")) { b = b[2:] // trim off leading "\\x" result := make([]byte, hex.DecodedLen(len(b))) _, err := hex.Decode(result, b) if err != nil { return d, err } d = parser.DBytes(result) } else { return d, fmt.Errorf("unsupported bytea encoding: %q", b) } case formatBinary: d = parser.DBytes(b) default: return d, fmt.Errorf("unsupported bytea format code: %d", code) } case oid.T_timestamp: switch code { case formatText: ts, err := pq.ParseTimestamp(nil, string(b)) if err != nil { return d, fmt.Errorf("could not parse string %q as timestamp", b) } d = parser.DTimestamp{Time: ts} case formatBinary: return d, fmt.Errorf("unsupported timestamp format code: %d", code) } case oid.T_date: switch code { case formatText: ts, err := pq.ParseTimestamp(nil, string(b)) if err != nil { return d, fmt.Errorf("could not parse string %q as date", b) } daysSinceEpoch := ts.Unix() / secondsInDay d = parser.DDate(daysSinceEpoch) case formatBinary: return d, fmt.Errorf("unsupported date format code: %d", code) } default: return d, fmt.Errorf("unsupported OID: %v", id) } return d, nil }
// UnmarshalColumnValue decodes the value from a key-value pair using the type // expected by the column. An error is returned if the value's type does not // match the column's type. func UnmarshalColumnValue( a *DatumAlloc, kind ColumnType_Kind, value *roachpb.Value, ) (parser.Datum, error) { if value == nil { return parser.DNull, nil } switch kind { case ColumnType_BOOL: v, err := value.GetInt() if err != nil { return nil, err } return parser.MakeDBool(parser.DBool(v != 0)), nil case ColumnType_INT: v, err := value.GetInt() if err != nil { return nil, err } return a.NewDInt(parser.DInt(v)), nil case ColumnType_FLOAT: v, err := value.GetFloat() if err != nil { return nil, err } return a.NewDFloat(parser.DFloat(v)), nil case ColumnType_DECIMAL: v, err := value.GetDecimal() if err != nil { return nil, err } dd := a.NewDDecimal(parser.DDecimal{}) dd.Set(v) return dd, nil case ColumnType_STRING: v, err := value.GetBytes() if err != nil { return nil, err } return a.NewDString(parser.DString(v)), nil case ColumnType_BYTES: v, err := value.GetBytes() if err != nil { return nil, err } return a.NewDBytes(parser.DBytes(v)), nil case ColumnType_DATE: v, err := value.GetInt() if err != nil { return nil, err } return a.NewDDate(parser.DDate(v)), nil case ColumnType_TIMESTAMP: v, err := value.GetTime() if err != nil { return nil, err } return a.NewDTimestamp(parser.DTimestamp{Time: v}), nil case ColumnType_TIMESTAMPTZ: v, err := value.GetTime() if err != nil { return nil, err } return a.NewDTimestampTZ(parser.DTimestampTZ{Time: v}), nil case ColumnType_INTERVAL: d, err := value.GetDuration() if err != nil { return nil, err } return a.NewDInterval(parser.DInterval{Duration: d}), nil default: return nil, util.Errorf("unsupported column type: %s", kind) } }
// DecodeTableKey decodes a table key/value. func DecodeTableKey( a *DatumAlloc, valType parser.Datum, key []byte, dir encoding.Direction, ) (parser.Datum, []byte, error) { if (dir != encoding.Ascending) && (dir != encoding.Descending) { return nil, nil, util.Errorf("invalid direction: %d", dir) } var isNull bool if key, isNull = encoding.DecodeIfNull(key); isNull { return parser.DNull, key, nil } var rkey []byte var err error switch valType.(type) { case *parser.DBool: var i int64 if dir == encoding.Ascending { rkey, i, err = encoding.DecodeVarintAscending(key) } else { rkey, i, err = encoding.DecodeVarintDescending(key) } // No need to chunk allocate DBool as MakeDBool returns either // parser.DBoolTrue or parser.DBoolFalse. return parser.MakeDBool(parser.DBool(i != 0)), rkey, err case *parser.DInt: var i int64 if dir == encoding.Ascending { rkey, i, err = encoding.DecodeVarintAscending(key) } else { rkey, i, err = encoding.DecodeVarintDescending(key) } return a.NewDInt(parser.DInt(i)), rkey, err case *parser.DFloat: var f float64 if dir == encoding.Ascending { rkey, f, err = encoding.DecodeFloatAscending(key) } else { rkey, f, err = encoding.DecodeFloatDescending(key) } return a.NewDFloat(parser.DFloat(f)), rkey, err case *parser.DDecimal: var d *inf.Dec if dir == encoding.Ascending { rkey, d, err = encoding.DecodeDecimalAscending(key, nil) } else { rkey, d, err = encoding.DecodeDecimalDescending(key, nil) } dd := a.NewDDecimal(parser.DDecimal{}) dd.Set(d) return dd, rkey, err case *parser.DString: var r string if dir == encoding.Ascending { rkey, r, err = encoding.DecodeUnsafeStringAscending(key, nil) } else { rkey, r, err = encoding.DecodeUnsafeStringDescending(key, nil) } return a.NewDString(parser.DString(r)), rkey, err case *parser.DBytes: var r []byte if dir == encoding.Ascending { rkey, r, err = encoding.DecodeBytesAscending(key, nil) } else { rkey, r, err = encoding.DecodeBytesDescending(key, nil) } return a.NewDBytes(parser.DBytes(r)), rkey, err case *parser.DDate: var t int64 if dir == encoding.Ascending { rkey, t, err = encoding.DecodeVarintAscending(key) } else { rkey, t, err = encoding.DecodeVarintDescending(key) } return a.NewDDate(parser.DDate(t)), rkey, err case *parser.DTimestamp: var t time.Time if dir == encoding.Ascending { rkey, t, err = encoding.DecodeTimeAscending(key) } else { rkey, t, err = encoding.DecodeTimeDescending(key) } return a.NewDTimestamp(parser.DTimestamp{Time: t}), rkey, err case *parser.DTimestampTZ: var t time.Time if dir == encoding.Ascending { rkey, t, err = encoding.DecodeTimeAscending(key) } else { rkey, t, err = encoding.DecodeTimeDescending(key) } return a.NewDTimestampTZ(parser.DTimestampTZ{Time: t}), rkey, err case *parser.DInterval: var d duration.Duration if dir == encoding.Ascending { rkey, d, err = encoding.DecodeDurationAscending(key) } else { rkey, d, err = encoding.DecodeDurationDescending(key) } return a.NewDInterval(parser.DInterval{Duration: d}), rkey, err default: return nil, nil, util.Errorf("TODO(pmattis): decoded index key: %s", valType.Type()) } }
func decodeTableKey(valType parser.Datum, key []byte, dir encoding.Direction) ( parser.Datum, []byte, error) { if (dir != encoding.Ascending) && (dir != encoding.Descending) { return nil, nil, util.Errorf("invalid direction: %d", dir) } var isNull bool if key, isNull = encoding.DecodeIfNull(key); isNull { return parser.DNull, key, nil } var rkey []byte var err error switch valType.(type) { case parser.DBool: var i int64 if dir == encoding.Ascending { rkey, i, err = encoding.DecodeVarintAscending(key) } else { rkey, i, err = encoding.DecodeVarintDescending(key) } return parser.DBool(i != 0), rkey, err case parser.DInt: var i int64 if dir == encoding.Ascending { rkey, i, err = encoding.DecodeVarintAscending(key) } else { rkey, i, err = encoding.DecodeVarintDescending(key) } return parser.DInt(i), rkey, err case parser.DFloat: var f float64 if dir == encoding.Ascending { rkey, f, err = encoding.DecodeFloatAscending(key, nil) } else { rkey, f, err = encoding.DecodeFloatDescending(key, nil) } return parser.DFloat(f), rkey, err case *parser.DDecimal: var d *inf.Dec if dir == encoding.Ascending { rkey, d, err = encoding.DecodeDecimalAscending(key, nil) } else { rkey, d, err = encoding.DecodeDecimalDescending(key, nil) } dd := &parser.DDecimal{} dd.Set(d) return dd, rkey, err case parser.DString: var r string if dir == encoding.Ascending { rkey, r, err = encoding.DecodeStringAscending(key, nil) } else { rkey, r, err = encoding.DecodeStringDescending(key, nil) } return parser.DString(r), rkey, err case parser.DBytes: var r []byte if dir == encoding.Ascending { rkey, r, err = encoding.DecodeBytesAscending(key, nil) } else { rkey, r, err = encoding.DecodeBytesDescending(key, nil) } return parser.DBytes(r), rkey, err case parser.DDate: var t int64 if dir == encoding.Ascending { rkey, t, err = encoding.DecodeVarintAscending(key) } else { rkey, t, err = encoding.DecodeVarintDescending(key) } return parser.DDate(t), rkey, err case parser.DTimestamp: var t time.Time if dir == encoding.Ascending { rkey, t, err = encoding.DecodeTimeAscending(key) } else { rkey, t, err = encoding.DecodeTimeDescending(key) } return parser.DTimestamp{Time: t}, rkey, err case parser.DInterval: var d int64 if dir == encoding.Ascending { rkey, d, err = encoding.DecodeVarintAscending(key) } else { rkey, d, err = encoding.DecodeVarintDescending(key) } return parser.DInterval{Duration: time.Duration(d)}, rkey, err default: return nil, nil, util.Errorf("TODO(pmattis): decoded index key: %s", valType.Type()) } }
// decodeOidDatum decodes bytes with specified Oid and format code into // a datum. func decodeOidDatum(id oid.Oid, code formatCode, b []byte) (parser.Datum, error) { var d parser.Datum switch id { case oid.T_bool: switch code { case formatText: v, err := strconv.ParseBool(string(b)) if err != nil { return d, err } d = parser.MakeDBool(parser.DBool(v)) case formatBinary: switch b[0] { case 0: d = parser.MakeDBool(false) case 1: d = parser.MakeDBool(true) default: return d, util.Errorf("unsupported binary bool: %q", b) } default: return d, util.Errorf("unsupported bool format code: %s", code) } case oid.T_int2: switch code { case formatText: i, err := strconv.ParseInt(string(b), 10, 64) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) case formatBinary: var i int16 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &i) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) default: return d, util.Errorf("unsupported int2 format code: %s", code) } case oid.T_int4: switch code { case formatText: i, err := strconv.ParseInt(string(b), 10, 64) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) case formatBinary: var i int32 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &i) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) default: return d, util.Errorf("unsupported int4 format code: %s", code) } case oid.T_int8: switch code { case formatText: i, err := strconv.ParseInt(string(b), 10, 64) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) case formatBinary: var i int64 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &i) if err != nil { return d, err } d = parser.NewDInt(parser.DInt(i)) default: return d, util.Errorf("unsupported int8 format code: %s", code) } case oid.T_float4: switch code { case formatText: f, err := strconv.ParseFloat(string(b), 64) if err != nil { return d, err } d = parser.NewDFloat(parser.DFloat(f)) case formatBinary: var f float32 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &f) if err != nil { return d, err } d = parser.NewDFloat(parser.DFloat(f)) default: return d, util.Errorf("unsupported float4 format code: %s", code) } case oid.T_float8: switch code { case formatText: f, err := strconv.ParseFloat(string(b), 64) if err != nil { return d, err } d = parser.NewDFloat(parser.DFloat(f)) case formatBinary: var f float64 err := binary.Read(bytes.NewReader(b), binary.BigEndian, &f) if err != nil { return d, err } d = parser.NewDFloat(parser.DFloat(f)) default: return d, util.Errorf("unsupported float8 format code: %s", code) } case oid.T_numeric: switch code { case formatText: dd := &parser.DDecimal{} if _, ok := dd.SetString(string(b)); !ok { return nil, util.Errorf("could not parse string %q as decimal", b) } d = dd case formatBinary: r := bytes.NewReader(b) alloc := struct { pgNum pgNumeric i16 int16 dd parser.DDecimal }{} for _, ptr := range []interface{}{ &alloc.pgNum.ndigits, &alloc.pgNum.weight, &alloc.pgNum.sign, &alloc.pgNum.dscale, } { if err := binary.Read(r, binary.BigEndian, ptr); err != nil { return d, err } } decDigits := make([]byte, 0, alloc.pgNum.ndigits*pgDecDigits) for i := int16(0); i < alloc.pgNum.ndigits-1; i++ { if err := binary.Read(r, binary.BigEndian, &alloc.i16); err != nil { return d, err } decDigits = strconv.AppendUint(decDigits, uint64(alloc.i16), 10) } // The last digit may contain padding, which we need to deal with. if err := binary.Read(r, binary.BigEndian, &alloc.i16); err != nil { return d, err } dscale := (alloc.pgNum.ndigits - 1 - alloc.pgNum.weight) * pgDecDigits if overScale := dscale - alloc.pgNum.dscale; overScale > 0 { dscale -= overScale for i := int16(0); i < overScale; i++ { alloc.i16 /= 10 } } decDigits = strconv.AppendUint(decDigits, uint64(alloc.i16), 10) alloc.dd.UnscaledBig().SetString(string(decDigits), 10) alloc.dd.SetScale(inf.Scale(dscale)) switch alloc.pgNum.sign { case pgNumericPos: case pgNumericNeg: alloc.dd.Neg(&alloc.dd.Dec) default: return d, util.Errorf("unsupported numeric sign: %s", alloc.pgNum.sign) } d = &alloc.dd default: return d, util.Errorf("unsupported numeric format code: %s", code) } case oid.T_text, oid.T_varchar: switch code { case formatText, formatBinary: d = parser.NewDString(string(b)) default: return d, util.Errorf("unsupported text format code: %s", code) } case oid.T_bytea: switch code { case formatText: // http://www.postgresql.org/docs/current/static/datatype-binary.html#AEN5667 // Code cribbed from github.com/lib/pq. // We only support hex encoding. if len(b) >= 2 && bytes.Equal(b[:2], []byte("\\x")) { b = b[2:] // trim off leading "\\x" result := make([]byte, hex.DecodedLen(len(b))) _, err := hex.Decode(result, b) if err != nil { return d, err } d = parser.NewDBytes(parser.DBytes(result)) } else { return d, util.Errorf("unsupported bytea encoding: %q", b) } case formatBinary: d = parser.NewDBytes(parser.DBytes(b)) default: return d, util.Errorf("unsupported bytea format code: %s", code) } case oid.T_timestamp, oid.T_timestamptz: switch code { case formatText: ts, err := parseTs(string(b)) if err != nil { return d, util.Errorf("could not parse string %q as timestamp", b) } d = parser.MakeDTimestamp(ts, time.Microsecond) default: return d, util.Errorf("unsupported timestamp format code: %s", code) } case oid.T_date: switch code { case formatText: ts, err := parseTs(string(b)) if err != nil { return d, util.Errorf("could not parse string %q as date", b) } daysSinceEpoch := ts.Unix() / secondsInDay d = parser.NewDDate(parser.DDate(daysSinceEpoch)) default: return d, util.Errorf("unsupported date format code: %s", code) } default: return d, util.Errorf("unsupported OID: %v", id) } return d, nil }