morrySnow commented on code in PR #35284:
URL: https://github.com/apache/doris/pull/35284#discussion_r1628900860


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/insert/InsertUtils.java:
##########
@@ -344,6 +357,31 @@ public static Plan normalizePlan(Plan plan, TableIf table) 
{
                     StatementScopeIdGenerator.newRelationId(), 
constantExprs.build()));
         }
         List<LogicalPlan> oneRowRelations = oneRowRelationBuilder.build();
+
+        // if (plan instanceof UnboundTableSink) {
+        //     List<String> newColNames = new ArrayList<>();
+        //     if (unboundLogicalSink.getColNames().isEmpty()) {
+        //         for (Column column : table.getBaseSchema(false)) {
+        //             if (column.getGeneratedColumnInfo() != null) {
+        //                 continue;
+        //             }
+        //             newColNames.add(column.getName());
+        //         }
+        //     } else {
+        //         for (String name : unboundLogicalSink.getColNames()) {
+        //             Column column = table.getColumn(name);
+        //             if (column.getGeneratedColumnInfo() != null) {
+        //                 continue;
+        //             }
+        //             newColNames.add(name);
+        //         }
+        //     }
+        //     if (!unboundLogicalSink.getColNames().isEmpty() && 
newColNames.isEmpty()) {
+        //
+        //     }
+        //     plan = ((UnboundTableSink) plan).withColNames(newColNames);
+        // }

Review Comment:
   remove useless code



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/insert/InsertUtils.java:
##########
@@ -383,6 +421,10 @@ public static TableIf getTargetTable(Plan plan, 
ConnectContext ctx) {
 
     private static NamedExpression generateDefaultExpression(Column column) {
         try {
+            GeneratedColumnInfo generatedColumnInfo = 
column.getGeneratedColumnInfo();
+            if (generatedColumnInfo != null) {
+                return new Alias(new 
NullLiteral(DataType.fromCatalogType(column.getType())), column.getName());

Review Comment:
   add comment to explain why use nullliteral as a placeholder



##########
regression-test/suites/ddl_p0/test_create_table_generated_column/fault_tolerance_nereids.groovy:
##########
@@ -0,0 +1,159 @@
+// 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_generated_column_fault_tolerance_nereids") {
+    sql "SET enable_nereids_planner=true;"
+    sql "SET enable_fallback_to_original_planner=false;"
+    test {
+        sql """
+        create table gencol_type_check(a int,b int, c array<int> generated 
always as (abs(a+b,3)) not null)
+        DISTRIBUTED BY HASH(a)
+        PROPERTIES("replication_num" = "1");
+        """
+        exception "Can not found function 'abs' which has 2 arity."
+    }
+
+    // gencol_has_sum
+    test {
+        sql """
+        create table gencol_has_sum(a int,b int, c int generated always as 
(sum(a)) not null)
+        DISTRIBUTED BY HASH(a)
+        PROPERTIES("replication_num" = "1");
+        """
+        exception "Expression of generated column 'c' contains a disallowed 
function"
+    }
+
+    // gencol_has_column_not_define
+    test {
+        sql """
+        create table gencol_has_sum(a int,b int, c int generated always as 
(abs(d)) not null)
+        DISTRIBUTED BY HASH(a)
+        PROPERTIES("replication_num" = "1");
+        """
+        exception "Unknown column 'd' in 'generated column function'"
+    }
+
+    // gencol_refer_gencol_after
+    test {
+        sql """
+        create table gencol_refer_gencol(a int,c double generated always as 
(abs(a+d)) not null,b int, d int generated always as(c+1))
+        DISTRIBUTED BY HASH(a)
+        PROPERTIES("replication_num" = "1");
+        """
+        exception "Generated column can refer only to generated columns 
defined prior to it."
+    }
+
+    sql "set @myvar=2"
+    // gencol_has_var
+    test {
+        sql """
+        create table test_gen_col_not_null100(a varchar(10),c double generated 
always as (abs(a+b+@myvar)) not null,b int)
+        DISTRIBUTED BY HASH(a)
+        PROPERTIES("replication_num" = "1");
+        """
+        exception "Generated column expression cannot contain variable."
+    }
+
+    test {
+        sql """
+        create table test_gen_col_auto_increment(a bigint not null 
auto_increment, b int, c int as (a*b)) 
+        distributed by hash(a) properties("replication_num" = "1");
+        """
+        exception "Generated column 'c' cannot refer to auto-increment column."
+    }
+
+    test{
+        sql """
+        create table test_gen_col_subquery(a int,b int, c int generated always 
as (a+(select 1)) not null)
+        DISTRIBUTED BY HASH(a)
+        PROPERTIES("replication_num" = "1");
+        """
+        exception "Generated column does not support subquery."
+    }
+
+    test {
+        sql """
+        create table test_gen_col_array_func_lambda(pk int,a array<int>,b 
array<int>, c array<int> generated always as (array_count(x->(x%2=0),b)) not 
null)
+        DISTRIBUTED BY HASH(pk)
+        PROPERTIES("replication_num" = "1");
+        """
+        exception "Generated column does not support lambda."
+    }
+
+    test {
+        sql """
+            create table test_gen_col_array_func(pk int,a array<int>,b 
array<int>, c double generated always as (a+b) not null)
+            DISTRIBUTED BY HASH(pk)
+            PROPERTIES("replication_num" = "1");
+        """
+        exception "Cannot cast from ARRAY<INT> to numeric type"

Review Comment:
   The error message should mention that it is related to a generated column
   
   



##########
fe/fe-core/src/main/java/org/apache/doris/alter/SchemaChangeHandler.java:
##########
@@ -376,6 +378,21 @@ private boolean processDropColumn(DropColumnClause 
alterClause, OlapTable olapTa
             }
         }
 
+        // generated column check
+        Map<String, Column> nameToColumn = new HashMap<>();

Review Comment:
   check alter table column datatype in next pr?



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSink.java:
##########
@@ -381,6 +387,20 @@ private static Map<String, NamedExpression> 
getColumnToOutput(
                 }
             }
         }
+        for (Column column : generatedColumns) {

Review Comment:
   add this explaination to a comment to avoid confusing when reading code



##########
fe/fe-core/src/main/java/org/apache/doris/catalog/Column.java:
##########
@@ -931,6 +947,9 @@ public String toSql(boolean isUniqueTable, boolean 
isCompatible) {
         } else {
             sb.append(typeStr);
         }
+        if (generatedColumnInfo != null) {
+            return generatedColumnToSql(sb);

Review Comment:
   why not just append generated column info here and reuse other code?



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundTableSink.java:
##########
@@ -173,6 +173,11 @@ public Plan 
withGroupExprLogicalPropChildren(Optional<GroupExpression> groupExpr
                 isPartialUpdate, dmlCommandType, groupExpression, 
logicalProperties, children.get(0));
     }
 
+    public Plan withColNames(List<String> colNames) {
+        return new UnboundTableSink<>(nameParts, colNames, hints, 
temporaryPartition, partitions, autoDetectPartition,
+                isPartialUpdate, dmlCommandType, groupExpression, 
Optional.of(getLogicalProperties()), child());
+    }
+

Review Comment:
   unused function remove it



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java:
##########
@@ -798,5 +824,209 @@ public CreateTableStmt translateToLegacyStmt() {
     public void setIsExternal(boolean isExternal) {
         this.isExternal = isExternal;
     }
+
+    private void genreatedColumnCommonCheck() {
+        boolean hasGeneratedCol = false;
+        for (ColumnDefinition column : columns) {
+            if (column.getGeneratedColumnDesc().isPresent()) {
+                hasGeneratedCol = true;
+                break;
+            }
+        }
+        if (hasGeneratedCol && !engineName.equalsIgnoreCase("olap")) {
+            throw new AnalysisException("Tables can only have generated 
columns if the olap engine is used");
+        }
+        if (hasGeneratedCol && keysType == KeysType.AGG_KEYS) {
+            throw new AnalysisException("Generated Column cannot be used in 
the aggregate table");
+        }
+    }
+
+    private void generatedColumnCheck(ConnectContext ctx) {
+        genreatedColumnCommonCheck();
+        LogicalEmptyRelation plan = new LogicalEmptyRelation(
+                ConnectContext.get().getStatementContext().getNextRelationId(),
+                new ArrayList<>());
+        CascadesContext cascadesContext = 
CascadesContext.initContext(ctx.getStatementContext(), plan,
+                PhysicalProperties.ANY);
+        Map<String, Slot> columnToSlotReference = Maps.newHashMap();
+        Map<String, ColumnDefinition> nameToColumnDefinition = 
Maps.newHashMap();
+        Map<Slot, SlotRefAndIdx> translateMap = Maps.newHashMap();
+        for (int i = 0; i < columns.size(); i++) {
+            ColumnDefinition column = columns.get(i);
+            Slot slot = new SlotReference(column.getName(), column.getType());
+            columnToSlotReference.put(column.getName(), slot);
+            nameToColumnDefinition.put(column.getName(), column);
+            SlotRef slotRef = new SlotRef(null, column.getName());
+            slotRef.setType(column.getType().toCatalogDataType());
+            translateMap.put(slot, new SlotRefAndIdx(slotRef, i, 
column.getGeneratedColumnDesc().isPresent()));
+        }
+        ExpressionToExpr.initializeslotRefMap(translateMap);
+        PlanTranslatorContext planTranslatorContext = new 
PlanTranslatorContext(cascadesContext);
+        List<Slot> slots = Lists.newArrayList(columnToSlotReference.values());
+        List<GeneratedColumnUtil.ExprAndname> exprAndnames = 
Lists.newArrayList();
+        for (int i = 0; i < columns.size(); i++) {
+            ColumnDefinition column = columns.get(i);
+            Optional<GeneratedColumnDesc> info = 
column.getGeneratedColumnDesc();
+            if (!info.isPresent()) {
+                continue;
+            }
+            Expression parsedExpression = info.get().getExpression();
+            checkparsedExpressionInGeneratedColumn(parsedExpression);

Review Comment:
   ```suggestion
               checkParsedExpressionInGeneratedColumn(parsedExpression);
   ```



##########
fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java:
##########
@@ -686,6 +686,17 @@ public String toSqlImpl() {
             sb.append(((FunctionCallExpr) expr).fnName);
             sb.append(" ");
             sb.append(children.get(1).toSql());
+        } else if (fnName.getFunction().equalsIgnoreCase("encryptkeyref")) {

Review Comment:
   if rely on tosql of Expr, we should check all subclass of Expr to ensure it 
is right later



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java:
##########
@@ -798,5 +824,209 @@ public CreateTableStmt translateToLegacyStmt() {
     public void setIsExternal(boolean isExternal) {
         this.isExternal = isExternal;
     }
+
+    private void genreatedColumnCommonCheck() {
+        boolean hasGeneratedCol = false;
+        for (ColumnDefinition column : columns) {
+            if (column.getGeneratedColumnDesc().isPresent()) {
+                hasGeneratedCol = true;
+                break;
+            }
+        }
+        if (hasGeneratedCol && !engineName.equalsIgnoreCase("olap")) {
+            throw new AnalysisException("Tables can only have generated 
columns if the olap engine is used");
+        }
+        if (hasGeneratedCol && keysType == KeysType.AGG_KEYS) {
+            throw new AnalysisException("Generated Column cannot be used in 
the aggregate table");

Review Comment:
   why? could be used in key column?



##########
regression-test/suites/ddl_p0/test_create_table_generated_column/test_generated_column_nereids.groovy:
##########


Review Comment:
   add case `insert into tbl select ...`. we should throw exception when try to 
insert data into generated column



##########
regression-test/suites/ddl_p0/test_create_table_generated_column/fault_tolerance_nereids.groovy:
##########
@@ -0,0 +1,159 @@
+// 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_generated_column_fault_tolerance_nereids") {
+    sql "SET enable_nereids_planner=true;"
+    sql "SET enable_fallback_to_original_planner=false;"
+    test {
+        sql """
+        create table gencol_type_check(a int,b int, c array<int> generated 
always as (abs(a+b,3)) not null)
+        DISTRIBUTED BY HASH(a)
+        PROPERTIES("replication_num" = "1");
+        """
+        exception "Can not found function 'abs' which has 2 arity."
+    }
+
+    // gencol_has_sum
+    test {
+        sql """
+        create table gencol_has_sum(a int,b int, c int generated always as 
(sum(a)) not null)
+        DISTRIBUTED BY HASH(a)
+        PROPERTIES("replication_num" = "1");
+        """
+        exception "Expression of generated column 'c' contains a disallowed 
function"

Review Comment:
   print the disallowed function sql?



##########
regression-test/suites/ddl_p0/test_create_table_generated_column/fault_tolerance_nereids.groovy:
##########


Review Comment:
   should print column name in error message



##########
fe/fe-core/src/main/java/org/apache/doris/common/proc/IndexSchemaProcNode.java:
##########
@@ -65,6 +65,9 @@ public static ProcResult createResult(List<Column> schema, 
Set<String> bfColumns
             if (column.isAutoInc()) {
                 extras.add("AUTO_INCREMENT");
             }
+            if (column.getGeneratedColumnInfo() != null) {
+                extras.add("GENERATED");

Review Comment:
   mysql print: STORED GENERATED or VIRTUAL GENERATED



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


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

Reply via email to