Skip to content

Commit f27dc68

Browse files
authored
CNDB-13299 prevent too long index names (#1633)
Creating an index with too long index names leads to file errors or incorrect results. This PR prevents creating new indexes, i.e., not internal, with provided index names longer than 182 characters. This constant is based on the most restrictive requirement from different index types. It comes from SAI by subtracting the longest file name addition from the file name limit of 255 characters.
1 parent f6260d5 commit f27dc68

File tree

3 files changed

+68
-0
lines changed

3 files changed

+68
-0
lines changed

src/java/org/apache/cassandra/cql3/statements/schema/CreateIndexStatement.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,15 @@ public void validate(QueryState state)
9393
{
9494
super.validate(state);
9595

96+
// Check the length of a valid index name.
97+
// Non-valid indexes are validated in IndexMetadata#validate.
98+
if (!state.getClientState().isInternal
99+
&& SchemaConstants.isValidName(indexName, true)
100+
&& indexName.length() > SchemaConstants.INDEX_NAME_LENGTH)
101+
102+
throw ire("Index name shouldn't be more than %s characters long (got %s chars for %s)",
103+
SchemaConstants.INDEX_NAME_LENGTH, indexName.length(), indexName);
104+
96105
// save the query state to use it for guardrails validation in #apply
97106
this.state = state;
98107
}

src/java/org/apache/cassandra/schema/SchemaConstants.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ public final class SchemaConstants
7676
*/
7777
public static final int NAME_LENGTH = FILENAME_LENGTH - 32 - 1;
7878

79+
/**
80+
* Longest permissible index name, so no index can fail on file name error.
81+
* It is based on the most restrictive requirement coming from SAI and calculated by
82+
* {@link org.apache.cassandra.index.sai.disk.format.Version#calculateIndexNameAllowedLength}.
83+
* The exact number is used here, since it will be in user's documentation.
84+
*/
85+
public static final int INDEX_NAME_LENGTH = 182;
86+
7987
// 59adb24e-f3cd-3e02-97f0-5b395827453f
8088
public static final UUID emptyVersion;
8189

test/unit/org/apache/cassandra/index/IndexNameTest.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,14 @@
2222
import org.junit.runner.RunWith;
2323
import org.junit.runners.Parameterized;
2424

25+
import com.datastax.driver.core.exceptions.InvalidQueryException;
2526
import org.apache.cassandra.cql3.CQLTester;
2627
import org.apache.cassandra.exceptions.ConfigurationException;
28+
import org.apache.cassandra.index.sai.disk.format.Version;
29+
import org.apache.cassandra.schema.SchemaConstants;
2730

2831
import static org.assertj.core.api.Assertions.assertThatThrownBy;
32+
import static org.junit.Assert.assertEquals;
2933

3034
@RunWith(Parameterized.class)
3135
public class IndexNameTest extends CQLTester
@@ -121,4 +125,51 @@ public void failOnBadCharIndexName()
121125
assertThatThrownBy(() -> execute(String.format(createIndexQuery, "\"unacceptable index name\"", "%s", columnName)))
122126
.isInstanceOf(ConfigurationException.class);
123127
}
128+
129+
@Test
130+
public void testTooLongNamesInternal() throws Throwable
131+
{
132+
String longName = "a".repeat(183);
133+
134+
createTable("CREATE TABLE %s (" +
135+
"key int PRIMARY KEY," +
136+
"value int)"
137+
);
138+
createIndex(String.format(createIndexQuery, longName, "%s", "value"));
139+
execute(String.format("INSERT INTO %%s (\"key\", %s) VALUES (1, 1)", "value"));
140+
execute(String.format("INSERT INTO %%s (\"key\", %s) VALUES (2, 2)", "value"));
141+
142+
beforeAndAfterFlush(() -> assertRows(execute(String.format("SELECT key, %s FROM %%s WHERE %<s = 1", "value")), row(1, 1)));
143+
}
144+
145+
@Test
146+
public void testMaxAcceptableLongNamesNewIndex() throws Throwable
147+
{
148+
assertEquals(182, Version.calculateIndexNameAllowedLength());
149+
String longName = "a".repeat(182);
150+
createTable("CREATE TABLE %s (" +
151+
"key int PRIMARY KEY," +
152+
"value int)"
153+
);
154+
executeNet(String.format(createIndexQuery, longName, "%s", "value"));
155+
156+
execute(String.format("INSERT INTO %%s (\"key\", %s) VALUES (1, 1)", "value"));
157+
execute(String.format("INSERT INTO %%s (\"key\", %s) VALUES (2, 2)", "value"));
158+
159+
beforeAndAfterFlush(() -> assertRows(execute(String.format("SELECT key, %s FROM %%s WHERE %<s = 1", "value")), row(1, 1)));
160+
}
161+
162+
@Test
163+
public void failTooLongNamesNewIndex()
164+
{
165+
String longName = "a".repeat(183);
166+
createTable("CREATE TABLE %s (" +
167+
"key int PRIMARY KEY," +
168+
"value int)"
169+
);
170+
assertThatThrownBy(() -> executeNet(String.format(createIndexQuery, longName, "%s", "value")))
171+
.isInstanceOf(InvalidQueryException.class)
172+
.hasMessage(String.format("Index name shouldn't be more than %s characters long (got %s chars for %s)",
173+
SchemaConstants.INDEX_NAME_LENGTH, longName.length(), longName));
174+
}
124175
}

0 commit comments

Comments
 (0)