// 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()) } }
// processValueTuple processes the given values (of columns family.ColumnIDs), // setting values in the rf.row accordingly. The key is only used for logging. func (rf *RowFetcher) processValueTuple( family *ColumnFamilyDescriptor, kv client.KeyValue, debugStrings bool, prettyKeyPrefix string, ) (prettyKey string, prettyValue string, err error) { prettyKey = prettyKeyPrefix if debugStrings { rf.prettyValueBuf.Reset() } tupleBytes, err := kv.Value.GetTuple() if err != nil { return "", "", err } var colIDDiff uint32 var value parser.Datum var lastColID ColumnID for len(tupleBytes) > 0 { _, _, colIDDiff, _, err = encoding.DecodeValueTag(tupleBytes) if err != nil { return "", "", err } colID := lastColID + ColumnID(colIDDiff) lastColID = colID idx, ok := rf.colIdxMap[colID] // TODO(dan): Ideally rowFetcher would generate EncDatums instead of Datums // and that would make the logic simpler. We won't need valNeededForCol at // all, it would be up to the user of the class to decide if they want to // decode them or not. if !ok || !rf.valNeededForCol[idx] { // This column wasn't requested, so read its length and skip it. _, i, err := encoding.PeekValueLength(tupleBytes) if err != nil { return "", "", err } tupleBytes = tupleBytes[i:] if log.V(3) { log.Infof("Scan %s -> [%d] (skipped)", kv.Key, colID) } continue } if debugStrings { prettyKey = fmt.Sprintf("%s/%s", prettyKey, rf.desc.Columns[idx].Name) } kind := rf.cols[idx].Type.Kind.ToDatumType() value, tupleBytes, err = DecodeTableValue(&rf.alloc, kind, tupleBytes) if err != nil { return "", "", err } if debugStrings { fmt.Fprintf(&rf.prettyValueBuf, "/%v", value) } if rf.row[idx] != nil { panic(fmt.Sprintf("duplicate value for column %d", idx)) } rf.row[idx] = value if log.V(3) { log.Infof("Scan %d -> %v", idx, value) } } if debugStrings { prettyValue = rf.prettyValueBuf.String() } return prettyKey, prettyValue, nil }
// PrettyPrint returns the value in a human readable format. // e.g. `Put /Table/51/1/1/0 -> /TUPLE/2:2:Int/7/1:3:Float/6.28` // In `1:3:Float/6.28`, the `1` is the column id diff as stored, `3` is the // computed (i.e. not stored) actual column id, `Float` is the type, and `6.28` // is the encoded value. func (v Value) PrettyPrint() string { var buf bytes.Buffer t := v.GetTag() buf.WriteRune('/') buf.WriteString(t.String()) buf.WriteRune('/') var err error switch t { case ValueType_TUPLE: b := v.dataBytes() var colID uint32 for i := 0; len(b) > 0; i++ { if i != 0 { buf.WriteRune('/') } _, _, colIDDiff, typ, err := encoding.DecodeValueTag(b) if err != nil { break } colID += colIDDiff var s string b, s, err = encoding.PrettyPrintValueEncoded(b) if err != nil { break } fmt.Fprintf(&buf, "%d:%d:%s/%s", colIDDiff, colID, typ, s) } case ValueType_INT: var i int64 i, err = v.GetInt() buf.WriteString(strconv.FormatInt(i, 10)) case ValueType_FLOAT: var f float64 f, err = v.GetFloat() buf.WriteString(strconv.FormatFloat(f, 'g', -1, 64)) case ValueType_BYTES: var data []byte data, err = v.GetBytes() printable := len(bytes.TrimLeftFunc(data, unicode.IsPrint)) == 0 if printable { buf.WriteString(string(data)) } else { buf.WriteString(hex.EncodeToString(data)) } case ValueType_TIME: var t time.Time t, err = v.GetTime() buf.WriteString(t.UTC().Format(time.RFC3339Nano)) case ValueType_DECIMAL: var d *inf.Dec d, err = v.GetDecimal() buf.WriteString(d.String()) case ValueType_DURATION: var d duration.Duration d, err = v.GetDuration() buf.WriteString(d.String()) default: err = errors.Errorf("unknown tag: %s", t) } if err != nil { // Ignore the contents of buf and return directly. return fmt.Sprintf("/<err: %s>", err) } return buf.String() }