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

lingmiao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git


The following commit(s) were added to refs/heads/master by this push:
     new a62cebf  Forbidden float column in short key (#3812)
a62cebf is described below

commit a62cebfccfcdbe324035244cd9c144d4011d6729
Author: EmmyMiao87 <522274...@qq.com>
AuthorDate: Wed Jun 17 14:16:48 2020 +0800

    Forbidden float column in short key (#3812)
    
    * Forbidden float column in short key
    
    When the user does not specify the short key column, doris will 
automatically supplement the short key column.
    However, doris does not support float or double as the short key column, so 
when adding the short key column, doris should avoid setting those column as 
the key column.
    The short key columns must be less then 3 columns and less then 36 bytes.
    
    The CreateMaterailizedView, AddRollup and CreateDuplicateTable need to 
forbidden float column in short key.
    If the float column is directly encountered during the supplement process, 
the subsequent columns are all value columns.
    
    Also the float and double could not be the short key column. At the same 
time, Doris must be at least one short key column.
    So the type of first column could not be float or double.
    If the varchar is the short key column, it can only be the least one short 
key column.
    
    Fixed #3811
    
    For duplicate table without order by columns, the order by columns are same 
as short key columns.
    If the order by columns have been designated, the count of short key 
columns must be <= the count of order by columns.
---
 .../doris/alter/MaterializedViewHandler.java       |  53 +++-
 .../doris/analysis/CreateMaterializedViewStmt.java | 129 +++++----
 .../org/apache/doris/analysis/CreateTableStmt.java |  25 +-
 .../org/apache/doris/analysis/MVColumnItem.java    |  11 +
 .../java/org/apache/doris/catalog/Catalog.java     |  35 +--
 .../org/apache/doris/catalog/PrimitiveType.java    |   8 +-
 .../main/java/org/apache/doris/catalog/Type.java   |   8 +
 .../analysis/CreateMaterializedViewStmtTest.java   | 321 ++++++++++++++++++++-
 .../org/apache/doris/planner/QueryPlanTest.java    |   6 +-
 .../java/org/apache/doris/utframe/DorisAssert.java |   8 +-
 10 files changed, 504 insertions(+), 100 deletions(-)

diff --git 
a/fe/src/main/java/org/apache/doris/alter/MaterializedViewHandler.java 
b/fe/src/main/java/org/apache/doris/alter/MaterializedViewHandler.java
index 37136a0..8626374 100644
--- a/fe/src/main/java/org/apache/doris/alter/MaterializedViewHandler.java
+++ b/fe/src/main/java/org/apache/doris/alter/MaterializedViewHandler.java
@@ -36,6 +36,7 @@ import org.apache.doris.catalog.MaterializedIndex.IndexState;
 import org.apache.doris.catalog.OlapTable;
 import org.apache.doris.catalog.OlapTable.OlapTableState;
 import org.apache.doris.catalog.Partition;
+import org.apache.doris.catalog.PrimitiveType;
 import org.apache.doris.catalog.Replica;
 import org.apache.doris.catalog.Table;
 import org.apache.doris.catalog.Tablet;
@@ -481,7 +482,7 @@ public class MaterializedViewHandler extends AlterHandler {
 
     public List<Column> checkAndPrepareMaterializedView(AddRollupClause 
addRollupClause, OlapTable olapTable,
                                                         long baseIndexId, 
boolean changeStorageFormat)
-            throws DdlException {
+            throws DdlException{
         String rollupIndexName = addRollupClause.getRollupName();
         List<String> rollupColumnNames = addRollupClause.getColumnNames();
         if (changeStorageFormat) {
@@ -554,28 +555,52 @@ public class MaterializedViewHandler extends AlterHandler 
{
         } else if (KeysType.DUP_KEYS == keysType) {
             // supplement the duplicate key
             if (addRollupClause.getDupKeys() == null || 
addRollupClause.getDupKeys().isEmpty()) {
-                int keyStorageLayoutBytes = 0;
+                // check the column meta
                 for (int i = 0; i < rollupColumnNames.size(); i++) {
                     String columnName = rollupColumnNames.get(i);
                     Column baseColumn = baseColumnNameToColumn.get(columnName);
                     if (baseColumn == null) {
                         throw new DdlException("Column[" + columnName + "] 
does not exist in base index");
                     }
-                    keyStorageLayoutBytes += 
baseColumn.getType().getStorageLayoutBytes();
                     Column rollupColumn = new Column(baseColumn);
-                    if(changeStorageFormat) {
-                        rollupColumn.setIsKey(baseColumn.isKey());
-                        
rollupColumn.setAggregationType(baseColumn.getAggregationType(), true);
-                    } else if ((i + 1) <= FeConstants.shortkey_max_column_count
-                            || keyStorageLayoutBytes < 
FeConstants.shortkey_maxsize_bytes) {
-                        rollupColumn.setIsKey(true);
-                        rollupColumn.setAggregationType(null, false);
-                    } else {
-                        rollupColumn.setIsKey(false);
-                        rollupColumn.setAggregationType(AggregateType.NONE, 
true);
-                    }
                     rollupSchema.add(rollupColumn);
                 }
+                if (changeStorageFormat) {
+                    return rollupSchema;
+                }
+                // Supplement key of MV columns
+                int theBeginIndexOfValue = 0;
+                int keySizeByte = 0;
+                for (; theBeginIndexOfValue < rollupSchema.size(); 
theBeginIndexOfValue++) {
+                    Column column = rollupSchema.get(theBeginIndexOfValue);
+                    keySizeByte += column.getType().getIndexSize();
+                    if (theBeginIndexOfValue + 1 > 
FeConstants.shortkey_max_column_count
+                            || keySizeByte > 
FeConstants.shortkey_maxsize_bytes) {
+                        if (theBeginIndexOfValue == 0 && 
column.getType().getPrimitiveType().isCharFamily()) {
+                            column.setIsKey(true);
+                            theBeginIndexOfValue++;
+                        }
+                        break;
+                    }
+                    if (column.getType().isFloatingPointType()) {
+                        break;
+                    }
+                    if (column.getType().getPrimitiveType() == 
PrimitiveType.VARCHAR) {
+                        column.setIsKey(true);
+                        theBeginIndexOfValue++;
+                        break;
+                    }
+                    column.setIsKey(true);
+                }
+                if (theBeginIndexOfValue == 0) {
+                    throw new DdlException("The first column could not be 
float or double");
+                }
+                // Supplement value of MV columns
+                for (; theBeginIndexOfValue < rollupSchema.size(); 
theBeginIndexOfValue++) {
+                    Column rollupColumn = 
rollupSchema.get(theBeginIndexOfValue);
+                    rollupColumn.setIsKey(false);
+                    rollupColumn.setAggregationType(AggregateType.NONE, true);
+                }
             } else {
                 /*
                  * eg.
diff --git 
a/fe/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java 
b/fe/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java
index 56ec28d..6f0ff6f 100644
--- a/fe/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java
+++ b/fe/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java
@@ -19,6 +19,7 @@ package org.apache.doris.analysis;
 
 import org.apache.doris.catalog.AggregateType;
 import org.apache.doris.catalog.KeysType;
+import org.apache.doris.catalog.PrimitiveType;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.Config;
 import org.apache.doris.common.ErrorCode;
@@ -69,8 +70,7 @@ public class CreateMaterializedViewStmt extends DdlStmt {
     private String dbName;
     private KeysType mvKeysType = KeysType.DUP_KEYS;
 
-    public CreateMaterializedViewStmt(String mvName, SelectStmt selectStmt,
-                                      Map<String, String> properties) {
+    public CreateMaterializedViewStmt(String mvName, SelectStmt selectStmt, 
Map<String, String> properties) {
         this.mvName = mvName;
         this.selectStmt = selectStmt;
         this.properties = properties;
@@ -116,16 +116,16 @@ public class CreateMaterializedViewStmt extends DdlStmt {
         analyzeFromClause();
         if (selectStmt.getWhereClause() != null) {
             throw new AnalysisException("The where clause is not supported in 
add materialized view clause, expr:"
-                                                + 
selectStmt.getWhereClause().toSql());
+                    + selectStmt.getWhereClause().toSql());
         }
         if (selectStmt.getHavingPred() != null) {
             throw new AnalysisException("The having clause is not supported in 
add materialized view clause, expr:"
-                                                + 
selectStmt.getHavingPred().toSql());
+                    + selectStmt.getHavingPred().toSql());
         }
         analyzeOrderByClause();
         if (selectStmt.getLimit() != -1) {
             throw new AnalysisException("The limit clause is not supported in 
add materialized view clause, expr:"
-                                                + " limit " + 
selectStmt.getLimit());
+                    + " limit " + selectStmt.getLimit());
         }
     }
 
@@ -151,7 +151,7 @@ public class CreateMaterializedViewStmt extends DdlStmt {
             Expr selectListItemExpr = selectListItem.getExpr();
             if (!(selectListItemExpr instanceof SlotRef) && 
!(selectListItemExpr instanceof FunctionCallExpr)) {
                 throw new AnalysisException("The materialized view only 
support the single column or function expr. "
-                                                    + "Error column: " + 
selectListItemExpr.toSql());
+                        + "Error column: " + selectListItemExpr.toSql());
             }
             if (selectListItem.getExpr() instanceof SlotRef) {
                 if (meetAggregate) {
@@ -164,6 +164,7 @@ public class CreateMaterializedViewStmt extends DdlStmt {
                     
ErrorReport.reportAnalysisException(ErrorCode.ERR_DUP_FIELDNAME, columnName);
                 }
                 MVColumnItem mvColumnItem = new MVColumnItem(columnName);
+                mvColumnItem.setType(slotRef.getType());
                 mvColumnItemList.add(mvColumnItem);
             } else if (selectListItem.getExpr() instanceof FunctionCallExpr) {
                 FunctionCallExpr functionCallExpr = (FunctionCallExpr) 
selectListItem.getExpr();
@@ -174,7 +175,7 @@ public class CreateMaterializedViewStmt extends DdlStmt {
                         && !functionName.equalsIgnoreCase("min")
                         && !functionName.equalsIgnoreCase("max")) {
                     throw new AnalysisException("The materialized view only 
support the sum, min and max aggregate "
-                                                        + "function. Error 
function: " + functionCallExpr.toSqlImpl());
+                            + "function. Error function: " + 
functionCallExpr.toSqlImpl());
                 }
 
                 Preconditions.checkState(functionCallExpr.getChildren().size() 
== 1);
@@ -182,13 +183,11 @@ public class CreateMaterializedViewStmt extends DdlStmt {
                 SlotRef slotRef;
                 if (functionChild0 instanceof SlotRef) {
                     slotRef = (SlotRef) functionChild0;
-                }
-                else if (functionChild0 instanceof CastExpr
-                        && (functionChild0.getChild(0) instanceof SlotRef)) {
+                } else if (functionChild0 instanceof CastExpr && 
(functionChild0.getChild(0) instanceof SlotRef)) {
                     slotRef = (SlotRef) functionChild0.getChild(0);
                 } else {
                     throw new AnalysisException("The children of aggregate 
function only support one original column. "
-                                                        + "Error function: " + 
functionCallExpr.toSqlImpl());
+                            + "Error function: " + 
functionCallExpr.toSqlImpl());
                 }
                 meetAggregate = true;
                 // check duplicate column
@@ -226,49 +225,14 @@ public class CreateMaterializedViewStmt extends DdlStmt {
 
     private void analyzeOrderByClause() throws AnalysisException {
         if (selectStmt.getOrderByElements() == null) {
-            /**
-             * The keys type of Materialized view is aggregation.
-             * All of group by columns are keys of materialized view.
-             */
-            if (mvKeysType == KeysType.AGG_KEYS) {
-                for (MVColumnItem mvColumnItem : mvColumnItemList) {
-                    if (mvColumnItem.getAggregationType() != null) {
-                        break;
-                    }
-                    mvColumnItem.setIsKey(true);
-                }
-                return;
-            }
-
-            /**
-             * There is no aggregation function in materialized view.
-             * Supplement key of MV columns
-             * For example: select k1, k2 ... kn from t1
-             * The default key columns are first 36 bytes of the columns in 
define order.
-             * If the number of columns in the first 36 is less than 3, the 
first 3 columns will be used.
-             * column: k1, k2, k3... km. The key is true.
-             * Supplement non-key of MV columns
-             * column: km... kn. The key is false, aggregation type is none, 
isAggregationTypeImplicit is true.
-             */
-            int keyStorageLayoutBytes = 0;
-            for (int i = 0; i < selectStmt.getResultExprs().size(); i++) {
-                MVColumnItem mvColumnItem = mvColumnItemList.get(i);
-                Expr resultColumn = selectStmt.getResultExprs().get(i);
-                keyStorageLayoutBytes += 
resultColumn.getType().getStorageLayoutBytes();
-                if ((i + 1) <= FeConstants.shortkey_max_column_count
-                        || keyStorageLayoutBytes < 
FeConstants.shortkey_maxsize_bytes) {
-                    mvColumnItem.setIsKey(true);
-                } else {
-                    mvColumnItem.setAggregationType(AggregateType.NONE, true);
-                }
-            }
+            supplyOrderColumn();
             return;
         }
 
         List<OrderByElement> orderByElements = selectStmt.getOrderByElements();
         if (orderByElements.size() > mvColumnItemList.size()) {
-            throw new AnalysisException("The number of columns in order clause 
must be less then "
-                                                + "the number of columns in 
select clause");
+            throw new AnalysisException("The number of columns in order clause 
must be less then " + "the number of "
+                    + "columns in select clause");
         }
         if (beginIndexOfAggregation != -1 && (orderByElements.size() != 
(beginIndexOfAggregation))) {
             throw new AnalysisException("The key of columns in mv must be all 
of group by columns");
@@ -277,13 +241,13 @@ public class CreateMaterializedViewStmt extends DdlStmt {
             Expr orderByElement = orderByElements.get(i).getExpr();
             if (!(orderByElement instanceof SlotRef)) {
                 throw new AnalysisException("The column in order clause must 
be original column without calculation. "
-                                                    + "Error column: " + 
orderByElement.toSql());
+                        + "Error column: " + orderByElement.toSql());
             }
             MVColumnItem mvColumnItem = mvColumnItemList.get(i);
             SlotRef slotRef = (SlotRef) orderByElement;
             if 
(!mvColumnItem.getName().equalsIgnoreCase(slotRef.getColumnName())) {
                 throw new AnalysisException("The order of columns in order by 
clause must be same as "
-                                                    + "the order of columns in 
select list");
+                        + "the order of columns in select list");
             }
             Preconditions.checkState(mvColumnItem.getAggregationType() == 
null);
             mvColumnItem.setIsKey(true);
@@ -301,6 +265,69 @@ public class CreateMaterializedViewStmt extends DdlStmt {
         }
     }
 
+    /*
+    This function is used to supply order by columns and calculate short key 
count
+     */
+    private void supplyOrderColumn() throws AnalysisException {
+        /**
+         * The keys type of Materialized view is aggregation.
+         * All of group by columns are keys of materialized view.
+         */
+        if (mvKeysType == KeysType.AGG_KEYS) {
+            for (MVColumnItem mvColumnItem : mvColumnItemList) {
+                if (mvColumnItem.getAggregationType() != null) {
+                    break;
+                }
+                mvColumnItem.setIsKey(true);
+            }
+        } else if (mvKeysType == KeysType.DUP_KEYS) {
+            /**
+             * There is no aggregation function in materialized view.
+             * Supplement key of MV columns
+             * The key is same as the short key in duplicate table
+             * For example: select k1, k2 ... kn from t1
+             * The default key columns are first 36 bytes of the columns in 
define order.
+             * If the number of columns in the first 36 is more than 3, the 
first 3 columns will be used.
+             * column: k1, k2, k3. The key is true.
+             * Supplement non-key of MV columns
+             * column: k4... kn. The key is false, aggregation type is none, 
isAggregationTypeImplicit is true.
+             */
+            int theBeginIndexOfValue = 0;
+            // supply key
+            int keySizeByte = 0;
+            for (; theBeginIndexOfValue < mvColumnItemList.size(); 
theBeginIndexOfValue++) {
+                MVColumnItem column = 
mvColumnItemList.get(theBeginIndexOfValue);
+                keySizeByte += column.getType().getIndexSize();
+                if (theBeginIndexOfValue + 1 > 
FeConstants.shortkey_max_column_count
+                        || keySizeByte > FeConstants.shortkey_maxsize_bytes) {
+                    if (theBeginIndexOfValue == 0 && 
column.getType().getPrimitiveType().isCharFamily()) {
+                        column.setIsKey(true);
+                        theBeginIndexOfValue++;
+                    }
+                    break;
+                }
+                if (column.getType().isFloatingPointType()) {
+                    break;
+                }
+                if (column.getType().getPrimitiveType() == 
PrimitiveType.VARCHAR) {
+                    column.setIsKey(true);
+                    theBeginIndexOfValue++;
+                    break;
+                }
+                column.setIsKey(true);
+            }
+            if (theBeginIndexOfValue == 0) {
+                throw new AnalysisException("The first column could not be 
float or double type, use decimal instead");
+            }
+            // supply value
+            for (; theBeginIndexOfValue < mvColumnItemList.size(); 
theBeginIndexOfValue++) {
+                MVColumnItem mvColumnItem = 
mvColumnItemList.get(theBeginIndexOfValue);
+                mvColumnItem.setAggregationType(AggregateType.NONE, true);
+            }
+        }
+
+    }
+
     @Override
     public String toSql() {
         return null;
diff --git a/fe/src/main/java/org/apache/doris/analysis/CreateTableStmt.java 
b/fe/src/main/java/org/apache/doris/analysis/CreateTableStmt.java
index 9e7cd58..ded7c78 100644
--- a/fe/src/main/java/org/apache/doris/analysis/CreateTableStmt.java
+++ b/fe/src/main/java/org/apache/doris/analysis/CreateTableStmt.java
@@ -25,6 +25,7 @@ import org.apache.doris.catalog.Column;
 import org.apache.doris.catalog.Index;
 import org.apache.doris.catalog.KeysType;
 import org.apache.doris.catalog.PartitionType;
+import org.apache.doris.catalog.PrimitiveType;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.Config;
 import org.apache.doris.common.ErrorCode;
@@ -283,11 +284,29 @@ public class CreateTableStmt extends DdlStmt {
                     keysDesc = new KeysDesc(KeysType.AGG_KEYS, 
keysColumnNames);
                 } else {
                     for (ColumnDef columnDef : columnDefs) {
-                        keyLength += 
columnDef.getType().getStorageLayoutBytes();
-                        if (keysColumnNames.size() < 
FeConstants.shortkey_max_column_count
-                                || keyLength < 
FeConstants.shortkey_maxsize_bytes) {
+                        keyLength += columnDef.getType().getIndexSize();
+                        if (keysColumnNames.size() >= 
FeConstants.shortkey_max_column_count
+                                || keyLength > 
FeConstants.shortkey_maxsize_bytes) {
+                            if (keysColumnNames.size() == 0
+                                    && 
columnDef.getType().getPrimitiveType().isCharFamily()) {
+                                keysColumnNames.add(columnDef.getName());
+                            }
+                            break;
+                        }
+                        if (columnDef.getType().isFloatingPointType()) {
+                            break;
+                        }
+                        if (columnDef.getType().getPrimitiveType() == 
PrimitiveType.VARCHAR) {
                             keysColumnNames.add(columnDef.getName());
+                            break;
                         }
+                        keysColumnNames.add(columnDef.getName());
+                    }
+                    // The OLAP table must has at least one short key and the 
float and double should not be short key.
+                    // So the float and double could not be the first column 
in OLAP table.
+                    if (keysColumnNames.isEmpty()) {
+                        throw new AnalysisException("The first column could 
not be float or double,"
+                                + " use decimal instead.");
                     }
                     keysDesc = new KeysDesc(KeysType.DUP_KEYS, 
keysColumnNames);
                 }
diff --git a/fe/src/main/java/org/apache/doris/analysis/MVColumnItem.java 
b/fe/src/main/java/org/apache/doris/analysis/MVColumnItem.java
index a78e216..e92bd4e 100644
--- a/fe/src/main/java/org/apache/doris/analysis/MVColumnItem.java
+++ b/fe/src/main/java/org/apache/doris/analysis/MVColumnItem.java
@@ -18,6 +18,7 @@
 package org.apache.doris.analysis;
 
 import org.apache.doris.catalog.AggregateType;
+import org.apache.doris.catalog.Type;
 
 /**
  * This is a result of semantic analysis for AddMaterializedViewClause.
@@ -27,6 +28,8 @@ import org.apache.doris.catalog.AggregateType;
  */
 public class MVColumnItem {
     private String name;
+    // the origin type of slot ref
+    private Type type;
     private boolean isKey;
     private AggregateType aggregationType;
     private boolean isAggregationTypeImplicit;
@@ -40,6 +43,14 @@ public class MVColumnItem {
         return name;
     }
 
+    public Type getType() {
+        return type;
+    }
+
+    public void setType(Type type) {
+        this.type = type;
+    }
+
     public void setIsKey(boolean key) {
         isKey = key;
     }
diff --git a/fe/src/main/java/org/apache/doris/catalog/Catalog.java 
b/fe/src/main/java/org/apache/doris/catalog/Catalog.java
index 773c76e..da9906c 100755
--- a/fe/src/main/java/org/apache/doris/catalog/Catalog.java
+++ b/fe/src/main/java/org/apache/doris/catalog/Catalog.java
@@ -4879,29 +4879,30 @@ public class Catalog {
              * contains at most one VARCHAR column. And if contains, it should
              * be at the last position of the short key list.
              */
-            shortKeyColumnCount = 1;
+            shortKeyColumnCount = 0;
             int shortKeySizeByte = 0;
-            Column firstColumn = indexColumns.get(0);
-            if (firstColumn.getDataType() != PrimitiveType.VARCHAR) {
-                shortKeySizeByte = firstColumn.getOlapColumnIndexSize();
-                int maxShortKeyColumnCount = Math.min(indexColumns.size(), 
FeConstants.shortkey_max_column_count);
-                for (int i = 1; i < maxShortKeyColumnCount; i++) {
-                    Column column = indexColumns.get(i);
-                    shortKeySizeByte += column.getOlapColumnIndexSize();
-                    if (shortKeySizeByte > FeConstants.shortkey_maxsize_bytes) 
{
-                        break;
-                    }
-                    if (column.getDataType() == PrimitiveType.VARCHAR) {
+            int maxShortKeyColumnCount = Math.min(indexColumns.size(), 
FeConstants.shortkey_max_column_count);
+            for (int i = 0; i < maxShortKeyColumnCount; i++) {
+                Column column = indexColumns.get(i);
+                shortKeySizeByte += column.getOlapColumnIndexSize();
+                if (shortKeySizeByte > FeConstants.shortkey_maxsize_bytes) {
+                    if (column.getDataType().isCharFamily()) {
                         ++shortKeyColumnCount;
-                        break;
                     }
+                    break;
+                }
+                if (column.getType().isFloatingPointType()) {
+                    break;
+                }
+                if (column.getDataType() == PrimitiveType.VARCHAR) {
                     ++shortKeyColumnCount;
+                    break;
                 }
+                ++shortKeyColumnCount;
+            }
+            if (shortKeyColumnCount == 0) {
+                throw new DdlException("The first column could not be float or 
double type, use decimal instead");
             }
-            // else
-            // first column type is VARCHAR
-            // use only first column as shortKey
-            // do nothing here
 
         } // end calc shortKeyColumnCount
 
diff --git a/fe/src/main/java/org/apache/doris/catalog/PrimitiveType.java 
b/fe/src/main/java/org/apache/doris/catalog/PrimitiveType.java
index caa8e83..0972009 100644
--- a/fe/src/main/java/org/apache/doris/catalog/PrimitiveType.java
+++ b/fe/src/main/java/org/apache/doris/catalog/PrimitiveType.java
@@ -17,15 +17,15 @@
 
 package org.apache.doris.catalog;
 
-import java.util.List;
-
 import org.apache.doris.mysql.MysqlColType;
 import org.apache.doris.thrift.TPrimitiveType;
+
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSetMultimap;
 import com.google.common.collect.Lists;
 
 import java.util.ArrayList;
+import java.util.List;
 
 public enum PrimitiveType {
     INVALID_TYPE("INVALID_TYPE", -1, TPrimitiveType.INVALID_TYPE),
@@ -671,6 +671,10 @@ public enum PrimitiveType {
         return (this == VARCHAR || this == CHAR || this == HLL);
     }
 
+    public boolean isCharFamily() {
+        return (this == VARCHAR || this == CHAR);
+    }
+
     public boolean isIntegerType() {
         return (this == TINYINT || this == SMALLINT
                 || this == INT || this == BIGINT);
diff --git a/fe/src/main/java/org/apache/doris/catalog/Type.java 
b/fe/src/main/java/org/apache/doris/catalog/Type.java
index e2d8119..4ba15c1 100644
--- a/fe/src/main/java/org/apache/doris/catalog/Type.java
+++ b/fe/src/main/java/org/apache/doris/catalog/Type.java
@@ -1030,4 +1030,12 @@ public abstract class Type {
     public int getStorageLayoutBytes() {
         return 0;
     }
+
+    public int getIndexSize() {
+        if (this.getPrimitiveType() == PrimitiveType.CHAR) {
+            return ((ScalarType) this).getLength();
+        } else {
+            return this.getPrimitiveType().getOlapColumnIndexSize();
+        }
+    }
 }
diff --git 
a/fe/src/test/java/org/apache/doris/analysis/CreateMaterializedViewStmtTest.java
 
b/fe/src/test/java/org/apache/doris/analysis/CreateMaterializedViewStmtTest.java
index de6c5a3..1a778fb 100644
--- 
a/fe/src/test/java/org/apache/doris/analysis/CreateMaterializedViewStmtTest.java
+++ 
b/fe/src/test/java/org/apache/doris/analysis/CreateMaterializedViewStmtTest.java
@@ -19,6 +19,7 @@ package org.apache.doris.analysis;
 
 import org.apache.doris.catalog.AggregateType;
 import org.apache.doris.catalog.KeysType;
+import org.apache.doris.catalog.PrimitiveType;
 import org.apache.doris.common.Config;
 import org.apache.doris.common.UserException;
 import org.apache.doris.common.jmockit.Deencapsulation;
@@ -584,16 +585,216 @@ public class CreateMaterializedViewStmtTest {
                 result = columnName3;
                 slotRef4.getColumnName();
                 result = columnName4;
-                selectStmt.getResultExprs();
-                result = Lists.newArrayList(slotRef1, slotRef2, slotRef3, 
slotRef4);
-                slotRef1.getType().getStorageLayoutBytes();
-                result = 35;
-                slotRef2.getType().getStorageLayoutBytes();
+                slotRef1.getType().getIndexSize();
+                result = 34;
+                slotRef1.getType().getPrimitiveType();
+                result = PrimitiveType.INT;
+                slotRef2.getType().getIndexSize();
+                result = 1;
+                slotRef2.getType().getPrimitiveType();
+                result = PrimitiveType.INT;
+                slotRef3.getType().getIndexSize();
+                result = 1;
+                slotRef3.getType().getPrimitiveType();
+                result = PrimitiveType.INT;
+                slotRef4.getType().getIndexSize();
+                result = 4;
+                selectStmt.getAggInfo(); // return null, so that the mv can be 
a duplicate mv
+                result = null;
+            }
+        };
+
+
+        CreateMaterializedViewStmt createMaterializedViewStmt = new 
CreateMaterializedViewStmt("test", selectStmt, null);
+        try {
+            createMaterializedViewStmt.analyze(analyzer);
+            Assert.assertEquals(KeysType.DUP_KEYS, 
createMaterializedViewStmt.getMVKeysType());
+            List<MVColumnItem> mvColumns = 
createMaterializedViewStmt.getMVColumnItemList();
+            Assert.assertEquals(4, mvColumns.size());
+            MVColumnItem mvColumn0 = mvColumns.get(0);
+            Assert.assertTrue(mvColumn0.isKey());
+            Assert.assertFalse(mvColumn0.isAggregationTypeImplicit());
+            Assert.assertEquals(columnName1, mvColumn0.getName());
+            Assert.assertEquals(null, mvColumn0.getAggregationType());
+            MVColumnItem mvColumn1 = mvColumns.get(1);
+            Assert.assertTrue(mvColumn1.isKey());
+            Assert.assertFalse(mvColumn1.isAggregationTypeImplicit());
+            Assert.assertEquals(columnName2, mvColumn1.getName());
+            Assert.assertEquals(null, mvColumn1.getAggregationType());
+            MVColumnItem mvColumn2 = mvColumns.get(2);
+            Assert.assertTrue(mvColumn2.isKey());
+            Assert.assertFalse(mvColumn2.isAggregationTypeImplicit());
+            Assert.assertEquals(columnName3, mvColumn2.getName());
+            Assert.assertEquals(null, mvColumn2.getAggregationType());
+            MVColumnItem mvColumn3 = mvColumns.get(3);
+            Assert.assertFalse(mvColumn3.isKey());
+            Assert.assertTrue(mvColumn3.isAggregationTypeImplicit());
+            Assert.assertEquals(columnName4, mvColumn3.getName());
+            Assert.assertEquals(AggregateType.NONE, 
mvColumn3.getAggregationType());
+        } catch (UserException e) {
+            Assert.fail(e.getMessage());
+        }
+    }
+
+    /*
+    ISSUE: #3811
+     */
+    @Test
+    public void 
testMVColumnsWithoutOrderbyWithoutAggregationWithFloat(@Injectable SlotRef 
slotRef1,
+            @Injectable SlotRef slotRef2, @Injectable SlotRef slotRef3, 
@Injectable SlotRef slotRef4,
+            @Injectable TableRef tableRef, @Injectable SelectStmt selectStmt) 
throws UserException {
+        SelectList selectList = new SelectList();
+        SelectListItem selectListItem1 = new SelectListItem(slotRef1, null);
+        selectList.addItem(selectListItem1);
+        SelectListItem selectListItem2 = new SelectListItem(slotRef2, null);
+        selectList.addItem(selectListItem2);
+        SelectListItem selectListItem3 = new SelectListItem(slotRef3, null);
+        selectList.addItem(selectListItem3);
+        SelectListItem selectListItem4 = new SelectListItem(slotRef4, null);
+        selectList.addItem(selectListItem4);
+
+        final String columnName1 = "k1";
+        final String columnName2 = "k2";
+        final String columnName3 = "v1";
+        final String columnName4 = "v2";
+
+        new Expectations() {
+            {
+                analyzer.getClusterName();
+                result = "default";
+                selectStmt.getAggInfo();
+                result = null;
+                selectStmt.getSelectList();
+                result = selectList;
+                selectStmt.getTableRefs();
+                result = Lists.newArrayList(tableRef);
+                selectStmt.getWhereClause();
+                result = null;
+                selectStmt.getHavingPred();
+                result = null;
+                selectStmt.getOrderByElements();
+                result = null;
+                selectStmt.getLimit();
+                result = -1;
+                selectStmt.analyze(analyzer);
+                slotRef1.getColumnName();
+                result = columnName1;
+                slotRef2.getColumnName();
+                result = columnName2;
+                slotRef3.getColumnName();
+                result = columnName3;
+                slotRef4.getColumnName();
+                result = columnName4;
+                slotRef1.getType().getIndexSize();
+                result = 1;
+                slotRef1.getType().getPrimitiveType();
+                result = PrimitiveType.INT;
+                slotRef2.getType().getIndexSize();
                 result = 2;
-                slotRef3.getType().getStorageLayoutBytes();
+                slotRef2.getType().getPrimitiveType();
+                result = PrimitiveType.INT;
+                slotRef3.getType().getIndexSize();
                 result = 3;
-                slotRef4.getType().getStorageLayoutBytes();
-                result = 4;
+                slotRef3.getType().isFloatingPointType();
+                result = true;
+                selectStmt.getAggInfo(); // return null, so that the mv can be 
a duplicate mv
+                result = null;
+            }
+        };
+
+
+        CreateMaterializedViewStmt createMaterializedViewStmt = new 
CreateMaterializedViewStmt("test", selectStmt, null);
+        try {
+            createMaterializedViewStmt.analyze(analyzer);
+            Assert.assertEquals(KeysType.DUP_KEYS, 
createMaterializedViewStmt.getMVKeysType());
+            List<MVColumnItem> mvColumns = 
createMaterializedViewStmt.getMVColumnItemList();
+            Assert.assertEquals(4, mvColumns.size());
+            MVColumnItem mvColumn0 = mvColumns.get(0);
+            Assert.assertTrue(mvColumn0.isKey());
+            Assert.assertFalse(mvColumn0.isAggregationTypeImplicit());
+            Assert.assertEquals(columnName1, mvColumn0.getName());
+            Assert.assertEquals(null, mvColumn0.getAggregationType());
+            MVColumnItem mvColumn1 = mvColumns.get(1);
+            Assert.assertTrue(mvColumn1.isKey());
+            Assert.assertFalse(mvColumn1.isAggregationTypeImplicit());
+            Assert.assertEquals(columnName2, mvColumn1.getName());
+            Assert.assertEquals(null, mvColumn1.getAggregationType());
+            MVColumnItem mvColumn2 = mvColumns.get(2);
+            Assert.assertFalse(mvColumn2.isKey());
+            Assert.assertTrue(mvColumn2.isAggregationTypeImplicit());
+            Assert.assertEquals(columnName3, mvColumn2.getName());
+            Assert.assertEquals(AggregateType.NONE, 
mvColumn2.getAggregationType());
+            MVColumnItem mvColumn3 = mvColumns.get(3);
+            Assert.assertFalse(mvColumn3.isKey());
+            Assert.assertTrue(mvColumn3.isAggregationTypeImplicit());
+            Assert.assertEquals(columnName4, mvColumn3.getName());
+            Assert.assertEquals(AggregateType.NONE, 
mvColumn3.getAggregationType());
+        } catch (UserException e) {
+            Assert.fail(e.getMessage());
+        }
+    }
+
+    /*
+    ISSUE: #3811
+    */
+    @Test
+    public void 
testMVColumnsWithoutOrderbyWithoutAggregationWithVarchar(@Injectable SlotRef 
slotRef1,
+            @Injectable SlotRef slotRef2, @Injectable SlotRef slotRef3, 
@Injectable SlotRef slotRef4,
+            @Injectable TableRef tableRef, @Injectable SelectStmt selectStmt) 
throws UserException {
+        SelectList selectList = new SelectList();
+        SelectListItem selectListItem1 = new SelectListItem(slotRef1, null);
+        selectList.addItem(selectListItem1);
+        SelectListItem selectListItem2 = new SelectListItem(slotRef2, null);
+        selectList.addItem(selectListItem2);
+        SelectListItem selectListItem3 = new SelectListItem(slotRef3, null);
+        selectList.addItem(selectListItem3);
+        SelectListItem selectListItem4 = new SelectListItem(slotRef4, null);
+        selectList.addItem(selectListItem4);
+
+        final String columnName1 = "k1";
+        final String columnName2 = "k2";
+        final String columnName3 = "v1";
+        final String columnName4 = "v2";
+
+        new Expectations() {
+            {
+                analyzer.getClusterName();
+                result = "default";
+                selectStmt.getAggInfo();
+                result = null;
+                selectStmt.getSelectList();
+                result = selectList;
+                selectStmt.getTableRefs();
+                result = Lists.newArrayList(tableRef);
+                selectStmt.getWhereClause();
+                result = null;
+                selectStmt.getHavingPred();
+                result = null;
+                selectStmt.getOrderByElements();
+                result = null;
+                selectStmt.getLimit();
+                result = -1;
+                selectStmt.analyze(analyzer);
+                slotRef1.getColumnName();
+                result = columnName1;
+                slotRef2.getColumnName();
+                result = columnName2;
+                slotRef3.getColumnName();
+                result = columnName3;
+                slotRef4.getColumnName();
+                result = columnName4;
+                slotRef1.getType().getIndexSize();
+                result = 1;
+                slotRef1.getType().getPrimitiveType();
+                result = PrimitiveType.INT;
+                slotRef2.getType().getIndexSize();
+                result = 2;
+                slotRef2.getType().getPrimitiveType();
+                result = PrimitiveType.INT;
+                slotRef3.getType().getIndexSize();
+                result = 3;
+                slotRef3.getType().getPrimitiveType();
+                result = PrimitiveType.VARCHAR;
                 selectStmt.getAggInfo(); // return null, so that the mv can be 
a duplicate mv
                 result = null;
             }
@@ -631,6 +832,110 @@ public class CreateMaterializedViewStmtTest {
         }
     }
 
+    /*
+    ISSUE: #3811
+     */
+    @Test
+    public void testMVColumnsWithFirstFloat(@Injectable SlotRef slotRef1,
+            @Injectable TableRef tableRef, @Injectable SelectStmt selectStmt) 
throws UserException {
+        SelectList selectList = new SelectList();
+        SelectListItem selectListItem1 = new SelectListItem(slotRef1, null);
+        selectList.addItem(selectListItem1);
+
+        final String columnName1 = "k1";
+
+        new Expectations() {
+            {
+                analyzer.getClusterName();
+                result = "default";
+                selectStmt.getAggInfo();
+                result = null;
+                selectStmt.getSelectList();
+                result = selectList;
+                selectStmt.getTableRefs();
+                result = Lists.newArrayList(tableRef);
+                selectStmt.getWhereClause();
+                result = null;
+                selectStmt.getHavingPred();
+                result = null;
+                selectStmt.getOrderByElements();
+                result = null;
+                selectStmt.analyze(analyzer);
+                slotRef1.getColumnName();
+                result = columnName1;
+                slotRef1.getType().isFloatingPointType();
+                result = true;
+                selectStmt.getAggInfo(); // return null, so that the mv can be 
a duplicate mv
+                result = null;
+            }
+        };
+
+
+        CreateMaterializedViewStmt createMaterializedViewStmt = new 
CreateMaterializedViewStmt("test", selectStmt, null);
+        try {
+            createMaterializedViewStmt.analyze(analyzer);
+            Assert.fail("The first column could not be float or double, use 
decimal instead");
+        } catch (UserException e) {
+            System.out.print(e.getMessage());
+        }
+    }
+
+    /*
+    ISSUE: #3811
+    */
+    @Test
+    public void testMVColumnsWithFirstVarchar(@Injectable SlotRef slotRef1,
+            @Injectable TableRef tableRef, @Injectable SelectStmt selectStmt) 
throws UserException {
+        SelectList selectList = new SelectList();
+        SelectListItem selectListItem1 = new SelectListItem(slotRef1, null);
+        selectList.addItem(selectListItem1);
+
+        final String columnName1 = "k1";
+
+        new Expectations() {
+            {
+                analyzer.getClusterName();
+                result = "default";
+                selectStmt.getAggInfo();
+                result = null;
+                selectStmt.getSelectList();
+                result = selectList;
+                selectStmt.getTableRefs();
+                result = Lists.newArrayList(tableRef);
+                selectStmt.getWhereClause();
+                result = null;
+                selectStmt.getHavingPred();
+                result = null;
+                selectStmt.getOrderByElements();
+                result = null;
+                selectStmt.getLimit();
+                result = -1;
+                selectStmt.analyze(analyzer);
+                slotRef1.getColumnName();
+                result = columnName1;
+                slotRef1.getType().getPrimitiveType();
+                result = PrimitiveType.VARCHAR;
+            }
+        };
+
+
+        CreateMaterializedViewStmt createMaterializedViewStmt = new 
CreateMaterializedViewStmt("test", selectStmt, null);
+        try {
+            createMaterializedViewStmt.analyze(analyzer);
+            Assert.assertEquals(KeysType.DUP_KEYS, 
createMaterializedViewStmt.getMVKeysType());
+            List<MVColumnItem> mvColumns = 
createMaterializedViewStmt.getMVColumnItemList();
+            Assert.assertEquals(1, mvColumns.size());
+            MVColumnItem mvColumn0 = mvColumns.get(0);
+            Assert.assertTrue(mvColumn0.isKey());
+            Assert.assertFalse(mvColumn0.isAggregationTypeImplicit());
+            Assert.assertEquals(columnName1, mvColumn0.getName());
+            Assert.assertEquals(null, mvColumn0.getAggregationType());
+        } catch (UserException e) {
+            Assert.fail(e.getMessage());
+        }
+    }
+
+
     @Test
     public void testMVColumns(@Injectable SlotRef slotRef1,
             @Injectable SlotRef slotRef2,
diff --git a/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java 
b/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java
index dc05ec5..9195490 100644
--- a/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java
+++ b/fe/src/test/java/org/apache/doris/planner/QueryPlanTest.java
@@ -69,9 +69,9 @@ public class QueryPlanTest {
         Catalog.getCurrentCatalog().createDb(createDbStmt);
         
         createTable("create table test.test1\n" + 
-                "(\n" + 
-                "    query_id varchar(48) comment \"Unique query id\",\n" + 
-                "    time datetime not null comment \"Query start time\",\n" + 
+                "(\n" +
+                "    time datetime not null comment \"Query start time\",\n" +
+                "    query_id varchar(48) comment \"Unique query id\",\n" +
                 "    client_ip varchar(32) comment \"Client IP\",\n" + 
                 "    user varchar(64) comment \"User name\",\n" + 
                 "    db varchar(96) comment \"Database of this query\",\n" + 
diff --git a/fe/src/test/java/org/apache/doris/utframe/DorisAssert.java 
b/fe/src/test/java/org/apache/doris/utframe/DorisAssert.java
index b808fec..8ba14da 100644
--- a/fe/src/test/java/org/apache/doris/utframe/DorisAssert.java
+++ b/fe/src/test/java/org/apache/doris/utframe/DorisAssert.java
@@ -141,11 +141,15 @@ public class DorisAssert {
         }
 
         public String explainQuery() throws Exception {
-            StmtExecutor stmtExecutor = new StmtExecutor(connectContext, 
"explain " + sql);
+            return internalExecute("explain " + sql);
+        }
+
+        private String internalExecute(String sql) throws Exception {
+            StmtExecutor stmtExecutor = new StmtExecutor(connectContext, sql);
             stmtExecutor.execute();
             QueryState queryState = connectContext.getState();
             if (queryState.getStateType() == QueryState.MysqlStateType.ERR) {
-                switch (queryState.getErrType()){
+                switch (queryState.getErrType()) {
                     case ANALYSIS_ERR:
                         throw new 
AnalysisException(queryState.getErrorMessage());
                     case OTHER_ERR:


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

Reply via email to