This is an automated email from the ASF dual-hosted git repository.

dlych pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git

commit b434fbe476a699d0333d30890da85e2ab976e9ba
Author: Dmitry Lychagin <dmitry.lycha...@couchbase.com>
AuthorDate: Fri Dec 11 16:28:25 2020 -0800

    [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 <jenk...@fulliautomatix.ics.uci.edu>
    Tested-by: Jenkins <jenk...@fulliautomatix.ics.uci.edu>
    Reviewed-by: Dmitry Lychagin <dmitry.lycha...@couchbase.com>
    Reviewed-by: Ali Alsuliman <ali.al.solai...@gmail.com>
---
 .../asterix/test/metadata/MetadataManagerTest.java | 99 ++++++++++++++++++++++
 .../metadata/declared/MetadataProvider.java        | 10 +++
 .../asterix/metadata/utils/MetadataConstants.java  |  3 +
 3 files changed, 112 insertions(+)

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 @@ public class MetadataManagerTest {
         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 @@ package org.apache.asterix.metadata.declared;
 
 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 class MetadataProvider implements 
IMetadataProvider<DataSourceId, String>
 
     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 @@ import org.apache.asterix.common.metadata.DataverseName;
  */
 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.

Reply via email to