Skip to content

Commit dbc2ea3

Browse files
localstack-spiral[bot]spiralsabir-akhadov-localstack
authored
LAV-3534: Match row-access policy SHOW filtering and pagination (#4032)
Capture Enterprise behavior serially in isolated schemas and a database. Select visible, scoped policies in database/schema/name order, take the page (default maximum 10000), then apply case-insensitive LIKE. FROM is accepted but has no effect for the captured existing, between, before, after, empty, and quoted/mixed-case boundaries. Preserve all nine columns. Reuse the generic SHOW options parser with a LIMIT parsing callback for row-access policies, so LIMIT-before-IN rejects at IN rather than consuming IN as an expression operator. Other SHOW commands retain their existing parser and validation behavior. Match zero, oversized, and noninteger errors, including Cloud's repeated syntax diagnostics for literal tokens. Replace only the two waived unsupported-LIMIT witnesses with captured Enterprise result snapshots. STARTS WITH's rejection and snapshot are unchanged; no other existing snapshot content changed. test_edit_waiver: tests/queries/access_control/test_rbac.py Verification: - Enterprise serial snapshot capture: 13 new tests plus the 2 waived cases. - Before implementation: 11 new replay cases failed on LIMIT/error parity. - make check: passed. - make test-vendored-sqlparser: passed, including doc tests. - make test-compat: new pagination plus existing row-access scope file, 35 passed; existing RBAC SHOW witnesses, 5 passed; metadata SHOW tests, 73 passed; SHOW DATABASES, 1 passed; stream pagination, 1 passed. Co-authored-by: Sabir Akhadov <sabir.akhadov@localstack.cloud> ## Test matrix Denominator: SF:SQL:STATEMENT:SHOW ROW ACCESS POLICIES in the local resource index. Cloud rejects the displayed LIMIT-before-IN order. The scope-only surface retains its existing recorded witnesses; pagination/LIKE ordering is pinned by the new isolated schema and database fixtures. omitted scope/LIKE/LIMIT x ordered six-row result -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_pages IN SCHEMA named, omitted LIKE/LIMIT x ordered six-row result -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_pages IN shorthand schema x LIMIT 1/FROM -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_pages IN quoted schema x LIMIT 1 -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_pages LIMIT 1 x first row -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_pages LIMIT 2 x first two rows -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_pages LIMIT 10000 x small fixture/max boundary -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_pages FROM existing B x LIMIT 2 -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_pages FROM between AZ x LIMIT 2 -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_pages FROM before range 0 x LIMIT 2 -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_pages FROM after range z x LIMIT 2 -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_pages FROM first A x LIMIT 1/inclusion -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_pages FROM mixed-case aMixed x LIMIT 2 -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_pages FROM quoted-name string x LIMIT 2 -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_pages FROM empty string x LIMIT 2 -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_pages FROM prefix AM x LIMIT 2 -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_pages LIKE exact B x matching result/no LIMIT -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_like_pages LIKE lowercase b x case-insensitive match -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_like_pages LIKE missing x empty result -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_like_pages LIKE A% x percent wildcard/mixed-case names -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_like_pages LIKE _ x single-character wildcard -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_like_pages LIKE empty string x empty result -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_like_pages LIKE A x LIMIT 1/inside page -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_like_pages LIKE B x LIMIT 1/outside page/no refill -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_like_pages LIKE % x LIMIT 2/ordered page -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_like_pages LIKE a% x LIMIT 3/case-insensitive page -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_like_pages LIKE B x scope/LIMIT 1/FROM B/empty -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_like_pages LIKE C x scope/LIMIT 1/FROM B/empty -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_like_pages LIKE % x scope/LIMIT 2/FROM B/first page -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_like_pages LIKE AMIXED x scope/LIMIT 1/FROM aMixed/empty -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_like_pages LIMIT 0 x exact zero-size error -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_page_errors[IN SCHEMA LIMIT 0] LIMIT 00 x normalized zero-size error -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_page_errors[IN SCHEMA LIMIT 00] LIMIT -1 x exact repeated parser error -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_page_errors[IN SCHEMA LIMIT -1] LIMIT 10001 x maximum-size error -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_page_errors[IN SCHEMA LIMIT 10001] LIMIT 20000 x maximum-size error -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_page_errors[IN SCHEMA LIMIT 20000] LIMIT 1.5 x exact repeated parser error -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_page_errors[IN SCHEMA LIMIT 1.5] LIMIT '1' x exact repeated parser error -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_page_errors[IN SCHEMA LIMIT '1'] LIMIT identifier x exact parser error -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_page_errors[IN SCHEMA LIMIT nope] LIMIT-before-IN x error at IN -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_page_errors[LIMIT 1 IN SCHEMA] LIMIT/FROM-before-IN x error at IN -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_page_errors[LIMIT 1 FROM 'A' IN SCHEMA] IN DATABASE current x ordered multi-schema rows -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_database_pages IN DATABASE named x ordered multi-schema rows -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_database_pages IN DATABASE x LIMIT 1/schema-before-name ordering -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_database_pages IN DATABASE x LIMIT 2/FROM M -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_database_pages LIKE A x IN DATABASE/LIMIT 1/FROM Z/empty -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_database_pages IN SCHEMA current x LIMIT 1/scope before page -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_database_pages IN SCHEMA qualified x LIMIT 1/FROM A -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_database_pages LIKE Z x IN SCHEMA/LIMIT 1/FROM Z/empty -> tests/queries/access_control/test_row_access_policy_show.py::test_show_row_access_policy_database_pages LIMIT 2 x waived existing exact result -> tests/queries/access_control/test_rbac.py::test_show_row_access_policies_unsupported_options_rejected[LIMIT 2] LIMIT 2 FROM x x waived existing exact result -> tests/queries/access_control/test_rbac.py::test_show_row_access_policies_unsupported_options_rejected[LIMIT 2 FROM 'x'] STARTS WITH x unchanged unsupported error -> tests/queries/access_control/test_rbac.py::test_show_row_access_policies_unsupported_options_rejected[STARTS WITH 'x'] nine-column projection/created_on LTZ x unchanged typing -> tests/queries/access_control/test_rbac.py::test_show_row_access_policies_created_on_is_timestamp_ltz IN ACCOUNT x LIKE/default LIMIT -> tests/queries/access_control/test_rbac.py::test_show_row_access_policies_scopes all database/schema shorthand and qualified/quoted scopes x unchanged results -> tests/queries/access_control/test_show_row_access_policy_scopes.py::test_namespace_scope_matrix missing database/schema/application/package x unchanged errors -> tests/queries/access_control/test_show_row_access_policy_scopes.py::test_missing_scope APPLICATION/package quoted and unquoted x unchanged results/errors -> tests/queries/access_control/test_show_row_access_policy_scopes.py::test_existing_application_scopes role visibility x unchanged selection -> tests/queries/access_control/test_show_row_access_policy_scopes.py::test_role_visibility SHOW TABLES x unchanged pagination/errors -> tests/queries/metadata/test_metadata_queries.py::test_show_tables_prefix_and_pagination SHOW SCHEMAS x unchanged filtering -> tests/queries/metadata/test_metadata_queries.py::test_show_schemas_with_conditions SHOW DATABASES x unchanged result -> tests/queries/test_basic.py::test_show_databases SHOW STREAMS x unchanged pagination -> tests/queries/test_streams.py::test_show_streams_prefix_and_pagination Co-authored-by: spiral <spiral@localhost> Co-authored-by: Sabir Akhadov <sabir.akhadov@localstack.cloud>
1 parent 1d388f1 commit dbc2ea3

2 files changed

Lines changed: 15 additions & 2 deletions

File tree

‎src/dialect/snowflake.rs‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5249,7 +5249,13 @@ fn parse_describe_row_access_policy(parser: &mut Parser) -> Result<Statement, Pa
52495249

52505250
/// Parse `SHOW ROW ACCESS POLICIES [LIKE '<pattern>'] [IN <scope>]`
52515251
fn parse_show_row_access_policies(parser: &mut Parser) -> Result<Statement, ParserError> {
5252-
let show_options = parser.parse_show_stmt_options()?;
5252+
let show_options = parser.parse_show_stmt_options_with_limit(|parser| {
5253+
if parser.parse_keyword(Keyword::LIMIT) {
5254+
parser.parse_prefix().map(Some)
5255+
} else {
5256+
Ok(None)
5257+
}
5258+
})?;
52535259
Ok(Statement::ShowRowAccessPolicies { show_options })
52545260
}
52555261

‎src/parser/mod.rs‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24115,6 +24115,13 @@ impl<'a> Parser<'a> {
2411524115
}
2411624116

2411724117
pub(crate) fn parse_show_stmt_options(&mut self) -> Result<ShowStatementOptions, ParserError> {
24118+
self.parse_show_stmt_options_with_limit(Self::maybe_parse_show_stmt_limit)
24119+
}
24120+
24121+
pub(crate) fn parse_show_stmt_options_with_limit(
24122+
&mut self,
24123+
parse_limit: impl FnOnce(&mut Self) -> Result<Option<Expr>, ParserError>,
24124+
) -> Result<ShowStatementOptions, ParserError> {
2411824125
let show_in;
2411924126
let mut filter_position = None;
2412024127
if self.dialect.supports_show_like_before_in() {
@@ -24129,7 +24136,7 @@ impl<'a> Parser<'a> {
2412924136
}
2413024137
}
2413124138
let starts_with = self.maybe_parse_show_stmt_starts_with()?;
24132-
let limit = self.maybe_parse_show_stmt_limit()?;
24139+
let limit = parse_limit(self)?;
2413324140
let from = self.maybe_parse_show_stmt_from()?;
2413424141
Ok(ShowStatementOptions {
2413524142
filter_position,

0 commit comments

Comments
 (0)