Merge branch 'cassandra-6.0' into trunk

* cassandra-6.0:
  Allow unreserved keywords as user and identity names in USER and IDENTITY statements
This commit is contained in:
Maxim Muzafarov 2026-07-27 16:08:58 +02:00
commit 5bf01cc7c0
No known key found for this signature in database
GPG Key ID: 7FEC714D84388C16
3 changed files with 35 additions and 1 deletions

View File

@ -6,6 +6,7 @@
* Allow nodetool garbagecollect to take a user defined list of SSTables (CASSANDRA-16767)
* Add a guardrail for misprepared statements (CASSANDRA-21139)
Merged from 6.0:
* Allow unreserved keywords as user and identity names in USER and IDENTITY statements (CASSANDRA-21510)
* Reduce allocations in DefaultQueryOptions (CASSANDRA-21467)
* Reduce number of scheduledTasks on metric id release in ThreadLocalMetrics (CASSANDRA-21475)
* Cache various Enum.values() used in deserialization to avoid per-read array allocation (CASSANDRA-21528)

View File

@ -2363,12 +2363,14 @@ vector_type returns [CQL3Type.Raw vt]
username
: IDENT
| STRING_LITERAL
| unreserved_keyword
| QUOTED_NAME { addRecognitionError("Quoted strings are are not supported for user names and USER is deprecated, please use ROLE");}
;
identity
: IDENT
| STRING_LITERAL
| unreserved_keyword
| QUOTED_NAME { addRecognitionError("Quoted strings are are not supported for identity");}
;

View File

@ -68,11 +68,42 @@ public class ReservedKeywordsTest
asserts.assertAll();
}
/**
* Legacy USER and IDENTITY statements must accept unreserved keywords as names, just like
* role statements do ({@code roleName} accepts {@code unreserved_keyword}). Otherwise adding
* a new keyword to the grammar breaks existing deployments with a user or identity of that name.
*/
@Test
public void testUnreservedKeywordsAsUserNameAndIdentity()
{
SoftAssertions asserts = new SoftAssertions();
for (var f : Cql_Lexer.class.getDeclaredFields())
{
if (!Modifier.isStatic(f.getModifiers())) continue;
if (!f.getName().startsWith("K_")) continue;
String keyword = f.getName().replaceFirst("K_", "");
if (ReservedKeywords.isReserved(keyword)) continue;
for (String statement : new String[]{ "DROP USER %s", "DROP IDENTITY %s" })
{
asserts.assertThat(parses(String.format(statement, keyword)))
.describedAs(String.format(statement, keyword))
.isTrue();
}
}
asserts.assertAll();
}
private static boolean isAllowed(String keyword)
{
return parses(String.format("ALTER TABLE ks.t ADD %s TEXT", keyword));
}
private static boolean parses(String cql)
{
try
{
QueryProcessor.parseStatement(String.format("ALTER TABLE ks.t ADD %s TEXT", keyword));
QueryProcessor.parseStatement(cql);
return true;
}
catch (SyntaxException ignore)