bttest: deal with non-ASCII characters in regex
Real BigTable will match non-ASCII characters in column and row regex
filters. This change enables the same behaviour for bttest.
@@ -67,9 +67,7 @@ const (
maxValidMilliSeconds = math.MaxInt64 - math.MaxInt64%1000
)
-var (
- validLabelTransformer = regexp.MustCompile(`[a-z0-9\-]{1,15}`)
-)
+var validLabelTransformer = regexp.MustCompile(`[a-z0-9\-]{1,15}`)
// Server is an in-memory Cloud Bigtable fake.
// It is unauthenticated, and only a rough approximation.
@@ -326,9 +324,11 @@ func (s *server) SnapshotTable(context.Context, *btapb.SnapshotTableRequest) (*l
func (s *server) GetSnapshot(context.Context, *btapb.GetSnapshotRequest) (*btapb.Snapshot, error) {
return nil, status.Errorf(codes.Unimplemented, "the emulator does not currently support snapshots")
}
+
func (s *server) ListSnapshots(context.Context, *btapb.ListSnapshotsRequest) (*btapb.ListSnapshotsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "the emulator does not currently support snapshots")
}
+
func (s *server) DeleteSnapshot(context.Context, *btapb.DeleteSnapshotRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "the emulator does not currently support snapshots")
}
@@ -747,8 +747,35 @@ func includeCell(f *btpb.RowFilter, fam, col string, cell cell) (bool, error) {
}
}
+// escapeUTF is used to escape non-ASCII characters in pattern strings passed
+// to binaryregexp. This makes regexp column and row key matching work more
+// closely to what's seen with the real BigTable.
+func escapeUTF(in []byte) []byte {
+ var toEsc int
+ for _, c := range in {
+ if c > 127 {
+ toEsc++
+ }
+ }
+ if toEsc == 0 {
+ return in
+ }
+ // Each escaped byte becomes 4 bytes (byte a1 becomes \xA1)
+ out := make([]byte, 0, len(in)+3*toEsc)
+ for _, c := range in {
+ if c > 127 {
+ h, l := c>>4, c&0xF
+ const conv = "0123456789ABCDEF"
+ out = append(out, '\\', 'x', conv[h], conv[l])
+ } else {
+ out = append(out, c)
+ }
+ }
+ return out
+}
+
func newRegexp(pat []byte) (*binaryregexp.Regexp, error) {
- re, err := binaryregexp.Compile("^(?:" + string(pat) + ")$") // match entire target
+ re, err := binaryregexp.Compile("^(?:" + string(escapeUTF(pat)) + ")$") // match entire target
if err != nil {
log.Printf("Bad pattern %q: %v", pat, err)
}
