Repository navigation
fix(bigtable): preserve empty row keys in RowRange and fix UTF-8 prefix bounds #18882
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b792911
b8c452c
6735ff7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,8 @@ | |
|
|
||
| """User-friendly container for Google Cloud Bigtable RowSet""" | ||
|
|
||
| from google.cloud._helpers import _to_bytes # type: ignore | ||
|
|
||
| from google.cloud.bigtable.data.read_rows_query import ( | ||
| ReadRowsQuery, | ||
| ) | ||
|
|
@@ -121,14 +123,21 @@ def add_row_range_with_prefix(self, row_key_prefix): | |
| :start-after: [START bigtable_api_add_row_range_with_prefix] | ||
| :end-before: [END bigtable_api_add_row_range_with_prefix] | ||
|
|
||
| :type row_key_prefix: str | ||
| :type row_key_prefix: str | bytes | ||
| :param row_key_prefix: To retrieve all rows that start with this row key prefix. | ||
| Prefix cannot be zero length.""" | ||
|
|
||
| end_key = row_key_prefix[:-1] + chr(ord(row_key_prefix[-1]) + 1) | ||
| self.add_row_range_from_keys( | ||
| row_key_prefix.encode("utf-8"), end_key.encode("utf-8") | ||
| ) | ||
| prefix_bytes = _to_bytes(row_key_prefix, encoding="utf-8") | ||
| if not prefix_bytes: | ||
| raise ValueError("row_key_prefix cannot be empty.") | ||
| # Carry the +1 increment past any trailing 0xFF (max byte) bytes; | ||
| # if all bytes are 0xFF, no larger prefix exists so the upper bound is None. | ||
| stripped = prefix_bytes.rstrip(b"\xff") | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why is \xff a special case?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| if not stripped: | ||
| end_key = None | ||
| else: | ||
| end_key = stripped[:-1] + bytes([stripped[-1] + 1]) | ||
| self.add_row_range_from_keys(prefix_bytes, end_key) | ||
|
|
||
|
|
||
| class RowRange(_MappableAttributesMixin, BaseRowRange): | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this not
end_is_inclusive is not False?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because
b""is the smallest possible key in lexicographical byte order,[b"", ...)(start_is_inclusive=True) is equivalent to an unbounded start (None), whereas(..., b""](end_is_inclusive=True) matches only the empty keyb""(k <= b"") rather than all rows. Usingend_is_inclusive is not Falsewould turnRowRange(end_key=b"", end_is_inclusive=True)intoend_key=None(unbounded), matching the entire table instead of justb"". Checkingend_is_inclusive is Noneonly normalizes""/b""when the caller omittedend_is_inclusive(such asRowRange("", "")), while preserving both explicitend_is_inclusive=True(end_key_closed=b"") andend_is_inclusive=False(end_key_open=b"").