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

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


The following commit(s) were added to refs/heads/master by this push:
     new d07e97bbb62 [fix](generated column) Preserve generated column sessions 
in CREATE TABLE LIKE (#67809)
d07e97bbb62 is described below

commit d07e97bbb6293bd1d9e729e86537c0de2eb489b4
Author: feiniaofeiafei <[email protected]>
AuthorDate: Fri Sep 18 17:12:15 2026 +0800

    [fix](generated column) Preserve generated column sessions in CREATE TABLE 
LIKE (#67809)
    
    ### What problem does this PR solve?
    
    Problem Summary:
    
    CREATE TABLE LIKE reconstructs generated columns from SQL using the
    caller's session settings, losing the expression settings saved in the
    source columns. For a generated expression `a * b` over `DECIMAL(20,5)`
    and `DECIMAL(21,6)`, a source created with `enable_decimal256=true`
    produces `1.26212529751`, but a clone created with the option disabled
    produces `1.26212530000` for the same input. SQL mode also affects
    parsing: a source expression `a || 'x'` created with `PIPES_AS_CONCAT`
    produces `ax`, while its clone can produce NULL under a different SQL
    mode.
    
    Snapshot each generated column's session settings under the source
    table's read lock and carry them through `GeneratedColumnDesc`. Restore
    these settings temporarily when parsing and analyzing the cloned
    expression, then persist them in the new `Column`. The caller's session
    is restored after analysis, including on exceptions. Ordinary CREATE
    TABLE retains its existing session behavior.
    
    Existing incorrectly created clones and stored data are not
    automatically repaired.
    
    ### Release note
    
    Fix CREATE TABLE LIKE changing generated column results when the
    caller's expression-related session settings differ from the source
    table's settings.
    
    ### Check List (For Author)
    
    - Test
        - [x] Regression test
    - Passed `test_generated_column_like_session`, `test_generated_column`,
    and `test_generated_column_fault_tolerance_nereids` on the final
    branch's FE.
    - New coverage includes both decimal256 setting directions, repeated
    LIKE, SQL mode, NULL values, and preservation of the caller's session.
    Expected output was generated by `run-regression-test.sh` and verified
    in subsequent runs.
        - [x] Unit Test
    - All 11 `CreateTableLikeTest` tests passed via `run-fe-ut.sh` on the
    initial validation baseline with the same repair and test files.
    - The final upstream baseline has an unrelated test-compilation error in
    `IvmNormalizeMTMVJoinTest` (an outdated `IvmRewriteContext` constructor
    call). Final FE packaging therefore used `DISABLE_BUILD_UI=ON
    MVN_OPT=-Dmaven.test.skip=true ./build.sh --fe`. No unrelated test code
    was changed. Checkstyle passed.
        - [x] Manual test (add detailed scripts or steps below)
    - Reproduced both precision and SQL mode differences before replacing FE
    libraries; verified correct results after replacement.
    - Restarted the final FE and cloned previously created fixed tables
    again, verifying persisted session settings and unchanged caller
    settings.
    - The test FE used `be_exec_version=13` to match its existing BE.
        - [ ] No need to test or manual test. Explain why:
    
    - Behavior changed:
        - [ ] No.
    - [x] Yes. Generated columns created through LIKE preserve the source
    columns' expression semantics.
---
 .../main/java/org/apache/doris/catalog/Column.java |   8 +-
 .../main/java/org/apache/doris/catalog/Env.java    |   2 +-
 .../plans/commands/CreateTableLikeCommand.java     |  22 ++++
 .../plans/commands/info/ColumnDefinition.java      |  12 ++-
 .../trees/plans/commands/info/CreateTableInfo.java |  40 ++++----
 .../plans/commands/info/GeneratedColumnDesc.java   |  21 +++-
 .../apache/doris/catalog/CreateTableLikeTest.java  | 112 +++++++++++++++++++++
 .../test_generated_column_like_session.out         |  25 +++++
 .../test_generated_column_like_session.groovy      |  83 +++++++++++++++
 9 files changed, 300 insertions(+), 25 deletions(-)

diff --git a/fe/fe-catalog/src/main/java/org/apache/doris/catalog/Column.java 
b/fe/fe-catalog/src/main/java/org/apache/doris/catalog/Column.java
index e7a22663d48..eefee5b729c 100644
--- a/fe/fe-catalog/src/main/java/org/apache/doris/catalog/Column.java
+++ b/fe/fe-catalog/src/main/java/org/apache/doris/catalog/Column.java
@@ -884,6 +884,11 @@ public class Column implements GsonPostProcessable {
     }
 
     public String toSql(boolean isUniqueTable, boolean isCompatible) {
+        return toSql(isUniqueTable, isCompatible, false);
+    }
+
+    /** Use a placeholder only for internal CREATE TABLE LIKE parsing; restore 
the expression before analysis. */
+    public String toSql(boolean isUniqueTable, boolean isCompatible, boolean 
useGeneratedColumnPlaceholder) {
         StringBuilder sb = new StringBuilder();
         sb.append("`").append(name).append("` ");
         String typeStr = type.toSql();
@@ -899,7 +904,8 @@ public class Column implements GsonPostProcessable {
             sb.append(" ").append(aggregationType.toSql());
         }
         if (generatedColumnInfo != null) {
-            sb.append(" AS 
(").append(generatedColumnInfo.getExprSql()).append(")");
+            sb.append(" AS (").append(useGeneratedColumnPlaceholder ? "NULL" : 
generatedColumnInfo.getExprSql())
+                    .append(")");
         }
         if (isAllowNull) {
             sb.append(" NULL");
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java
index c8a6210415d..63c3bf15ec3 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java
@@ -4338,7 +4338,7 @@ public class Env {
             // sqlalchemy requires this to parse SHOW CREATE TABLE stmt.
             if (table.isManagedTable()) {
                 sb.append("  ").append(
-                        column.toSql(((OlapTable) table).getKeysType() == 
KeysType.UNIQUE_KEYS, true));
+                        column.toSql(((OlapTable) table).getKeysType() == 
KeysType.UNIQUE_KEYS, true, true));
             } else {
                 sb.append("  ").append(column.toSql());
             }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableLikeCommand.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableLikeCommand.java
index d8dda48d19b..f17a8df0a91 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableLikeCommand.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateTableLikeCommand.java
@@ -18,6 +18,7 @@
 package org.apache.doris.nereids.trees.plans.commands;
 
 import org.apache.doris.analysis.StmtType;
+import org.apache.doris.catalog.Column;
 import org.apache.doris.catalog.DatabaseIf;
 import org.apache.doris.catalog.Env;
 import org.apache.doris.catalog.OlapTable;
@@ -28,8 +29,10 @@ import org.apache.doris.common.ErrorReport;
 import org.apache.doris.common.UserException;
 import org.apache.doris.nereids.parser.NereidsParser;
 import org.apache.doris.nereids.trees.plans.PlanType;
+import org.apache.doris.nereids.trees.plans.commands.info.ColumnDefinition;
 import org.apache.doris.nereids.trees.plans.commands.info.CreateTableInfo;
 import org.apache.doris.nereids.trees.plans.commands.info.CreateTableLikeInfo;
+import org.apache.doris.nereids.trees.plans.commands.info.GeneratedColumnDesc;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.qe.StmtExecutor;
@@ -37,7 +40,10 @@ import org.apache.doris.qe.StmtExecutor;
 import com.google.common.collect.Lists;
 import org.apache.commons.collections4.CollectionUtils;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 
 /** CreateTableLikeCommand */
 public class CreateTableLikeCommand extends Command implements ForwardWithSync 
{
@@ -76,6 +82,7 @@ public class CreateTableLikeCommand extends Command 
implements ForwardWithSync {
             }
 
             List<String> createTableStmt = Lists.newArrayList();
+            Map<String, GeneratedColumnDesc> generatedColumns = new 
HashMap<>();
             table.readLock();
             try {
                 if (table.isManagedTable()) {
@@ -93,6 +100,16 @@ public class CreateTableLikeCommand extends Command 
implements ForwardWithSync {
                     throw new DdlException("Table[" + table.getName() + "] is 
external, not support rollup copy");
                 }
 
+                for (Column column : table.getBaseSchema()) {
+                    if (column.isGeneratedColumn()) {
+                        GeneratedColumnDesc desc = new GeneratedColumnDesc(
+                                column.getGeneratedColumnInfo().getExprSql());
+                        desc.setSessionVariables(
+                                
Optional.ofNullable(column.getSessionVariables()).map(HashMap::new).orElse(null));
+                        generatedColumns.put(column.getName(), desc);
+                    }
+                }
+
                 Env.getCreateTableLikeStmt(createTableLikeInfo, 
createTableLikeInfo.getDbName(), table, createTableStmt,
                         null, null, false, false, true, -1L,
                             false, false);
@@ -115,6 +132,11 @@ public class CreateTableLikeCommand extends Command 
implements ForwardWithSync {
                 createTableCommand = new 
CreateTableCommand(createTableCommand.getCtasQuery(),
                     
createTableInfo.withTableNameAndIfNotExists(createTableLikeInfo.getTableName(),
                             createTableLikeInfo.isIfNotExists()));
+                for (ColumnDefinition column : 
createTableInfo.getColumnDefinitions()) {
+                    // The synthetic DDL contains AS (NULL); restore the 
source before any analysis.
+                    column.getGeneratedColumnDesc().ifPresent(desc ->
+                            
column.setGeneratedColumnDesc(generatedColumns.get(column.getName())));
+                }
                 createTableCommand.run(ctx, executor);
             } finally {
                 ctx.setSkipAuth(false);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/ColumnDefinition.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/ColumnDefinition.java
index 4ccc685539a..f10d9c517a0 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/ColumnDefinition.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/ColumnDefinition.java
@@ -631,8 +631,8 @@ public class ColumnDefinition {
                 
onUpdateDefaultValue.map(DefaultValue::getDefaultValueExprDef).orElse(null), 
clusterKeyId,
                 
generatedColumnDesc.map(GeneratedColumnDesc::translateToInfo).orElse(null),
                 generatedColumnsThatReferToThis,
-                generatedColumnDesc.map(desc ->
-                        
ConnectContextUtil.getAffectQueryResultInPlanVariables(ConnectContext.get()))
+                generatedColumnDesc.map(desc -> 
desc.getSessionVariables().orElseGet(() ->
+                        
ConnectContextUtil.getAffectQueryResultInPlanVariables(ConnectContext.get())))
                         .orElse(null)
                 );
         column.setAggregationTypeImplicit(aggTypeImplicit);
@@ -650,8 +650,8 @@ public class ColumnDefinition {
                 
onUpdateDefaultValue.map(DefaultValue::getDefaultValueExprDef).orElse(null), 
clusterKeyId,
                 
generatedColumnDesc.map(GeneratedColumnDesc::translateToInfo).orElse(null),
                 generatedColumnsThatReferToThis,
-                generatedColumnDesc.map(desc ->
-                        
ConnectContextUtil.getAffectQueryResultInPlanVariables(ConnectContext.get()))
+                generatedColumnDesc.map(desc -> 
desc.getSessionVariables().orElseGet(() ->
+                        
ConnectContextUtil.getAffectQueryResultInPlanVariables(ConnectContext.get())))
                         .orElse(null));
         column.setNullableSpecified(nullableSpecified);
         column.setCommentSpecified(commentSpecified);
@@ -773,6 +773,10 @@ public class ColumnDefinition {
         return generatedColumnDesc;
     }
 
+    public void setGeneratedColumnDesc(GeneratedColumnDesc 
generatedColumnDesc) {
+        this.generatedColumnDesc = Optional.of(generatedColumnDesc);
+    }
+
     public long getAutoIncInitValue() {
         return autoIncInitValue;
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java
index 6c5e728e84f..8307f965bf8 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/CreateTableInfo.java
@@ -80,6 +80,7 @@ import org.apache.doris.nereids.types.VariantField;
 import org.apache.doris.nereids.types.VariantType;
 import org.apache.doris.nereids.util.TypeCoercionUtils;
 import org.apache.doris.nereids.util.Utils;
+import org.apache.doris.qe.AutoCloseSessionVariable;
 import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.qe.SessionVariable;
 import org.apache.doris.thrift.TInvertedIndexFileStorageFormat;
@@ -1140,24 +1141,27 @@ public class CreateTableInfo {
             if (!info.isPresent()) {
                 continue;
             }
-            Expression parsedExpression = info.get().getExpression();
-            checkParsedExpressionInGeneratedColumn(parsedExpression);
-            Expression boundSlotExpression = 
SlotReplacer.INSTANCE.replace(parsedExpression, columnToSlotReference);
-            Scope scope = new Scope(slots);
-            ExpressionAnalyzer analyzer = new ExpressionAnalyzer(null, scope, 
cascadesContext, false, false);
-            Expression expr;
-            try {
-                expr = analyzer.analyze(boundSlotExpression, new 
ExpressionRewriteContext(cascadesContext));
-            } catch (AnalysisException e) {
-                throw new AnalysisException("In generated column '" + 
column.getName() + "', "
-                        + Utils.convertFirstChar(e.getMessage()));
-            }
-            checkExpressionInGeneratedColumn(expr, column, 
nameToColumnDefinition);
-            TypeCoercionUtils.checkCanCastTo(expr.getDataType(), 
column.getType());
-            ExpressionToExpr translator = new ExpressionToExpr(i, 
translateMap);
-            Expr e = expr.accept(translator, planTranslatorContext);
-            info.get().setExpr(e);
-            exprAndNames.add(new ExprAndName(e.clone(), column.getName()));
+            try (AutoCloseSessionVariable autoClose = new 
AutoCloseSessionVariable(ctx,
+                    info.get().getSessionVariables().orElse(null))) {
+                Expression parsedExpression = info.get().getExpression();
+                checkParsedExpressionInGeneratedColumn(parsedExpression);
+                Expression boundSlotExpression = 
SlotReplacer.INSTANCE.replace(parsedExpression, columnToSlotReference);
+                Scope scope = new Scope(slots);
+                ExpressionAnalyzer analyzer = new ExpressionAnalyzer(null, 
scope, cascadesContext, false, false);
+                Expression expr;
+                try {
+                    expr = analyzer.analyze(boundSlotExpression, new 
ExpressionRewriteContext(cascadesContext));
+                } catch (AnalysisException e) {
+                    throw new AnalysisException("In generated column '" + 
column.getName() + "', "
+                            + Utils.convertFirstChar(e.getMessage()));
+                }
+                checkExpressionInGeneratedColumn(expr, column, 
nameToColumnDefinition);
+                TypeCoercionUtils.checkCanCastTo(expr.getDataType(), 
column.getType());
+                ExpressionToExpr translator = new ExpressionToExpr(i, 
translateMap);
+                Expr e = expr.accept(translator, planTranslatorContext);
+                info.get().setExpr(e);
+                exprAndNames.add(new ExprAndName(e.clone(), column.getName()));
+            }
         }
 
         // for alter drop column
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/GeneratedColumnDesc.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/GeneratedColumnDesc.java
index 5639859bbd7..7b75e0cc00c 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/GeneratedColumnDesc.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/GeneratedColumnDesc.java
@@ -19,8 +19,12 @@ package org.apache.doris.nereids.trees.plans.commands.info;
 
 import org.apache.doris.analysis.Expr;
 import org.apache.doris.catalog.GeneratedColumnInfo;
+import org.apache.doris.nereids.parser.NereidsParser;
 import org.apache.doris.nereids.trees.expressions.Expression;
 
+import java.util.Map;
+import java.util.Optional;
+
 /**GeneratedColumnDesc for nereids*/
 public class GeneratedColumnDesc {
     /**GeneratedColumnType*/
@@ -33,6 +37,7 @@ public class GeneratedColumnDesc {
     private final String exprSql;
     private Expr expr;
     private final Expression expression;
+    private Optional<Map<String, String>> sessionVariables = Optional.empty();
 
     /** constructor */
     public GeneratedColumnDesc(String exprSql, Expression expression) {
@@ -41,6 +46,11 @@ public class GeneratedColumnDesc {
         this.type = GeneratedColumnType.STORED;
     }
 
+    /** Defer parsing a copied expression until the source column's session 
settings are active. */
+    public GeneratedColumnDesc(String exprSql) {
+        this(exprSql, null);
+    }
+
     public Expr getExpr() {
         return expr;
     }
@@ -50,7 +60,16 @@ public class GeneratedColumnDesc {
     }
 
     public Expression getExpression() {
-        return expression;
+        // CREATE TABLE LIKE must also parse the expression under its original 
session settings.
+        return expression == null ? new 
NereidsParser().parseExpression(exprSql) : expression;
+    }
+
+    public void setSessionVariables(Map<String, String> sessionVariables) {
+        this.sessionVariables = Optional.ofNullable(sessionVariables);
+    }
+
+    public Optional<Map<String, String>> getSessionVariables() {
+        return sessionVariables;
     }
 
     public GeneratedColumnInfo translateToInfo() {
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/catalog/CreateTableLikeTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/catalog/CreateTableLikeTest.java
index 15c2fa5e30e..9080e514d13 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/catalog/CreateTableLikeTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/catalog/CreateTableLikeTest.java
@@ -17,11 +17,17 @@
 
 package org.apache.doris.catalog;
 
+import org.apache.doris.analysis.ExprToSqlVisitor;
+import org.apache.doris.analysis.ToSqlParams;
 import org.apache.doris.common.DdlException;
 import org.apache.doris.common.ExceptionChecker;
 import org.apache.doris.common.FeConstants;
 import org.apache.doris.nereids.parser.NereidsParser;
+import org.apache.doris.nereids.trees.plans.commands.CreateTableCommand;
 import org.apache.doris.nereids.trees.plans.commands.CreateTableLikeCommand;
+import org.apache.doris.nereids.trees.plans.commands.info.GeneratedColumnDesc;
+import org.apache.doris.qe.SessionVariable;
+import org.apache.doris.qe.SqlModeHelper;
 import org.apache.doris.qe.StmtExecutor;
 import org.apache.doris.utframe.TestWithFeService;
 
@@ -49,6 +55,112 @@ public class CreateTableLikeTest extends TestWithFeService {
         createDatabase("test2");
     }
 
+    @Test
+    public void testGeneratedColumnSessionVariables() throws Exception {
+        SessionVariable original = connectContext.getSessionVariable();
+        boolean originalDecimal256 = original.enableDecimal256;
+        try {
+            for (boolean decimal256 : new boolean[] {true, false}) {
+                String sourceName = "generated_session_src_" + decimal256;
+                String targetName = "generated_session_dst_" + decimal256;
+                original.enableDecimal256 = decimal256;
+                createTable("CREATE TABLE test." + sourceName + " ("
+                        + "a DECIMAL(20,5), b DECIMAL(21,6), "
+                        + "c DECIMAL(38,11) GENERATED ALWAYS AS (a * b) NOT 
NULL) "
+                        + "DISTRIBUTED BY HASH(a) BUCKETS 1 
PROPERTIES(\"replication_num\"=\"1\")");
+                original.enableDecimal256 = !decimal256;
+                createTableLike("CREATE TABLE test." + targetName + " LIKE 
test." + sourceName);
+
+                Database db = 
Env.getCurrentInternalCatalog().getDbOrDdlException("test");
+                Column source = 
db.getTableOrDdlException(sourceName).getColumn("c");
+                Column target = 
db.getTableOrDdlException(targetName).getColumn("c");
+                Assertions.assertEquals(source.getSessionVariables(), 
target.getSessionVariables());
+                
Assertions.assertEquals(source.getGeneratedColumnInfo().getExpr().getType(),
+                        target.getGeneratedColumnInfo().getExpr().getType());
+                
Assertions.assertEquals(source.getGeneratedColumnInfo().getExpr()
+                                .accept(ExprToSqlVisitor.INSTANCE, 
ToSqlParams.WITHOUT_TABLE),
+                        target.getGeneratedColumnInfo().getExpr()
+                                .accept(ExprToSqlVisitor.INSTANCE, 
ToSqlParams.WITHOUT_TABLE));
+                Assertions.assertSame(original, 
connectContext.getSessionVariable());
+                Assertions.assertEquals(!decimal256, 
original.enableDecimal256);
+            }
+        } finally {
+            original.enableDecimal256 = originalDecimal256;
+        }
+    }
+
+    @Test
+    public void testGeneratedColumnLikeBackslashModes() throws Exception {
+        SessionVariable original = connectContext.getSessionVariable();
+        long originalSqlMode = original.getSqlMode();
+        try {
+            for (boolean noBackslashEscapes : new boolean[] {true, false}) {
+                String sourceName = "generated_backslash_src_" + 
noBackslashEscapes;
+                long sourceMode = noBackslashEscapes ? 
SqlModeHelper.MODE_NO_BACKSLASH_ESCAPES : 0;
+                long callerMode = noBackslashEscapes ? 0 : 
SqlModeHelper.MODE_NO_BACKSLASH_ESCAPES;
+                String expression = noBackslashEscapes ? "concat(a, 'C:\\')" : 
"concat(a, 'C:\\\\')";
+                original.setSqlMode(sourceMode);
+                createTable("CREATE TABLE test." + sourceName + " ("
+                        + "a VARCHAR(10), c VARCHAR(30) AS (" + expression + 
"), "
+                        + "d VARCHAR(40) AS (concat(c, 'x'))) "
+                        + "DISTRIBUTED BY HASH(a) BUCKETS 1 
PROPERTIES(\"replication_num\"=\"1\")");
+                Database db = 
Env.getCurrentInternalCatalog().getDbOrDdlException("test");
+                Table source = db.getTableOrDdlException(sourceName);
+                String sourceDdl = getCreateTableStmt(source);
+                original.setSqlMode(callerMode);
+                String previousName = sourceName;
+                for (int copy = 0; copy < 2; copy++) {
+                    String targetName = sourceName + "_copy_" + copy;
+                    createTableLike("CREATE TABLE test." + targetName + " LIKE 
test." + previousName);
+                    Table target = db.getTableOrDdlException(targetName);
+                    for (String columnName : new String[] {"c", "d"}) {
+                        Column sourceColumn = source.getColumn(columnName);
+                        Column targetColumn = target.getColumn(columnName);
+                        
Assertions.assertEquals(sourceColumn.getSessionVariables(), 
targetColumn.getSessionVariables());
+                        
Assertions.assertEquals(sourceColumn.getGeneratedColumnInfo().getExprSql(),
+                                
targetColumn.getGeneratedColumnInfo().getExprSql());
+                        
Assertions.assertEquals(sourceColumn.getGeneratedColumnInfo().getExpr()
+                                        .accept(ExprToSqlVisitor.INSTANCE, 
ToSqlParams.WITHOUT_TABLE),
+                                targetColumn.getGeneratedColumnInfo().getExpr()
+                                        .accept(ExprToSqlVisitor.INSTANCE, 
ToSqlParams.WITHOUT_TABLE));
+                    }
+                    Assertions.assertSame(original, 
connectContext.getSessionVariable());
+                    Assertions.assertEquals(callerMode, original.getSqlMode());
+                    Assertions.assertEquals(sourceDdl, 
getCreateTableStmt(source));
+                    Assertions.assertEquals(sourceDdl.replace(sourceName, 
targetName), getCreateTableStmt(target));
+                    previousName = targetName;
+                }
+            }
+        } finally {
+            original.setSqlMode(originalSqlMode);
+        }
+    }
+
+    @Test
+    public void testDeferredGeneratedColumnRestoresSessionOnFailure() throws 
Exception {
+        SessionVariable original = connectContext.getSessionVariable();
+        long originalSqlMode = original.getSqlMode();
+        try {
+            original.setSqlMode(SqlModeHelper.MODE_NO_BACKSLASH_ESCAPES);
+            GeneratedColumnDesc desc = new 
GeneratedColumnDesc("missing_generated_function(a, 'C:\\')");
+            
desc.setSessionVariables(original.getAffectQueryResultInPlanVariables());
+            original.setSqlMode(0);
+            String sql = "CREATE TABLE test.generated_deferred_failure (a 
VARCHAR(10), c VARCHAR(30) AS (NULL)) "
+                    + "DISTRIBUTED BY HASH(a) BUCKETS 1 
PROPERTIES(\"replication_num\"=\"1\")";
+            CreateTableCommand command = (CreateTableCommand) new 
NereidsParser().parseSingle(sql);
+            
command.getCreateTableInfo().getColumnDefinitions().get(1).setGeneratedColumnDesc(desc);
+            Exception failure = Assertions.assertThrows(Exception.class,
+                    () -> command.run(connectContext, new 
StmtExecutor(connectContext, sql)));
+            
Assertions.assertTrue(failure.getMessage().contains("missing_generated_function"));
+            Assertions.assertSame(original, 
connectContext.getSessionVariable());
+            Assertions.assertEquals(0, original.getSqlMode());
+            
Assertions.assertNull(Env.getCurrentInternalCatalog().getDbOrDdlException("test")
+                    .getTableNullable("generated_deferred_failure"));
+        } finally {
+            original.setSqlMode(originalSqlMode);
+        }
+    }
+
     private void createTableLike(String sql) throws Exception {
         NereidsParser nereidsParser = new NereidsParser();
         CreateTableLikeCommand command = (CreateTableLikeCommand) 
nereidsParser.parseSingle(sql);
diff --git 
a/regression-test/data/ddl_p0/test_create_table_generated_column/test_generated_column_like_session.out
 
b/regression-test/data/ddl_p0/test_create_table_generated_column/test_generated_column_like_session.out
new file mode 100644
index 00000000000..1e68fd30be0
--- /dev/null
+++ 
b/regression-test/data/ddl_p0/test_create_table_generated_column/test_generated_column_like_session.out
@@ -0,0 +1,25 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !session_after_like --
+false
+
+-- !decimal_true --
+copy   1.12343 1.123457        1.26212529751
+dst    1.12343 1.123457        1.26212529751
+src    1.12343 1.123457        1.26212529751
+
+-- !session_after_reverse_like --
+true
+
+-- !decimal_false --
+dst    1.12343 1.123457        1.26212530000
+src    1.12343 1.123457        1.26212530000
+
+-- !sql_mode_after_like --
+
+
+-- !sql_mode --
+dst    \N      \N
+dst    a       ax
+src    \N      \N
+src    a       ax
+
diff --git 
a/regression-test/suites/ddl_p0/test_create_table_generated_column/test_generated_column_like_session.groovy
 
b/regression-test/suites/ddl_p0/test_create_table_generated_column/test_generated_column_like_session.groovy
new file mode 100644
index 00000000000..7d96b0c2491
--- /dev/null
+++ 
b/regression-test/suites/ddl_p0/test_create_table_generated_column/test_generated_column_like_session.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_generated_column_like_session") {
+    sql "DROP TABLE IF EXISTS test_gencol_like_decimal_src"
+    sql "DROP TABLE IF EXISTS test_gencol_like_decimal_dst"
+    sql "DROP TABLE IF EXISTS test_gencol_like_decimal_copy"
+    sql "SET enable_decimal256 = true"
+    sql """
+        CREATE TABLE test_gencol_like_decimal_src (
+            a DECIMAL(20,5), b DECIMAL(21,6),
+            c DECIMAL(38,11) GENERATED ALWAYS AS (a * b) NOT NULL
+        )
+        DISTRIBUTED BY HASH(a) BUCKETS 1
+        PROPERTIES("replication_num" = "1")
+    """
+    sql "SET enable_decimal256 = false"
+    sql "CREATE TABLE test_gencol_like_decimal_dst LIKE 
test_gencol_like_decimal_src"
+    qt_session_after_like "SELECT @@enable_decimal256"
+    sql "CREATE TABLE test_gencol_like_decimal_copy LIKE 
test_gencol_like_decimal_dst"
+    sql "INSERT INTO test_gencol_like_decimal_src VALUES (1.12343, 1.123457, 
DEFAULT)"
+    sql "INSERT INTO test_gencol_like_decimal_dst VALUES (1.12343, 1.123457, 
DEFAULT)"
+    sql "INSERT INTO test_gencol_like_decimal_copy VALUES (1.12343, 1.123457, 
DEFAULT)"
+    order_qt_decimal_true """
+        SELECT 'src', a, b, c FROM test_gencol_like_decimal_src
+        UNION ALL SELECT 'dst', a, b, c FROM test_gencol_like_decimal_dst
+        UNION ALL SELECT 'copy', a, b, c FROM test_gencol_like_decimal_copy
+    """
+
+    sql "DROP TABLE IF EXISTS test_gencol_like_decimal_false_src"
+    sql "DROP TABLE IF EXISTS test_gencol_like_decimal_false_dst"
+    sql """
+        CREATE TABLE test_gencol_like_decimal_false_src (
+            a DECIMAL(20,5), b DECIMAL(21,6),
+            c DECIMAL(38,11) GENERATED ALWAYS AS (a * b) NOT NULL
+        )
+        DISTRIBUTED BY HASH(a) BUCKETS 1
+        PROPERTIES("replication_num" = "1")
+    """
+    sql "SET enable_decimal256 = true"
+    sql "CREATE TABLE test_gencol_like_decimal_false_dst LIKE 
test_gencol_like_decimal_false_src"
+    qt_session_after_reverse_like "SELECT @@enable_decimal256"
+    sql "INSERT INTO test_gencol_like_decimal_false_src VALUES (1.12343, 
1.123457, DEFAULT)"
+    sql "INSERT INTO test_gencol_like_decimal_false_dst VALUES (1.12343, 
1.123457, DEFAULT)"
+    order_qt_decimal_false """
+        SELECT 'src', a, b, c FROM test_gencol_like_decimal_false_src
+        UNION ALL SELECT 'dst', a, b, c FROM test_gencol_like_decimal_false_dst
+    """
+
+    sql "DROP TABLE IF EXISTS test_gencol_like_sql_mode_src"
+    sql "DROP TABLE IF EXISTS test_gencol_like_sql_mode_dst"
+    sql "SET sql_mode = 'PIPES_AS_CONCAT'"
+    sql """
+        CREATE TABLE test_gencol_like_sql_mode_src (
+            a VARCHAR(10), c VARCHAR(20) GENERATED ALWAYS AS (a || 'x')
+        )
+        DISTRIBUTED BY HASH(a) BUCKETS 1
+        PROPERTIES("replication_num" = "1")
+    """
+    sql "SET sql_mode = ''"
+    sql "CREATE TABLE test_gencol_like_sql_mode_dst LIKE 
test_gencol_like_sql_mode_src"
+    qt_sql_mode_after_like "SELECT @@sql_mode"
+    sql "INSERT INTO test_gencol_like_sql_mode_src VALUES ('a', DEFAULT), 
(NULL, DEFAULT)"
+    sql "INSERT INTO test_gencol_like_sql_mode_dst VALUES ('a', DEFAULT), 
(NULL, DEFAULT)"
+    order_qt_sql_mode """
+        SELECT 'src', a, c FROM test_gencol_like_sql_mode_src
+        UNION ALL SELECT 'dst', a, c FROM test_gencol_like_sql_mode_dst
+    """
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to