This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch branch-4.2
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-4.2 by this push:
new b323ddc5d62 branch-4.2: [fix](fe) Quote variant predefined field
comments in generated SQL (#69756)
b323ddc5d62 is described below
commit b323ddc5d622515d838b539bd9676dd1c410b66e
Author: lihangyu <[email protected]>
AuthorDate: Thu Oct 29 09:43:07 2026 +0800
branch-4.2: [fix](fe) Quote variant predefined field comments in generated
SQL (#69756)
cherry-pick #68194
---
.../org/apache/doris/catalog/VariantField.java | 3 +-
.../doris/nereids/parser/LogicalPlanBuilder.java | 9 +---
.../apache/doris/nereids/types/VariantField.java | 3 +-
.../java/org/apache/doris/catalog/TypeTest.java | 16 +++++++
.../test_variant_predefine_comment_escape.out | 4 ++
.../test_variant_predefine_comment_escape.groovy | 55 ++++++++++++++++++++++
6 files changed, 81 insertions(+), 9 deletions(-)
diff --git
a/fe/fe-common/src/main/java/org/apache/doris/catalog/VariantField.java
b/fe/fe-common/src/main/java/org/apache/doris/catalog/VariantField.java
index adb99c52cf0..1f0ecacb492 100644
--- a/fe/fe-common/src/main/java/org/apache/doris/catalog/VariantField.java
+++ b/fe/fe-common/src/main/java/org/apache/doris/catalog/VariantField.java
@@ -75,7 +75,8 @@ public class VariantField {
sb.append("'").append(pattern).append("'");
sb.append(":").append(type.toSql(depth + 1));
if (!comment.isEmpty()) {
- sb.append(" COMMENT '").append(comment).append("'");
+ sb.append(" COMMENT \"").append(comment.replace("\\",
"\\\\").replace("\"", "\"\""))
+ .append("\"");
}
return sb.toString();
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
index 9fffd1180b3..b9932c79f10 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
@@ -5487,13 +5487,8 @@ public class LogicalPlanBuilder extends
DorisParserBaseVisitor<Object> {
@Override
public VariantField visitVariantSubColType(VariantSubColTypeContext ctx) {
- String comment;
- if (ctx.commentSpec() != null) {
- comment = ctx.commentSpec().STRING_LITERAL().getText();
- comment =
LogicalPlanBuilderAssistant.escapeBackSlash(comment.substring(1,
comment.length() - 1));
- } else {
- comment = "";
- }
+ String comment = ctx.commentSpec() == null ? ""
+ :
SqlLiteralUtils.parseStringLiteral(ctx.commentSpec().STRING_LITERAL().getText());
String pattern = ctx.STRING_LITERAL().getText();
pattern = pattern.substring(1, pattern.length() - 1);
if (ctx.variantSubColMatchType() != null) {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/VariantField.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/VariantField.java
index 5faed6893be..20e05b840dc 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/VariantField.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/VariantField.java
@@ -17,6 +17,7 @@
package org.apache.doris.nereids.types;
+import org.apache.doris.nereids.util.SqlLiteralUtils;
import org.apache.doris.nereids.util.Utils;
import org.apache.doris.thrift.TPatternType;
@@ -85,7 +86,7 @@ public class VariantField {
sb.append("'").append(pattern).append("'");
sb.append(":").append(dataType.toSql());
if (!comment.isEmpty()) {
- sb.append(" COMMENT '").append(comment).append("'");
+ sb.append(" COMMENT
").append(SqlLiteralUtils.quoteStringLiteral(comment));
}
return sb.toString();
}
diff --git a/fe/fe-core/src/test/java/org/apache/doris/catalog/TypeTest.java
b/fe/fe-core/src/test/java/org/apache/doris/catalog/TypeTest.java
index 0fae4b9c191..7f1861c96d2 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/catalog/TypeTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/catalog/TypeTest.java
@@ -19,6 +19,7 @@ package org.apache.doris.catalog;
import org.apache.doris.common.Config;
+import org.apache.doris.nereids.parser.NereidsParser;
import org.junit.Assert;
import org.junit.Test;
@@ -190,6 +191,21 @@ public class TypeTest {
}
}
+ @Test
+ public void testVariantFieldCommentToSqlRoundTrip() {
+ String comment = "O'Reilly \"quoted\" a\\b";
+ ArrayList<VariantField> fields = new ArrayList<>();
+ fields.add(new VariantField("price", Type.INT, comment));
+ String sql = new VariantType(fields, 0, false, 10000, 1, false, 0L,
64, false).toSql();
+
+ org.apache.doris.nereids.types.VariantType parsed =
(org.apache.doris.nereids.types.VariantType)
+ new NereidsParser().parseDataType(sql);
+ Assert.assertEquals(comment,
parsed.getPredefinedFields().get(0).getComment());
+ org.apache.doris.nereids.types.VariantType reparsed =
(org.apache.doris.nereids.types.VariantType)
+ new NereidsParser().parseDataType("variant<" +
parsed.getPredefinedFields().get(0).toSql() + ">");
+ Assert.assertEquals(comment,
reparsed.getPredefinedFields().get(0).getComment());
+ }
+
// ===================== Mixed Nesting & Precision =====================
@Test
public void testArrayMapStructCombinationWithPrecision() {
diff --git
a/regression-test/data/variant_p0/predefine/test_variant_predefine_comment_escape.out
b/regression-test/data/variant_p0/predefine/test_variant_predefine_comment_escape.out
new file mode 100644
index 00000000000..2b18bf6ae0e
--- /dev/null
+++
b/regression-test/data/variant_p0/predefine/test_variant_predefine_comment_escape.out
@@ -0,0 +1,4 @@
+-- This file is automatically generated. You should know what you did if you
want to edit this
+-- !select_copy --
+1 10 n p
+
diff --git
a/regression-test/suites/variant_p0/predefine/test_variant_predefine_comment_escape.groovy
b/regression-test/suites/variant_p0/predefine/test_variant_predefine_comment_escape.groovy
new file mode 100644
index 00000000000..9fcc88479ed
--- /dev/null
+++
b/regression-test/suites/variant_p0/predefine/test_variant_predefine_comment_escape.groovy
@@ -0,0 +1,55 @@
+// 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.
+
+// SHOW CREATE TABLE must print predefined field comments as SQL literals that
can be replayed.
+suite("test_variant_predefine_comment_escape") {
+ sql "DROP TABLE IF EXISTS test_variant_predefine_comment_escape"
+ sql "DROP TABLE IF EXISTS test_variant_predefine_comment_escape_copy"
+ sql """
+ CREATE TABLE test_variant_predefine_comment_escape (
+ id INT,
+ v VARIANT<
+ 'price':INT COMMENT "O'Reilly",
+ 'name':STRING COMMENT 'say ''hi'' and "bye"',
+ 'path':STRING COMMENT 'C:\\\\tmp',
+ PROPERTIES ("variant_max_subcolumns_count" = "10")
+ >
+ ) DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 1
+ PROPERTIES ("replication_num" = "1")
+ """
+ // SHOW CREATE TABLE output also carries cluster-dependent properties (doc
mode, binlog,
+ // file cache), so only the predefined field list is compared here.
+ def predefinedFields = { String ddl -> (ddl =~ /variant<(.*),PROPERTIES
/)[0][1] }
+
+ def ddl = sql("SHOW CREATE TABLE
test_variant_predefine_comment_escape")[0][1]
+ def fields = predefinedFields(ddl)
+ // The comments keep their quotes, so they are only replayable when
printed as escaped literals.
+ assertTrue(fields.contains("O'Reilly"))
+ assertTrue(fields.contains('say '))
+ assertTrue(fields.contains('bye'))
+
+ // Replaying the printed DDL must yield a table whose fields print exactly
the same again:
+ // a lost escape fails the replay, and a mangled one changes the text.
+ sql ddl.replace("`test_variant_predefine_comment_escape`",
"`test_variant_predefine_comment_escape_copy`")
+ def copyDdl = sql("SHOW CREATE TABLE
test_variant_predefine_comment_escape_copy")[0][1]
+ assertEquals(fields, predefinedFields(copyDdl))
+
+ // These release branches default to Variant V1; its sink parses the JSON
string.
+ sql """INSERT INTO test_variant_predefine_comment_escape_copy
+ SELECT 1, '{"price": 10, "name": "n", "path": "p"}'"""
+ order_qt_select_copy "SELECT id, v['price'], v['name'], v['path'] FROM
test_variant_predefine_comment_escape_copy"
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]