// EncDatumFromBuffer initializes an EncDatum with an encoding that is // possibly followed by other data. Similar to EncDatumFromEncoded, // except that this function figures out where the encoding stops and returns a // slice for the rest of the buffer. func EncDatumFromBuffer(typ ColumnType, enc DatumEncoding, buf []byte) (EncDatum, []byte, error) { switch enc { case DatumEncoding_ASCENDING_KEY, DatumEncoding_DESCENDING_KEY: encLen, err := encoding.PeekLength(buf) if err != nil { return EncDatum{}, nil, err } ed := EncDatumFromEncoded(typ, enc, buf[:encLen]) return ed, buf[encLen:], nil case DatumEncoding_VALUE: typeOffset, encLen, err := encoding.PeekValueLength(buf) if err != nil { return EncDatum{}, nil, err } ed := EncDatumFromEncoded(typ, enc, buf[typeOffset:encLen]) return ed, buf[encLen:], nil default: panic(fmt.Sprintf("unknown encoding %s", enc)) } }
// SetFromBuffer initializes the EncDatum with an encoding that is possibly // followed by other data. Similar to SetEncoded, except that this function // figures out where the encoding stops and returns a slice for the rest of the // buffer. func (ed *EncDatum) SetFromBuffer( typ ColumnType_Kind, enc DatumEncoding, buf []byte, ) (remaining []byte, err error) { switch enc { case DatumEncoding_ASCENDING_KEY, DatumEncoding_DESCENDING_KEY: encLen, err := encoding.PeekLength(buf) if err != nil { return nil, err } ed.SetEncoded(typ, enc, buf[:encLen]) return buf[encLen:], nil case DatumEncoding_VALUE: typeOffset, encLen, err := encoding.PeekValueLength(buf) if err != nil { return nil, err } ed.SetEncoded(typ, enc, buf[typeOffset:encLen]) return buf[encLen:], nil default: panic(fmt.Sprintf("unknown encoding %s", ed.encoding)) } }
// 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 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] if !ok || !rf.valNeededForCol[idx] { // This column wasn't requested, so read its length and skip it. _, len, err := encoding.PeekValueLength(tupleBytes) if err != nil { return "", "", err } tupleBytes = tupleBytes[len:] if log.V(3) { log.Infof(context.TODO(), "Scan %s -> [%d] (skipped)", kv.Key, colID) } continue } if debugStrings { prettyKey = fmt.Sprintf("%s/%s", prettyKey, rf.desc.Columns[idx].Name) } var encValue EncDatum encValue, tupleBytes, err = EncDatumFromBuffer(rf.cols[idx].Type, DatumEncoding_VALUE, tupleBytes) if err != nil { return "", "", err } if debugStrings { err := encValue.EnsureDecoded(&rf.alloc) if err != nil { return "", "", err } fmt.Fprintf(&rf.prettyValueBuf, "/%v", encValue.Datum) } if !rf.row[idx].IsUnset() { panic(fmt.Sprintf("duplicate value for column %d", idx)) } rf.row[idx] = encValue if log.V(3) { log.Infof(context.TODO(), "Scan %d -> %v", idx, encValue) } } if debugStrings { prettyValue = rf.prettyValueBuf.String() } return prettyKey, prettyValue, nil }
// 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(context.TODO(), "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(context.TODO(), "Scan %d -> %v", idx, value) } } if debugStrings { prettyValue = rf.prettyValueBuf.String() } return prettyKey, prettyValue, nil }