[NO ISSUE][COMP] Limit dataverse name length
- user model changes: yes
- storage format changes: no
- interface changes: no
Details:
- Limit each part in a dataverse name length to 255 bytes (in UTF-8)
- Limit total length of a dataverse name to 1023 bytes (in UTF-8)
Change-Id: I044e71a0267299e50698fe9181ea2eb1819d97b0
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/9324
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Dmitry Lychagin <dmitry.lychagin@couchbase.com>
Reviewed-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/metadata/MetadataManagerTest.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/metadata/MetadataManagerTest.java
index 9045680..164ea7f 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/metadata/MetadataManagerTest.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/metadata/MetadataManagerTest.java
@@ -18,11 +18,20 @@
*/
package org.apache.asterix.test.metadata;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
import org.apache.asterix.api.common.AsterixHyracksIntegrationUtil;
import org.apache.asterix.common.config.GlobalConfig;
+import org.apache.asterix.common.exceptions.ErrorCode;
+import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.metadata.utils.MetadataConstants;
import org.apache.asterix.test.common.TestExecutor;
import org.apache.asterix.testframework.context.TestCaseContext;
+import org.apache.commons.lang3.StringUtils;
import org.junit.After;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -61,4 +70,94 @@
testExecutor.executeSqlppUpdateOrDdl("drop dataverse test;", cleanJson);
testExecutor.executeSqlppUpdateOrDdl(sql.toString(), cleanJson);
}
+
+ @Test
+ public void testDataverseNameLimits() throws Exception {
+ TestCaseContext.OutputFormat cleanJson = TestCaseContext.OutputFormat.CLEAN_JSON;
+
+ // at max dataverse name limits
+
+ char auml = 228, euml = 235;
+
+ List<DataverseName> dvNameOkList =
+ Arrays.asList(
+ // #1. max single-part name
+ DataverseName.createSinglePartName(
+ StringUtils.repeat('a', MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8)),
+ // #2. max single-part name (2-byte characters)
+ DataverseName.createSinglePartName(
+ StringUtils.repeat(auml, MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8 / 2)),
+ // #3. 4 max parts
+ DataverseName.create(Arrays.asList(
+ StringUtils.repeat('a', MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8),
+ StringUtils.repeat('b', MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8),
+ StringUtils.repeat('c', MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8),
+ StringUtils.repeat('d', MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8))),
+ // #3. 4 max parts (2-byte characters)
+ DataverseName.create(Arrays.asList(
+ StringUtils.repeat(auml, MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8 / 2),
+ StringUtils.repeat(euml, MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8 / 2),
+ StringUtils.repeat(auml, MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8 / 2),
+ StringUtils.repeat(euml,
+ MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8 / 2))));
+
+ for (DataverseName dvNameOk : dvNameOkList) {
+ String sql = String.format("create dataverse %s;", dvNameOk);
+ testExecutor.executeSqlppUpdateOrDdl(sql, cleanJson);
+ }
+
+ // exceeding dataverse name limits
+
+ char iuml = 239, ouml = 246;
+
+ List<DataverseName> dvNameErrList =
+ Arrays.asList(
+ // #1. single-part name exceeds part length limit
+ DataverseName.createSinglePartName(
+ StringUtils.repeat('A', MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8 + 1)),
+ // #2 single-part name exceeds part length limit (2-byte characters)
+ DataverseName.createSinglePartName(StringUtils.repeat(iuml,
+ MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8 / 2 + 1)),
+ // #3. 2-part name, 2nd part exceed part length limit
+ DataverseName.create(Arrays.asList("A",
+ StringUtils.repeat('B', MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8 + 1))),
+ // #4. 2-part name, 2nd part exceed part length limit (2-byte characters)
+ DataverseName.create(Arrays.asList("A",
+ StringUtils.repeat(ouml,
+ MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8 / 2 + 1))),
+ // #5. 5-part name, each part at the part length limit, total length limit is exceeded
+ DataverseName.create(Arrays.asList(
+ StringUtils.repeat('A', MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8),
+ StringUtils.repeat('B', MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8),
+ StringUtils.repeat('C', MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8),
+ StringUtils.repeat('D', MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8),
+ StringUtils.repeat('E', MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8))),
+ // #6. 5-part name, each part at the part length limit, total length limit is exceeded (2-byte characters)
+ DataverseName.create(Arrays.asList(
+ StringUtils.repeat(iuml, MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8 / 2),
+ StringUtils.repeat(ouml, MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8 / 2),
+ StringUtils.repeat(iuml, MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8 / 2),
+ StringUtils.repeat(ouml, MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8 / 2),
+ StringUtils.repeat(iuml, MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8 / 2))),
+ // #7. Multi-part name, each part at the part length limit, total length limit is exceeded
+ DataverseName.create(
+ Collections.nCopies(MetadataConstants.DATAVERSE_NAME_TOTAL_LENGTH_LIMIT_UTF8 + 1, "A")),
+ // #8. Multi-part name, each part at the part length limit, total length limit is exceeded (2-bytes characters)
+ DataverseName.create(
+ Collections.nCopies(MetadataConstants.DATAVERSE_NAME_TOTAL_LENGTH_LIMIT_UTF8 / 2 + 1,
+ String.valueOf(iuml))));
+
+ String invalidNameErrCode = ErrorCode.ASTERIX + ErrorCode.INVALID_DATABASE_OBJECT_NAME;
+ for (DataverseName dvNameErr : dvNameErrList) {
+ String sql = String.format("create dataverse %s;", dvNameErr);
+ try {
+ testExecutor.executeSqlppUpdateOrDdl(sql, cleanJson);
+ Assert.fail("Expected failure: " + invalidNameErrCode);
+ } catch (Exception e) {
+
+ Assert.assertTrue("Unexpected error message: " + e.getMessage(),
+ e.getMessage().contains(invalidNameErrCode));
+ }
+ }
+ }
}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
index 7d00c4b..075c2a8 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/declared/MetadataProvider.java
@@ -20,6 +20,7 @@
import java.io.File;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -1759,8 +1760,17 @@
public void validateDataverseName(DataverseName dataverseName, SourceLocation sourceLoc)
throws AlgebricksException {
+ int totalLengthUTF8 = 0;
for (String dvNamePart : dataverseName.getParts()) {
validateDatabaseObjectNameImpl(dvNamePart, sourceLoc);
+ int lengthUTF8 = dvNamePart.getBytes(StandardCharsets.UTF_8).length;
+ if (lengthUTF8 > MetadataConstants.DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8) {
+ throw new AsterixException(ErrorCode.INVALID_DATABASE_OBJECT_NAME, sourceLoc, dvNamePart);
+ }
+ totalLengthUTF8 += lengthUTF8;
+ }
+ if (totalLengthUTF8 > MetadataConstants.DATAVERSE_NAME_TOTAL_LENGTH_LIMIT_UTF8) {
+ throw new AsterixException(ErrorCode.INVALID_DATABASE_OBJECT_NAME, sourceLoc, dataverseName.toString());
}
}
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataConstants.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataConstants.java
index 4489050..9b037d6 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataConstants.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataConstants.java
@@ -26,6 +26,9 @@
*/
public class MetadataConstants {
+ public static final int DATAVERSE_NAME_PART_LENGTH_LIMIT_UTF8 = 255;
+ public static final int DATAVERSE_NAME_TOTAL_LENGTH_LIMIT_UTF8 = 1023;
+
// Name of the dataverse the metadata lives in.
public static final DataverseName METADATA_DATAVERSE_NAME = DataverseName.createBuiltinDataverseName("Metadata");
// Name of the node group where metadata is stored on.