Skip to content

Commit 2b2a0fc

Browse files
k-rusdjatnieks
authored andcommitted
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 f0b8c2b commit 2b2a0fc

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
@@ -134,6 +134,15 @@ public void validate(ClientState state)
134134
{
135135
super.validate(state);
136136

137+
// Check the length of a valid index name.
138+
// Non-valid indexes are validated in IndexMetadata#validate.
139+
if (!state.isInternal
140+
&& SchemaConstants.isValidName(indexName, true)
141+
&& indexName.length() > SchemaConstants.INDEX_NAME_LENGTH)
142+
143+
throw ire("Index name shouldn't be more than %s characters long (got %s chars for %s)",
144+
SchemaConstants.INDEX_NAME_LENGTH, indexName.length(), indexName);
145+
137146
// save the query state to use it for guardrails validation in #apply
138147
this.state = state;
139148
}

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

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

89+
/**
90+
* Longest permissible index name, so no index can fail on file name error.
91+
* It is based on the most restrictive requirement coming from SAI and calculated by
92+
* {@link org.apache.cassandra.index.sai.disk.format.Version#calculateIndexNameAllowedLength}.
93+
* The exact number is used here, since it will be in user's documentation.
94+
*/
95+
public static final int INDEX_NAME_LENGTH = 182;
96+
8997
// 59adb24e-f3cd-3e02-97f0-5b395827453f
9098
public static final UUID emptyVersion;
9199

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)