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

dataroaring pushed a commit to branch branch-3.0
in repository https://gitbox.apache.org/repos/asf/doris.git

commit ffd8931cfe0e82664acda58020973edf4762fc42
Author: zclllhhjj <zhaochan...@selectdb.com>
AuthorDate: Mon Aug 19 19:07:47 2024 +0800

    [Enhancement](partition) Forbid create table with null partition item which 
relative column is not null (#39449)
    
    ## Proposed changes
    
    Issue Number: close #xxx
    
    before:
    ```sql
    CREATE TABLE `test_null` (
    `k0` BIGINT NOT NULL,
    `k1` BIGINT NOT NULL
    )
    partition by list (k0, k1) (
    PARTITION `pX` values in ((NULL, 1))
    )
    PROPERTIES (
    "replication_allocation" = "tag.location.default: 1"
    );
    ```
    may core in local exchange for inserting.
    
    now:
    ```sql
    mysql [test]>CREATE TABLE `test_null` (
        -> `k0` BIGINT NOT NULL,
        -> `k1` BIGINT NOT NULL
        -> )
        -> partition by list (k0, k1) (
        -> PARTITION `pX` values in ((NULL, 1))
        -> )
        -> PROPERTIES (
        -> "replication_allocation" = "tag.location.default: 1"
        -> );
    ERROR 1105 (HY000): errCode = 2, detailMessage = errCode = 2, detailMessage 
= Can't have null partition is for NOT NULL partition column in partition 
expr's index 0
    ```
---
 .../apache/doris/datasource/InternalCatalog.java   | 130 ++++++++++++++++-----
 .../trees/plans/commands/CreateTableCommand.java   |   7 +-
 .../org/apache/doris/catalog/CreateTableTest.java  |  29 +++--
 .../datasource/hive/HiveDDLAndDMLPlanTest.java     |   2 +-
 .../trees/plans/CreateTableCommandTest.java        |  49 ++++----
 .../suites/partition_p0/test_null_partition.groovy |  83 +++++++++++++
 6 files changed, 227 insertions(+), 73 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java
index 61d783fa6a6..71c71fb8ec7 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java
@@ -46,7 +46,9 @@ import org.apache.doris.analysis.LiteralExpr;
 import org.apache.doris.analysis.MultiPartitionDesc;
 import org.apache.doris.analysis.PartitionDesc;
 import org.apache.doris.analysis.PartitionKeyDesc;
+import org.apache.doris.analysis.PartitionKeyDesc.PartitionKeyValueType;
 import org.apache.doris.analysis.PartitionNames;
+import org.apache.doris.analysis.PartitionValue;
 import org.apache.doris.analysis.QueryStmt;
 import org.apache.doris.analysis.RecoverDbStmt;
 import org.apache.doris.analysis.RecoverPartitionStmt;
@@ -2252,6 +2254,8 @@ public class InternalCatalog implements 
CatalogIf<Database> {
         db.checkQuota();
     }
 
+    // below are private functions used by createOlapTable
+
     private Type getChildTypeByName(String name, CreateTableStmt stmt)
             throws AnalysisException {
         List<Column> columns = stmt.getColumns();
@@ -2263,6 +2267,98 @@ public class InternalCatalog implements 
CatalogIf<Database> {
         throw new AnalysisException("Cannot find column `" + name + "` in 
table's columns");
     }
 
+    private boolean findAllowNullforSlotRef(List<Column> baseSchema, SlotRef 
slot) throws AnalysisException {
+        for (Column col : baseSchema) {
+            if (col.nameEquals(slot.getColumnName(), true)) {
+                return col.isAllowNull();
+            }
+        }
+        throw new AnalysisException("Unknown partition column name:" + 
slot.getColumnName());
+    }
+
+    private void checkNullityEqual(ArrayList<Boolean> partitionSlotNullables, 
List<PartitionValue> item)
+            throws AnalysisException {
+        // for MAX_VALUE or somethings
+        if (item == null) {
+            return;
+        }
+        for (int i = 0; i < item.size(); i++) {
+            try {
+                if (!partitionSlotNullables.get(i) && 
item.get(i).isNullPartition()) {
+                    throw new AnalysisException("Can't have null partition is 
for NOT NULL partition "
+                            + "column in partition expr's index " + i);
+                }
+            } catch (IndexOutOfBoundsException e) {
+                throw new AnalysisException("partition item's size out of 
partition columns: " + e.getMessage());
+            }
+        }
+    }
+
+    private void checkPartitionNullity(List<Column> baseSchema, PartitionDesc 
partitionDesc,
+            SinglePartitionDesc partition)
+            throws AnalysisException {
+        // in creating OlapTable, expr.desc is null. so we should find the 
column ourself.
+        ArrayList<Expr> partitionExprs = partitionDesc.getPartitionExprs();
+        ArrayList<Boolean> partitionSlotNullables = new ArrayList<Boolean>();
+        for (Expr expr : partitionExprs) {
+            if (expr instanceof SlotRef) {
+                partitionSlotNullables.add(findAllowNullforSlotRef(baseSchema, 
(SlotRef) expr));
+            } else if (expr instanceof FunctionCallExpr) {
+                partitionSlotNullables.add(Expr.isNullable(((FunctionCallExpr) 
expr).getFn(), expr.getChildren()));
+            } else {
+                throw new AnalysisException("Unknown partition expr type:" + 
expr.getExprName());
+            }
+        }
+
+        if (partition.getPartitionKeyDesc().getPartitionType() == 
PartitionKeyValueType.IN) {
+            List<List<PartitionValue>> inValues = 
partition.getPartitionKeyDesc().getInValues();
+            for (List<PartitionValue> item : inValues) {
+                checkNullityEqual(partitionSlotNullables, item);
+            }
+        } else if (partition.getPartitionKeyDesc().getPartitionType() == 
PartitionKeyValueType.LESS_THAN) {
+            // only upper
+            List<PartitionValue> upperValues = 
partition.getPartitionKeyDesc().getUpperValues();
+            checkNullityEqual(partitionSlotNullables, upperValues);
+        } else {
+            // fixed. upper and lower
+            List<PartitionValue> lowerValues = 
partition.getPartitionKeyDesc().getLowerValues();
+            List<PartitionValue> upperValues = 
partition.getPartitionKeyDesc().getUpperValues();
+            checkNullityEqual(partitionSlotNullables, lowerValues);
+            checkNullityEqual(partitionSlotNullables, upperValues);
+        }
+    }
+
+    private void checkLegalityofPartitionExprs(CreateTableStmt stmt, 
PartitionDesc partitionDesc)
+            throws AnalysisException {
+        for (Expr expr : partitionDesc.getPartitionExprs()) {
+            if (expr != null && expr instanceof FunctionCallExpr) { // test 
them
+                FunctionCallExpr func = (FunctionCallExpr) expr;
+                ArrayList<Expr> children = func.getChildren();
+                Type[] childTypes = new Type[children.size()];
+                for (int i = 0; i < children.size(); i++) {
+                    if (children.get(i) instanceof LiteralExpr) {
+                        childTypes[i] = children.get(i).getType();
+                    } else if (children.get(i) instanceof SlotRef) {
+                        childTypes[i] = 
getChildTypeByName(children.get(i).getExprName(), stmt);
+                    } else {
+                        throw new AnalysisException(String.format(
+                                "partition expr %s has unrecognized parameter 
in slot %d", func.getExprName(), i));
+                    }
+                }
+                Function fn = null;
+                try {
+                    fn = 
func.getBuiltinFunction(func.getFnName().getFunction(), childTypes,
+                            Function.CompareMode.IS_INDISTINGUISHABLE); // 
only for test
+                } catch (Exception e) {
+                    throw new AnalysisException("partition expr " + 
func.getExprName() + " is illegal!");
+                }
+                if (fn == null) {
+                    throw new AnalysisException("partition expr " + 
func.getExprName() + " is illegal!");
+                }
+            }
+        }
+    }
+
     // Create olap table and related base index synchronously.
     private boolean createOlapTable(Database db, CreateTableStmt stmt) throws 
UserException {
         String tableName = stmt.getTableName();
@@ -2308,43 +2404,21 @@ public class InternalCatalog implements 
CatalogIf<Database> {
         // create partition info
         PartitionDesc partitionDesc = stmt.getPartitionDesc();
 
-        // check legality of partiton exprs
         ConnectContext ctx = ConnectContext.get();
         Env env = Env.getCurrentEnv();
+
+        // check legality of partiton exprs.
         if (ctx != null && env != null && partitionDesc != null && 
partitionDesc.getPartitionExprs() != null) {
-            for (Expr expr : partitionDesc.getPartitionExprs()) {
-                if (expr != null && expr instanceof FunctionCallExpr) { // 
test them
-                    FunctionCallExpr func = (FunctionCallExpr) expr;
-                    ArrayList<Expr> children = func.getChildren();
-                    Type[] childTypes = new Type[children.size()];
-                    for (int i = 0; i < children.size(); i++) {
-                        if (children.get(i) instanceof LiteralExpr) {
-                            childTypes[i] = children.get(i).getType();
-                        } else if (children.get(i) instanceof SlotRef) {
-                            childTypes[i] = 
getChildTypeByName(children.get(i).getExprName(), stmt);
-                        } else {
-                            throw new AnalysisException(String.format(
-                                    "partition expr %s has unrecognized 
parameter in slot %d", func.getExprName(), i));
-                        }
-                    }
-                    Function fn = null;
-                    try {
-                        fn = 
func.getBuiltinFunction(func.getFnName().getFunction(), childTypes,
-                                Function.CompareMode.IS_INDISTINGUISHABLE); // 
only for test
-                    } catch (Exception e) {
-                        throw new AnalysisException("partition expr " + 
func.getExprName() + " is illegal!");
-                    }
-                    if (fn == null) {
-                        throw new AnalysisException("partition expr " + 
func.getExprName() + " is illegal!");
-                    }
-                }
-            }
+            checkLegalityofPartitionExprs(stmt, partitionDesc);
         }
 
         PartitionInfo partitionInfo = null;
         Map<String, Long> partitionNameToId = Maps.newHashMap();
         if (partitionDesc != null) {
             for (SinglePartitionDesc desc : 
partitionDesc.getSinglePartitionDescs()) {
+                // check legality of nullity of partition items.
+                checkPartitionNullity(baseSchema, partitionDesc, desc);
+
                 long partitionId = idGeneratorBuffer.getNextId();
                 partitionNameToId.put(desc.getPartitionName(), partitionId);
             }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableCommand.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableCommand.java
index ad39513c83d..891585d8e06 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableCommand.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableCommand.java
@@ -98,11 +98,8 @@ public class CreateTableCommand extends Command implements 
ForwardWithSync {
                 LOG.debug("Nereids start to execute the create table command, 
query id: {}, tableName: {}",
                         ctx.queryId(), createTableInfo.getTableName());
             }
-            try {
-                Env.getCurrentEnv().createTable(createTableStmt);
-            } catch (Exception e) {
-                throw new AnalysisException(e.getMessage(), e.getCause());
-            }
+
+            Env.getCurrentEnv().createTable(createTableStmt);
             return;
         }
         LogicalPlan query = ctasQuery.get();
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/catalog/CreateTableTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/catalog/CreateTableTest.java
index bdd5a66902c..5f66e903e3a 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/catalog/CreateTableTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/catalog/CreateTableTest.java
@@ -372,17 +372,16 @@ public class CreateTableTest extends TestWithFeService {
 
         // single partition column with multi keys
         ExceptionChecker
-                .expectThrowsWithMsg(IllegalArgumentException.class, 
"partition key desc list size[2] is not equal to partition column size[1]",
-                        () -> createTable("create table test.tbl10\n"
-                                + "(k1 int not null, k2 varchar(128), k3 int, 
v1 int, v2 int)\n"
-                                + "partition by list(k1)\n"
-                                + "(\n"
-                                + "partition p1 values in (\"1\", \"3\", 
\"5\"),\n"
-                                + "partition p2 values in (\"2\", \"4\", 
\"6\"),\n"
-                                + "partition p3 values in ((\"7\", \"8\"))\n"
-                                + ")\n"
-                                + "distributed by hash(k2) buckets 1\n"
-                                + "properties('replication_num' = '1');"));
+                        .expectThrowsWithMsg(AnalysisException.class,
+                                        "partition item's size out of 
partition columns: Index 1 out of bounds for length 1",
+                                        () -> createTable("create table 
test.tbl10\n"
+                                                        + "(k1 int not null, 
k2 varchar(128), k3 int, v1 int, v2 int)\n"
+                                                        + "partition by 
list(k1)\n" + "(\n"
+                                                        + "partition p1 values 
in (\"1\", \"3\", \"5\"),\n"
+                                                        + "partition p2 values 
in (\"2\", \"4\", \"6\"),\n"
+                                                        + "partition p3 values 
in ((\"7\", \"8\"))\n" + ")\n"
+                                                        + "distributed by 
hash(k2) buckets 1\n"
+                                                        + 
"properties('replication_num' = '1');"));
 
         // multi partition columns with single key
         ExceptionChecker
@@ -399,7 +398,7 @@ public class CreateTableTest extends TestWithFeService {
 
         // multi partition columns with multi keys
         ExceptionChecker
-                .expectThrowsWithMsg(IllegalArgumentException.class, 
"partition key desc list size[3] is not equal to partition column size[2]",
+                .expectThrowsWithMsg(AnalysisException.class, "partition 
item's size out of partition columns: Index 2 out of bounds for length 2",
                         () -> createTable("create table test.tbl12\n"
                                 + "(k1 int not null, k2 varchar(128) not null, 
k3 int, v1 int, v2 int)\n"
                                 + "partition by list(k1, k2)\n"
@@ -922,8 +921,8 @@ public class CreateTableTest extends TestWithFeService {
 
     @Test
     public void testCreateTableWithNerieds() throws Exception {
-        
ExceptionChecker.expectThrowsWithMsg(org.apache.doris.nereids.exceptions.AnalysisException.class,
-                "Failed to check min load replica num",
+        
ExceptionChecker.expectThrowsWithMsg(org.apache.doris.common.DdlException.class,
+                                "Failed to check min load replica num",
                 () -> createTable("create table 
test.tbl_min_load_replica_num_2_nereids\n"
                         + "(k1 int, k2 int)\n"
                         + "duplicate key(k1)\n"
@@ -964,7 +963,7 @@ public class CreateTableTest extends TestWithFeService {
                         + "distributed by hash(k1) buckets 10", true));
 
         createDatabaseWithSql("create database db2 
properties('replication_num' = '4')");
-        
ExceptionChecker.expectThrowsWithMsg(org.apache.doris.nereids.exceptions.AnalysisException.class,
+        ExceptionChecker.expectThrowsWithMsg(DdlException.class,
                 "replication num should be less than the number of available 
backends. "
                         + "replication num is 4, available backend num is 3",
                 () -> createTable("create table db2.tbl_4_replica\n"
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/datasource/hive/HiveDDLAndDMLPlanTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/datasource/hive/HiveDDLAndDMLPlanTest.java
index a40a4fed385..ab4e5fd0fc5 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/datasource/hive/HiveDDLAndDMLPlanTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/datasource/hive/HiveDDLAndDMLPlanTest.java
@@ -339,7 +339,7 @@ public class HiveDDLAndDMLPlanTest extends 
TestWithFeService {
                 + "PROPERTIES (\n"
                 + "  'location'='hdfs://loc/db/tbl',\n"
                 + "  'file_format'='orc')";
-        
ExceptionChecker.expectThrowsWithMsg(org.apache.doris.nereids.exceptions.AnalysisException.class,
+        
ExceptionChecker.expectThrowsWithMsg(org.apache.doris.common.UserException.class,
                 "errCode = 2, detailMessage = errCode = 2,"
                         + " detailMessage = Create hive bucket table need set 
enable_create_hive_bucket_table to true",
                 () -> createTable(createBucketedTableErr, true));
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/CreateTableCommandTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/CreateTableCommandTest.java
index dc45e3de0fe..741faea4a13 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/CreateTableCommandTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/CreateTableCommandTest.java
@@ -241,12 +241,12 @@ public class CreateTableCommandTest extends 
TestWithFeService {
 
     @Test
     public void testAbnormal() throws ConfigException {
-        checkThrow(AnalysisException.class,
+        checkThrow(org.apache.doris.common.DdlException.class,
                 "Unknown properties: {aa=bb}",
                 () -> createTable("create table test.atbl1\n" + "(k1 int, k2 
float)\n" + "duplicate key(k1)\n"
                         + "distributed by hash(k1) buckets 1\n" + 
"properties('replication_num' = '1','aa'='bb'); "));
 
-        checkThrow(AnalysisException.class,
+        checkThrow(org.apache.doris.common.DdlException.class,
                 "Floating point type should not be used in distribution 
column",
                 () -> createTable("create table test.atbl1\n" + "(k1 int, k2 
float)\n" + "duplicate key(k1)\n"
                         + "distributed by hash(k2) buckets 1\n" + 
"properties('replication_num' = '1'); "));
@@ -257,18 +257,18 @@ public class CreateTableCommandTest extends 
TestWithFeService {
                         + "partition by range(k3)\n" + "(partition p1 values 
less than(\"10\"))\n"
                         + "distributed by hash(k2) buckets 1\n" + 
"properties('replication_num' = '1'); "));
 
-        checkThrow(AnalysisException.class,
+        checkThrow(org.apache.doris.common.DdlException.class,
                 "Varchar should not in the middle of short keys",
                 () -> createTable("create table test.atbl3\n" + "(k1 
varchar(40), k2 int, k3 int)\n"
                         + "duplicate key(k1, k2, k3)\n" + "distributed by 
hash(k1) buckets 1\n"
                         + "properties('replication_num' = '1', 'short_key' = 
'3');"));
 
-        checkThrow(AnalysisException.class, "Short key is too large. should 
less than: 3",
+        checkThrow(org.apache.doris.common.DdlException.class, "Short key is 
too large. should less than: 3",
                 () -> createTable("create table test.atbl4\n" + "(k1 int, k2 
int, k3 int)\n"
                         + "duplicate key(k1, k2, k3)\n" + "distributed by 
hash(k1) buckets 1\n"
                         + "properties('replication_num' = '1', 'short_key' = 
'4');"));
 
-        checkThrow(AnalysisException.class,
+        checkThrow(org.apache.doris.common.DdlException.class,
                 "replication num should be less than the number of available 
backends. replication num is 3, available backend num is 1",
                 () -> createTable("create table test.atbl5\n" + "(k1 int, k2 
int, k3 int)\n"
                         + "duplicate key(k1, k2, k3)\n" + "distributed by 
hash(k1) buckets 1\n"
@@ -278,48 +278,49 @@ public class CreateTableCommandTest extends 
TestWithFeService {
                 () -> createTable("create table test.atbl6\n" + "(k1 int, k2 
int)\n" + "duplicate key(k1)\n"
                         + "distributed by hash(k2) buckets 1\n" + 
"properties('replication_num' = '1'); "));
 
-        checkThrow(AnalysisException.class, "Table 'atbl6' already exists",
+        checkThrow(org.apache.doris.common.DdlException.class, "Table 'atbl6' 
already exists",
                 () -> createTable("create table test.atbl6\n" + "(k1 int, k2 
int, k3 int)\n"
                         + "duplicate key(k1, k2, k3)\n" + "distributed by 
hash(k1) buckets 1\n"
                         + "properties('replication_num' = '1');"));
 
         ConfigBase.setMutableConfig("disable_storage_medium_check", "false");
-        checkThrow(AnalysisException.class,
+        checkThrow(org.apache.doris.common.DdlException.class,
                 "Failed to find enough backend, please check the replication 
num,replication tag and storage medium.\n"
                         + "Create failed replications:\n"
                         + "replication tag: {\"location\" : \"default\"}, 
replication num: 1, storage medium: SSD",
                 () -> createTable("create table test.tb7(key1 int, key2 
varchar(10)) distributed by hash(key1) \n"
                         + "buckets 1 properties('replication_num' = '1', 
'storage_medium' = 'ssd');"));
 
-        checkThrow(AnalysisException.class, "sequence column only support 
UNIQUE_KEYS",
+        checkThrow(org.apache.doris.common.DdlException.class, "sequence 
column only support UNIQUE_KEYS",
                 () -> createTable("create table test.atbl8\n" + "(k1 
varchar(40), k2 int, v1 int sum)\n"
                         + "aggregate key(k1, k2)\n"
                         + "partition by range(k2)\n" + "(partition p1 values 
less than(\"10\"))\n"
                         + "distributed by hash(k2) buckets 1\n" + 
"properties('replication_num' = '1',\n"
                         + "'function_column.sequence_type' = 'int');"));
 
-        checkThrow(AnalysisException.class, "sequence type only support 
integer types and date types",
+        checkThrow(org.apache.doris.common.DdlException.class,
+                "sequence type only support integer types and date types",
                 () -> createTable("create table test.atbl8\n" + "(k1 
varchar(40), k2 int, v1 int)\n"
                         + "unique key(k1, k2)\n"
                         + "partition by range(k2)\n" + "(partition p1 values 
less than(\"10\"))\n"
                         + "distributed by hash(k2) buckets 1\n" + 
"properties('replication_num' = '1',\n"
                         + "'function_column.sequence_type' = 'double');"));
 
-        checkThrow(AnalysisException.class, "The sequence_col and 
sequence_type cannot be set at the same time",
+        checkThrow(org.apache.doris.common.DdlException.class, "The 
sequence_col and sequence_type cannot be set at the same time",
                 () -> createTable("create table test.atbl8\n" + "(k1 
varchar(40), k2 int, v1 int)\n"
                         + "unique key(k1, k2)\n"
                         + "partition by range(k2)\n" + "(partition p1 values 
less than(\"10\"))\n"
                         + "distributed by hash(k2) buckets 1\n" + 
"properties('replication_num' = '1',\n"
                         + "'function_column.sequence_type' = 'int', 
'function_column.sequence_col' = 'v1');"));
 
-        checkThrow(AnalysisException.class, "The specified sequence column[v3] 
not exists",
+        checkThrow(org.apache.doris.common.DdlException.class, "The specified 
sequence column[v3] not exists",
                 () -> createTable("create table test.atbl8\n" + "(k1 
varchar(40), k2 int, v1 int)\n"
                         + "unique key(k1, k2)\n"
                         + "partition by range(k2)\n" + "(partition p1 values 
less than(\"10\"))\n"
                         + "distributed by hash(k2) buckets 1\n" + 
"properties('replication_num' = '1',\n"
                         + "'function_column.sequence_col' = 'v3');"));
 
-        checkThrow(AnalysisException.class, "Sequence type only support 
integer types and date types",
+        checkThrow(org.apache.doris.common.DdlException.class, "Sequence type 
only support integer types and date types",
                 () -> createTable("create table test.atbl8\n" + "(k1 
varchar(40), k2 int, v1 int)\n"
                         + "unique key(k1, k2)\n"
                         + "partition by range(k2)\n" + "(partition p1 values 
less than(\"10\"))\n"
@@ -341,7 +342,7 @@ public class CreateTableCommandTest extends 
TestWithFeService {
                 + "properties('replication_num' = '1');"));
 
         // single partition column with multi keys
-        checkThrow(AnalysisException.class,
+        checkThrow(org.apache.doris.common.AnalysisException.class,
                 "partition key desc list size[2] is not equal to partition 
column size[1]",
                 () -> createTable("create table test.tbl10\n"
                         + "(k1 int not null, k2 varchar(128), k3 int, v1 int, 
v2 int)\n"
@@ -355,7 +356,7 @@ public class CreateTableCommandTest extends 
TestWithFeService {
                         + "properties('replication_num' = '1');"));
 
         // multi partition columns with single key
-        checkThrow(AnalysisException.class,
+        checkThrow(IllegalArgumentException.class,
                 "partition key desc list size[1] is not equal to partition 
column size[2]",
                 () -> createTable("create table test.tbl11\n"
                         + "(k1 int not null, k2 varchar(128) not null, k3 int, 
v1 int, v2 int)\n"
@@ -368,7 +369,7 @@ public class CreateTableCommandTest extends 
TestWithFeService {
                         + "properties('replication_num' = '1');"));
 
         // multi partition columns with multi keys
-        checkThrow(AnalysisException.class,
+        checkThrow(org.apache.doris.common.AnalysisException.class,
                 "partition key desc list size[3] is not equal to partition 
column size[2]",
                 () -> createTable("create table test.tbl12\n"
                         + "(k1 int not null, k2 varchar(128) not null, k3 int, 
v1 int, v2 int)\n"
@@ -453,7 +454,7 @@ public class CreateTableCommandTest extends 
TestWithFeService {
                         + "PROPERTIES(\"replication_num\" = \"1\");"));
 
         // range: partition content != partition key type
-        checkThrow(AnalysisException.class, "Invalid number format: beijing",
+        checkThrow(org.apache.doris.common.DdlException.class, "Invalid number 
format: beijing",
                 () -> createTable("CREATE TABLE test.tbl17 (\n"
                         + "    k1 int, k2 varchar(128), k3 int, v1 int, v2 
int\n"
                         + ")\n"
@@ -466,7 +467,7 @@ public class CreateTableCommandTest extends 
TestWithFeService {
                         + "PROPERTIES(\"replication_num\" = \"1\");"));
 
         // list: partition content != partition key type
-        checkThrow(AnalysisException.class, "Invalid number format: beijing",
+        checkThrow(org.apache.doris.common.DdlException.class, "Invalid number 
format: beijing",
                 () -> createTable("CREATE TABLE test.tbl18 (\n"
                         + "    k1 int not null, k2 varchar(128), k3 int, v1 
int, v2 int\n"
                         + ")\n"
@@ -482,7 +483,7 @@ public class CreateTableCommandTest extends 
TestWithFeService {
          * dynamic partition table
          */
         // list partition with dynamic properties
-        checkThrow(AnalysisException.class, "Only support dynamic partition 
properties on range partition table",
+        checkThrow(org.apache.doris.common.DdlException.class, "Only support 
dynamic partition properties on range partition table",
                 () -> createTable("CREATE TABLE test.tbl19\n"
                         + "(\n"
                         + "    k1 DATE not null\n"
@@ -500,7 +501,7 @@ public class CreateTableCommandTest extends 
TestWithFeService {
                         + ");\n"));
 
         // no partition table with dynamic properties
-        checkThrow(AnalysisException.class, "Only support dynamic partition 
properties on range partition table",
+        checkThrow(org.apache.doris.common.DdlException.class, "Only support 
dynamic partition properties on range partition table",
                 () -> createTable("CREATE TABLE test.tbl20\n"
                         + "(\n"
                         + "    k1 DATE\n"
@@ -558,7 +559,7 @@ public class CreateTableCommandTest extends 
TestWithFeService {
                         + " 'data_sort.sort_type' = 'lexical');"));
 
         // create z-order sort table, default col_num
-        checkThrow(AnalysisException.class, "only support lexical method now!",
+        checkThrow(org.apache.doris.common.AnalysisException.class, "only 
support lexical method now!",
                 () -> createTable(
                         "create table test.zorder_tbl2\n" + "(k1 varchar(40), 
k2 int, k3 int)\n"
                                 + "duplicate key(k1, k2, k3)\n"
@@ -567,7 +568,7 @@ public class CreateTableCommandTest extends 
TestWithFeService {
                                 + " 'data_sort.sort_type' = 'zorder');"));
 
         // create z-order sort table, define sort_col_num
-        checkThrow(AnalysisException.class, "only support lexical method now!",
+        checkThrow(org.apache.doris.common.AnalysisException.class, "only 
support lexical method now!",
                 () -> createTable(
                         "create table test.zorder_tbl3\n" + "(k1 varchar(40), 
k2 int, k3 int)\n"
                                 + "duplicate key(k1, k2, k3)\n"
@@ -576,7 +577,7 @@ public class CreateTableCommandTest extends 
TestWithFeService {
                                 + " 'data_sort.sort_type' = 'zorder',"
                                 + " 'data_sort.col_num' = '2');"));
         // create z-order sort table, only 1 sort column
-        checkThrow(AnalysisException.class, "only support lexical method now!",
+        checkThrow(org.apache.doris.common.AnalysisException.class, "only 
support lexical method now!",
                 () -> createTable("create table test.zorder_tbl4\n" + "(k1 
varchar(40), k2 int, k3 int)\n"
                         + "duplicate key(k1, k2, k3)\n"
                         + "partition by range(k2)\n" + "(partition p1 values 
less than(\"10\"))\n"
@@ -584,7 +585,7 @@ public class CreateTableCommandTest extends 
TestWithFeService {
                         + " 'data_sort.sort_type' = 'zorder',"
                         + " 'data_sort.col_num' = '1');"));
         // create z-order sort table, sort column is empty
-        checkThrow(AnalysisException.class, "only support lexical method now!",
+        checkThrow(org.apache.doris.common.AnalysisException.class, "only 
support lexical method now!",
                 () -> createTable("create table test.zorder_tbl4\n" + "(k1 
varchar(40), k2 int, k3 int)\n"
                         + "duplicate key(k1, k2, k3)\n"
                         + "partition by range(k2)\n" + "(partition p1 values 
less than(\"10\"))\n"
@@ -691,7 +692,7 @@ public class CreateTableCommandTest extends 
TestWithFeService {
 
     @Test
     public void testCreateTableWithInMemory() {
-        checkThrow(AnalysisException.class, "Not support set 
'in_memory'='true' now!",
+        checkThrow(org.apache.doris.common.AnalysisException.class, "Not 
support set 'in_memory'='true' now!",
                 () -> createTable("create table test.test_inmemory(k1 INT, k2 
INT) duplicate key (k1) "
                         + "distributed by hash(k1) buckets 1 
properties('replication_num' = '1','in_memory'='true');"));
     }
diff --git a/regression-test/suites/partition_p0/test_null_partition.groovy 
b/regression-test/suites/partition_p0/test_null_partition.groovy
new file mode 100644
index 00000000000..2563b374d38
--- /dev/null
+++ b/regression-test/suites/partition_p0/test_null_partition.groovy
@@ -0,0 +1,83 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+suite("test_null_partition") {
+    sql "set allow_partition_column_nullable = true;"
+
+    sql " drop table if exists test_null "
+    test {
+        sql """
+            CREATE TABLE `test_null` (
+            `k0` BIGINT NOT NULL,
+            `k1` BIGINT NOT NULL
+            )
+            partition by list (k0, k1) (
+            PARTITION `pX` values in ((NULL, 1))
+            )
+            PROPERTIES (
+            "replication_allocation" = "tag.location.default: 1"
+            );
+        """
+        exception "Can't have null partition is for NOT NULL partition column 
in partition expr's index 0"
+    }
+    
+    test {
+        sql """
+            CREATE TABLE `test_null` (
+            `k0` BIGINT NOT NULL,
+            `k1` BIGINT NOT NULL
+            )
+            partition by list (k0, k1) (
+            PARTITION `pX` values in ((1, 2), (1, NULL))
+            )
+            PROPERTIES (
+            "replication_allocation" = "tag.location.default: 1"
+            );
+        """
+        exception "Can't have null partition is for NOT NULL partition column 
in partition expr's index 1"
+    }
+
+    sql " drop table if exists OK "
+    sql """
+        CREATE TABLE `OK` (
+        `k0` BIGINT NULL,
+        `k1` BIGINT NOT NULL
+        )
+        partition by list (k0, k1) (
+        PARTITION `pX` values in ((NULL, 1), (NULL, 2), (NULL, 3))
+        )
+        PROPERTIES (
+        "replication_allocation" = "tag.location.default: 1"
+        );
+    """
+
+    test {
+        sql """
+            CREATE TABLE `test_null` (
+            `k0` BIGINT NULL,
+            `k1` BIGINT NOT NULL
+            )
+            partition by list (k0, k1) (
+            PARTITION `pX` values in ((NULL, 1), (NULL, 2), (NULL, 3), (4, 
NULL))
+            )
+            PROPERTIES (
+            "replication_allocation" = "tag.location.default: 1"
+            );
+        """
+        exception "Can't have null partition is for NOT NULL partition column 
in partition expr's index 1"
+    }
+}
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org


Reply via email to