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

jshao pushed a commit to branch branch-1.1
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/branch-1.1 by this push:
     new 975faa1cac [#9816] fix(catalogs): Fix alter JDBC catalogs column 
default value problem(cherry-pick) (#9873)
975faa1cac is described below

commit 975faa1cacd9e12a50b1c321aa28e9919cc8f63e
Author: Qi Yu <[email protected]>
AuthorDate: Wed Feb 4 21:02:00 2026 +0800

    [#9816] fix(catalogs): Fix alter JDBC catalogs column default value 
problem(cherry-pick) (#9873)
    
    ### What changes were proposed in this pull request?
    
    This pull request enhances the handling of default values for
    string-type columns in JDBC catalog implementations for MySQL,
    PostgreSQL, Doris, OceanBase, and StarRocks. It ensures that string
    default values are always properly quoted in generated SQL, addressing
    cases where default values may be empty or unquoted. Comprehensive unit
    tests have been added for each implementation to verify this behavior.
    
    ### Why are the changes needed?
    
    It's a bug.
    
    Fix: #9816
    
    ### Does this PR introduce _any_ user-facing change?
    
    N/A
    
    ### How was this patch tested?
    
    UTs.
    
    Co-authored-by: Copilot <[email protected]>
---
 .../converter/JdbcColumnDefaultValueConverter.java |  10 +-
 .../jdbc/operation/JdbcTableOperations.java        |  10 ++
 catalogs/catalog-jdbc-doris/build.gradle.kts       |   1 +
 .../doris/operation/DorisTableOperations.java      |  11 +-
 .../TestDorisTableOperationsSqlGeneration.java     | 110 ++++++++++++++++++
 .../mysql/operation/MysqlTableOperations.java      |   7 +-
 .../TestMysqlTableOperationsSqlGeneration.java     |  92 +++++++++++++++
 .../operation/OceanBaseTableOperations.java        |   7 +-
 .../TestOceanBaseTableOperationsSqlGeneration.java |  92 +++++++++++++++
 .../operation/PostgreSqlTableOperations.java       |   9 +-
 ...TestPostgreSqlTableOperationsSqlGeneration.java |  92 +++++++++++++++
 .../operations/StarRocksTableOperations.java       |   7 +-
 .../TestStarRocksTableOperationsSqlGeneration.java | 123 +++++++++++++++++++++
 13 files changed, 537 insertions(+), 34 deletions(-)

diff --git 
a/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/converter/JdbcColumnDefaultValueConverter.java
 
b/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/converter/JdbcColumnDefaultValueConverter.java
index 899ab9af49..0998c9f2d6 100644
--- 
a/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/converter/JdbcColumnDefaultValueConverter.java
+++ 
b/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/converter/JdbcColumnDefaultValueConverter.java
@@ -22,6 +22,7 @@ import static 
org.apache.gravitino.rel.Column.DEFAULT_VALUE_NOT_SET;
 
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.gravitino.rel.expressions.Expression;
 import org.apache.gravitino.rel.expressions.FunctionExpression;
 import org.apache.gravitino.rel.expressions.literals.Literal;
@@ -61,7 +62,14 @@ public class JdbcColumnDefaultValueConverter {
       if (defaultValue.equals(Literals.NULL)) {
         return NULL;
       } else if (type instanceof Type.NumericType) {
-        return literal.value().toString();
+        String value = literal.value().toString();
+        // It seems that literals.value().toString() can be an empty string 
for numeric types
+        // in some cases like `alter table t modify column `id` int null 
default '';`, in such
+        // case value is an empty string, we should wrap it with single quotes 
to avoid SQL error.
+        if (StringUtils.isBlank(value)) {
+          value = "'%s'".formatted(value);
+        }
+        return value;
       } else if (type instanceof Types.TimestampType) {
         /**
          * @see LocalDateTime#toString() would return like 
'yyyy-MM-ddTHH:mm:ss'
diff --git 
a/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/operation/JdbcTableOperations.java
 
b/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/operation/JdbcTableOperations.java
index d911fa8e47..2cce434a05 100644
--- 
a/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/operation/JdbcTableOperations.java
+++ 
b/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/operation/JdbcTableOperations.java
@@ -18,6 +18,8 @@
  */
 package org.apache.gravitino.catalog.jdbc.operation;
 
+import static org.apache.gravitino.rel.Column.DEFAULT_VALUE_NOT_SET;
+
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 import java.sql.Connection;
@@ -95,6 +97,14 @@ public abstract class JdbcTableOperations implements 
TableOperation {
     this.columnDefaultValueConverter = jdbcColumnDefaultValueConverter;
   }
 
+  protected void appendDefaultValue(JdbcColumn column, StringBuilder 
sqlBuilder) {
+    if (DEFAULT_VALUE_NOT_SET.equals(column.defaultValue())) {
+      return;
+    }
+    String defaultValue = 
columnDefaultValueConverter.fromGravitino(column.defaultValue());
+    sqlBuilder.append("DEFAULT ").append(defaultValue).append(SPACE);
+  }
+
   @Override
   public void create(
       String databaseName,
diff --git a/catalogs/catalog-jdbc-doris/build.gradle.kts 
b/catalogs/catalog-jdbc-doris/build.gradle.kts
index 80c909f4c4..a380652cba 100644
--- a/catalogs/catalog-jdbc-doris/build.gradle.kts
+++ b/catalogs/catalog-jdbc-doris/build.gradle.kts
@@ -51,6 +51,7 @@ dependencies {
 
   testImplementation(libs.junit.jupiter.api)
   testImplementation(libs.junit.jupiter.params)
+  testImplementation(libs.mockito.core)
   testImplementation(libs.mysql.driver)
   testImplementation(libs.postgresql.driver)
   testImplementation(libs.testcontainers)
diff --git 
a/catalogs/catalog-jdbc-doris/src/main/java/org/apache/gravitino/catalog/doris/operation/DorisTableOperations.java
 
b/catalogs/catalog-jdbc-doris/src/main/java/org/apache/gravitino/catalog/doris/operation/DorisTableOperations.java
index 108d0440d2..08c1dc272d 100644
--- 
a/catalogs/catalog-jdbc-doris/src/main/java/org/apache/gravitino/catalog/doris/operation/DorisTableOperations.java
+++ 
b/catalogs/catalog-jdbc-doris/src/main/java/org/apache/gravitino/catalog/doris/operation/DorisTableOperations.java
@@ -24,6 +24,7 @@ import static 
org.apache.gravitino.catalog.doris.DorisTablePropertiesMetadata.RE
 import static 
org.apache.gravitino.catalog.doris.utils.DorisUtils.generatePartitionSqlFragment;
 import static org.apache.gravitino.rel.Column.DEFAULT_VALUE_NOT_SET;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import java.sql.Connection;
@@ -148,7 +149,8 @@ public class DorisTableOperations extends 
JdbcTableOperations {
     return result;
   }
 
-  private Map<String, String> appendNecessaryProperties(Map<String, String> 
properties) {
+  @VisibleForTesting
+  Map<String, String> appendNecessaryProperties(Map<String, String> 
properties) {
     Map<String, String> resultMap;
     if (properties == null) {
       resultMap = new HashMap<>();
@@ -749,12 +751,7 @@ public class DorisTableOperations extends 
JdbcTableOperations {
     }
 
     // Add DEFAULT value if specified
-    if (!DEFAULT_VALUE_NOT_SET.equals(column.defaultValue())) {
-      sqlBuilder
-          .append("DEFAULT ")
-          
.append(columnDefaultValueConverter.fromGravitino(column.defaultValue()))
-          .append(SPACE);
-    }
+    appendDefaultValue(column, sqlBuilder);
 
     // Add column auto_increment if specified
     if (column.autoIncrement()) {
diff --git 
a/catalogs/catalog-jdbc-doris/src/test/java/org/apache/gravitino/catalog/doris/operation/TestDorisTableOperationsSqlGeneration.java
 
b/catalogs/catalog-jdbc-doris/src/test/java/org/apache/gravitino/catalog/doris/operation/TestDorisTableOperationsSqlGeneration.java
new file mode 100644
index 0000000000..6d3d5a541d
--- /dev/null
+++ 
b/catalogs/catalog-jdbc-doris/src/test/java/org/apache/gravitino/catalog/doris/operation/TestDorisTableOperationsSqlGeneration.java
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+package org.apache.gravitino.catalog.doris.operation;
+
+import java.util.Collections;
+import org.apache.gravitino.catalog.doris.converter.DorisTypeConverter;
+import org.apache.gravitino.catalog.jdbc.JdbcColumn;
+import 
org.apache.gravitino.catalog.jdbc.converter.JdbcColumnDefaultValueConverter;
+import org.apache.gravitino.catalog.jdbc.converter.JdbcExceptionConverter;
+import org.apache.gravitino.rel.expressions.NamedReference;
+import org.apache.gravitino.rel.expressions.distributions.Distribution;
+import org.apache.gravitino.rel.expressions.distributions.Distributions;
+import org.apache.gravitino.rel.expressions.literals.Literals;
+import org.apache.gravitino.rel.expressions.transforms.Transforms;
+import org.apache.gravitino.rel.indexes.Indexes;
+import org.apache.gravitino.rel.types.Types;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+public class TestDorisTableOperationsSqlGeneration {
+
+  private static class TestableDorisTableOperations extends 
DorisTableOperations {
+    public TestableDorisTableOperations() {
+      super.exceptionMapper = new JdbcExceptionConverter();
+      super.typeConverter = new DorisTypeConverter();
+      super.columnDefaultValueConverter = new 
JdbcColumnDefaultValueConverter();
+    }
+
+    public String createTableSql(
+        String tableName, JdbcColumn[] columns, Distribution distribution) {
+      return generateCreateTableSql(
+          tableName,
+          columns,
+          "comment",
+          Collections.emptyMap(),
+          Transforms.EMPTY_TRANSFORM,
+          distribution,
+          Indexes.EMPTY_INDEXES);
+    }
+  }
+
+  @Test
+  public void testCreateTableWithEmptyStringDefaultValue() {
+    TestableDorisTableOperations ops = new TestableDorisTableOperations();
+    String tableName = "test_table";
+    JdbcColumn col1 =
+        JdbcColumn.builder()
+            .withName("col1")
+            .withType(Types.IntegerType.get())
+            .withNullable(false)
+            .withDefaultValue(Literals.of("", Types.VarCharType.of(255)))
+            .build();
+    // Doris requires distribution
+    Distribution distribution = Distributions.hash(1, 
NamedReference.field("col1"));
+
+    TestableDorisTableOperations mockOps = Mockito.spy(ops);
+    Mockito.doAnswer(a -> a.getArgument(0))
+        .when(mockOps)
+        .appendNecessaryProperties(Mockito.anyMap());
+
+    String sql = mockOps.createTableSql(tableName, new JdbcColumn[] {col1}, 
distribution);
+    JdbcColumnDefaultValueConverter converter = new 
JdbcColumnDefaultValueConverter();
+    Assertions.assertTrue(
+        sql.contains("DEFAULT " + 
converter.fromGravitino(col1.defaultValue())),
+        "Should contain DEFAULT '' but was: " + sql);
+  }
+
+  @Test
+  public void testCreateTableWithNonEmptyStringDefaultValue() {
+    TestableDorisTableOperations ops = new TestableDorisTableOperations();
+    String tableName = "test_table";
+    JdbcColumn col1 =
+        JdbcColumn.builder()
+            .withName("col1")
+            .withType(Types.IntegerType.get())
+            .withNullable(false)
+            .withDefaultValue(Literals.of("abc", Types.VarCharType.of(255)))
+            .build();
+    // Doris requires distribution
+    Distribution distribution = Distributions.hash(1, 
NamedReference.field("col1"));
+
+    TestableDorisTableOperations mockOps = Mockito.spy(ops);
+    Mockito.doAnswer(a -> a.getArgument(0))
+        .when(mockOps)
+        .appendNecessaryProperties(Mockito.anyMap());
+
+    String sql = mockOps.createTableSql(tableName, new JdbcColumn[] {col1}, 
distribution);
+    JdbcColumnDefaultValueConverter converter = new 
JdbcColumnDefaultValueConverter();
+    Assertions.assertTrue(
+        sql.contains("DEFAULT " + 
converter.fromGravitino(col1.defaultValue())),
+        "Should contain DEFAULT value but was: " + sql);
+  }
+}
diff --git 
a/catalogs/catalog-jdbc-mysql/src/main/java/org/apache/gravitino/catalog/mysql/operation/MysqlTableOperations.java
 
b/catalogs/catalog-jdbc-mysql/src/main/java/org/apache/gravitino/catalog/mysql/operation/MysqlTableOperations.java
index 4df98eb96f..e14fd38076 100644
--- 
a/catalogs/catalog-jdbc-mysql/src/main/java/org/apache/gravitino/catalog/mysql/operation/MysqlTableOperations.java
+++ 
b/catalogs/catalog-jdbc-mysql/src/main/java/org/apache/gravitino/catalog/mysql/operation/MysqlTableOperations.java
@@ -618,12 +618,7 @@ public class MysqlTableOperations extends 
JdbcTableOperations {
     }
 
     // Add DEFAULT value if specified
-    if (!DEFAULT_VALUE_NOT_SET.equals(column.defaultValue())) {
-      sqlBuilder
-          .append("DEFAULT ")
-          
.append(columnDefaultValueConverter.fromGravitino(column.defaultValue()))
-          .append(SPACE);
-    }
+    appendDefaultValue(column, sqlBuilder);
 
     // Add column auto_increment if specified
     if (column.autoIncrement()) {
diff --git 
a/catalogs/catalog-jdbc-mysql/src/test/java/org/apache/gravitino/catalog/mysql/operation/TestMysqlTableOperationsSqlGeneration.java
 
b/catalogs/catalog-jdbc-mysql/src/test/java/org/apache/gravitino/catalog/mysql/operation/TestMysqlTableOperationsSqlGeneration.java
new file mode 100644
index 0000000000..2727feee23
--- /dev/null
+++ 
b/catalogs/catalog-jdbc-mysql/src/test/java/org/apache/gravitino/catalog/mysql/operation/TestMysqlTableOperationsSqlGeneration.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+package org.apache.gravitino.catalog.mysql.operation;
+
+import java.util.Collections;
+import org.apache.gravitino.catalog.jdbc.JdbcColumn;
+import 
org.apache.gravitino.catalog.jdbc.converter.JdbcColumnDefaultValueConverter;
+import org.apache.gravitino.catalog.jdbc.converter.JdbcExceptionConverter;
+import org.apache.gravitino.catalog.mysql.converter.MysqlTypeConverter;
+import org.apache.gravitino.rel.expressions.distributions.Distributions;
+import org.apache.gravitino.rel.expressions.literals.Literals;
+import org.apache.gravitino.rel.expressions.transforms.Transforms;
+import org.apache.gravitino.rel.indexes.Indexes;
+import org.apache.gravitino.rel.types.Types;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TestMysqlTableOperationsSqlGeneration {
+
+  private static class TestableMysqlTableOperations extends 
MysqlTableOperations {
+    public TestableMysqlTableOperations() {
+      super.exceptionMapper = new JdbcExceptionConverter();
+      super.typeConverter = new MysqlTypeConverter();
+      super.columnDefaultValueConverter = new 
JdbcColumnDefaultValueConverter();
+    }
+
+    public String createTableSql(String tableName, JdbcColumn[] columns) {
+      return generateCreateTableSql(
+          tableName,
+          columns,
+          "comment",
+          Collections.emptyMap(),
+          Transforms.EMPTY_TRANSFORM,
+          Distributions.NONE,
+          Indexes.EMPTY_INDEXES);
+    }
+  }
+
+  @Test
+  public void testCreateTableWithEmptyStringDefaultValue() {
+    TestableMysqlTableOperations ops = new TestableMysqlTableOperations();
+    String tableName = "test_table";
+    JdbcColumn col1 =
+        JdbcColumn.builder()
+            .withName("col1")
+            .withType(Types.VarCharType.of(255))
+            .withNullable(false)
+            .withDefaultValue(Literals.of("", Types.VarCharType.of(255)))
+            .build();
+
+    String sql = ops.createTableSql(tableName, new JdbcColumn[] {col1});
+    JdbcColumnDefaultValueConverter converter = new 
JdbcColumnDefaultValueConverter();
+    Assertions.assertTrue(
+        sql.contains("DEFAULT " + 
converter.fromGravitino(col1.defaultValue())),
+        "Should contain DEFAULT '' but was: " + sql);
+  }
+
+  @Test
+  public void testCreateTableWithNonEmptyStringDefaultValue() {
+    TestableMysqlTableOperations ops = new TestableMysqlTableOperations();
+    String tableName = "test_table";
+    JdbcColumn col1 =
+        JdbcColumn.builder()
+            .withName("col1")
+            .withType(Types.VarCharType.of(255))
+            .withNullable(false)
+            .withDefaultValue(Literals.of("abc", Types.VarCharType.of(255)))
+            .build();
+
+    String sql = ops.createTableSql(tableName, new JdbcColumn[] {col1});
+    JdbcColumnDefaultValueConverter converter = new 
JdbcColumnDefaultValueConverter();
+    Assertions.assertTrue(
+        sql.contains("DEFAULT " + 
converter.fromGravitino(col1.defaultValue())),
+        "Should contain DEFAULT value but was: " + sql);
+  }
+}
diff --git 
a/catalogs/catalog-jdbc-oceanbase/src/main/java/org/apache/gravitino/catalog/oceanbase/operation/OceanBaseTableOperations.java
 
b/catalogs/catalog-jdbc-oceanbase/src/main/java/org/apache/gravitino/catalog/oceanbase/operation/OceanBaseTableOperations.java
index 697308dda2..ff3fef5e45 100644
--- 
a/catalogs/catalog-jdbc-oceanbase/src/main/java/org/apache/gravitino/catalog/oceanbase/operation/OceanBaseTableOperations.java
+++ 
b/catalogs/catalog-jdbc-oceanbase/src/main/java/org/apache/gravitino/catalog/oceanbase/operation/OceanBaseTableOperations.java
@@ -633,12 +633,7 @@ public class OceanBaseTableOperations extends 
JdbcTableOperations {
     }
 
     // Add DEFAULT value if specified
-    if (!DEFAULT_VALUE_NOT_SET.equals(column.defaultValue())) {
-      sqlBuilder
-          .append("DEFAULT ")
-          
.append(columnDefaultValueConverter.fromGravitino(column.defaultValue()))
-          .append(SPACE);
-    }
+    appendDefaultValue(column, sqlBuilder);
 
     // Add column auto_increment if specified
     if (column.autoIncrement()) {
diff --git 
a/catalogs/catalog-jdbc-oceanbase/src/test/java/org/apache/gravitino/catalog/oceanbase/operation/TestOceanBaseTableOperationsSqlGeneration.java
 
b/catalogs/catalog-jdbc-oceanbase/src/test/java/org/apache/gravitino/catalog/oceanbase/operation/TestOceanBaseTableOperationsSqlGeneration.java
new file mode 100644
index 0000000000..2897660bfc
--- /dev/null
+++ 
b/catalogs/catalog-jdbc-oceanbase/src/test/java/org/apache/gravitino/catalog/oceanbase/operation/TestOceanBaseTableOperationsSqlGeneration.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+package org.apache.gravitino.catalog.oceanbase.operation;
+
+import java.util.Collections;
+import org.apache.gravitino.catalog.jdbc.JdbcColumn;
+import 
org.apache.gravitino.catalog.jdbc.converter.JdbcColumnDefaultValueConverter;
+import org.apache.gravitino.catalog.jdbc.converter.JdbcExceptionConverter;
+import org.apache.gravitino.catalog.oceanbase.converter.OceanBaseTypeConverter;
+import org.apache.gravitino.rel.expressions.distributions.Distributions;
+import org.apache.gravitino.rel.expressions.literals.Literals;
+import org.apache.gravitino.rel.expressions.transforms.Transforms;
+import org.apache.gravitino.rel.indexes.Indexes;
+import org.apache.gravitino.rel.types.Types;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TestOceanBaseTableOperationsSqlGeneration {
+
+  private static class TestableOceanBaseTableOperations extends 
OceanBaseTableOperations {
+    public TestableOceanBaseTableOperations() {
+      super.exceptionMapper = new JdbcExceptionConverter();
+      super.typeConverter = new OceanBaseTypeConverter();
+      super.columnDefaultValueConverter = new 
JdbcColumnDefaultValueConverter();
+    }
+
+    public String createTableSql(String tableName, JdbcColumn[] columns) {
+      return generateCreateTableSql(
+          tableName,
+          columns,
+          "comment",
+          Collections.emptyMap(),
+          Transforms.EMPTY_TRANSFORM,
+          Distributions.NONE,
+          Indexes.EMPTY_INDEXES);
+    }
+  }
+
+  @Test
+  public void testCreateTableWithEmptyStringDefaultValue() {
+    TestableOceanBaseTableOperations ops = new 
TestableOceanBaseTableOperations();
+    String tableName = "test_table";
+    JdbcColumn col1 =
+        JdbcColumn.builder()
+            .withName("col1")
+            .withType(Types.VarCharType.of(255))
+            .withNullable(false)
+            .withDefaultValue(Literals.of("", Types.VarCharType.of(255)))
+            .build();
+
+    String sql = ops.createTableSql(tableName, new JdbcColumn[] {col1});
+    JdbcColumnDefaultValueConverter converter = new 
JdbcColumnDefaultValueConverter();
+    Assertions.assertTrue(
+        sql.contains("DEFAULT " + 
converter.fromGravitino(col1.defaultValue())),
+        "Should contain DEFAULT '' but was: " + sql);
+  }
+
+  @Test
+  public void testCreateTableWithNonEmptyStringDefaultValue() {
+    TestableOceanBaseTableOperations ops = new 
TestableOceanBaseTableOperations();
+    String tableName = "test_table";
+    JdbcColumn col1 =
+        JdbcColumn.builder()
+            .withName("col1")
+            .withType(Types.VarCharType.of(255))
+            .withNullable(false)
+            .withDefaultValue(Literals.of("abc", Types.VarCharType.of(255)))
+            .build();
+
+    String sql = ops.createTableSql(tableName, new JdbcColumn[] {col1});
+    JdbcColumnDefaultValueConverter converter = new 
JdbcColumnDefaultValueConverter();
+    Assertions.assertTrue(
+        sql.contains("DEFAULT " + 
converter.fromGravitino(col1.defaultValue())),
+        "Should contain DEFAULT value but was: " + sql);
+  }
+}
diff --git 
a/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/operation/PostgreSqlTableOperations.java
 
b/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/operation/PostgreSqlTableOperations.java
index 852500dbc0..ce1db26f20 100644
--- 
a/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/operation/PostgreSqlTableOperations.java
+++ 
b/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/operation/PostgreSqlTableOperations.java
@@ -18,8 +18,6 @@
  */
 package org.apache.gravitino.catalog.postgresql.operation;
 
-import static org.apache.gravitino.rel.Column.DEFAULT_VALUE_NOT_SET;
-
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
@@ -293,12 +291,7 @@ public class PostgreSqlTableOperations extends 
JdbcTableOperations
       sqlBuilder.append("NOT NULL ");
     }
     // Add DEFAULT value if specified
-    if (!DEFAULT_VALUE_NOT_SET.equals(column.defaultValue())) {
-      sqlBuilder
-          .append("DEFAULT ")
-          
.append(columnDefaultValueConverter.fromGravitino(column.defaultValue()))
-          .append(SPACE);
-    }
+    appendDefaultValue(column, sqlBuilder);
   }
 
   @Override
diff --git 
a/catalogs/catalog-jdbc-postgresql/src/test/java/org/apache/gravitino/catalog/postgresql/operation/TestPostgreSqlTableOperationsSqlGeneration.java
 
b/catalogs/catalog-jdbc-postgresql/src/test/java/org/apache/gravitino/catalog/postgresql/operation/TestPostgreSqlTableOperationsSqlGeneration.java
new file mode 100644
index 0000000000..12f2e1834e
--- /dev/null
+++ 
b/catalogs/catalog-jdbc-postgresql/src/test/java/org/apache/gravitino/catalog/postgresql/operation/TestPostgreSqlTableOperationsSqlGeneration.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+package org.apache.gravitino.catalog.postgresql.operation;
+
+import java.util.Collections;
+import org.apache.gravitino.catalog.jdbc.JdbcColumn;
+import 
org.apache.gravitino.catalog.jdbc.converter.JdbcColumnDefaultValueConverter;
+import org.apache.gravitino.catalog.jdbc.converter.JdbcExceptionConverter;
+import 
org.apache.gravitino.catalog.postgresql.converter.PostgreSqlTypeConverter;
+import org.apache.gravitino.rel.expressions.distributions.Distributions;
+import org.apache.gravitino.rel.expressions.literals.Literals;
+import org.apache.gravitino.rel.expressions.transforms.Transforms;
+import org.apache.gravitino.rel.indexes.Indexes;
+import org.apache.gravitino.rel.types.Types;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TestPostgreSqlTableOperationsSqlGeneration {
+
+  private static class TestablePostgreSqlTableOperations extends 
PostgreSqlTableOperations {
+    public TestablePostgreSqlTableOperations() {
+      super.exceptionMapper = new JdbcExceptionConverter();
+      super.typeConverter = new PostgreSqlTypeConverter();
+      super.columnDefaultValueConverter = new 
JdbcColumnDefaultValueConverter();
+    }
+
+    public String createTableSql(String tableName, JdbcColumn[] columns) {
+      return generateCreateTableSql(
+          tableName,
+          columns,
+          "comment",
+          Collections.emptyMap(),
+          Transforms.EMPTY_TRANSFORM,
+          Distributions.NONE,
+          Indexes.EMPTY_INDEXES);
+    }
+  }
+
+  @Test
+  public void testCreateTableWithEmptyStringDefaultValue() {
+    TestablePostgreSqlTableOperations ops = new 
TestablePostgreSqlTableOperations();
+    String tableName = "test_table";
+    JdbcColumn col1 =
+        JdbcColumn.builder()
+            .withName("col1")
+            .withType(Types.VarCharType.of(255))
+            .withNullable(false)
+            .withDefaultValue(Literals.of("", Types.VarCharType.of(255)))
+            .build();
+
+    String sql = ops.createTableSql(tableName, new JdbcColumn[] {col1});
+    JdbcColumnDefaultValueConverter converter = new 
JdbcColumnDefaultValueConverter();
+    Assertions.assertTrue(
+        sql.contains("DEFAULT " + 
converter.fromGravitino(col1.defaultValue())),
+        "Should contain DEFAULT '' but was: " + sql);
+  }
+
+  @Test
+  public void testCreateTableWithNonEmptyStringDefaultValue() {
+    TestablePostgreSqlTableOperations ops = new 
TestablePostgreSqlTableOperations();
+    String tableName = "test_table";
+    JdbcColumn col1 =
+        JdbcColumn.builder()
+            .withName("col1")
+            .withType(Types.VarCharType.of(255))
+            .withNullable(false)
+            .withDefaultValue(Literals.of("abc", Types.VarCharType.of(255)))
+            .build();
+
+    String sql = ops.createTableSql(tableName, new JdbcColumn[] {col1});
+    JdbcColumnDefaultValueConverter converter = new 
JdbcColumnDefaultValueConverter();
+    Assertions.assertTrue(
+        sql.contains("DEFAULT " + 
converter.fromGravitino(col1.defaultValue())),
+        "Should contain DEFAULT value but was: " + sql);
+  }
+}
diff --git 
a/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/operations/StarRocksTableOperations.java
 
b/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/operations/StarRocksTableOperations.java
index 9e6ac74736..f4dc067ba3 100644
--- 
a/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/operations/StarRocksTableOperations.java
+++ 
b/catalogs/catalog-jdbc-starrocks/src/main/java/org/apache/gravitino/catalog/starrocks/operations/StarRocksTableOperations.java
@@ -324,12 +324,7 @@ public class StarRocksTableOperations extends 
JdbcTableOperations {
     }
 
     // Add DEFAULT value if specified
-    if (!DEFAULT_VALUE_NOT_SET.equals(column.defaultValue())) {
-      sqlBuilder
-          .append("DEFAULT ")
-          
.append(columnDefaultValueConverter.fromGravitino(column.defaultValue()))
-          .append(SPACE);
-    }
+    appendDefaultValue(column, sqlBuilder);
 
     // Add column auto_increment if specified
     if (column.autoIncrement()) {
diff --git 
a/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java
 
b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java
new file mode 100644
index 0000000000..f8eab07a93
--- /dev/null
+++ 
b/catalogs/catalog-jdbc-starrocks/src/test/java/org/apache/gravitino/catalog/starrocks/operation/TestStarRocksTableOperationsSqlGeneration.java
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+package org.apache.gravitino.catalog.starrocks.operation;
+
+import java.util.Collections;
+import org.apache.gravitino.catalog.jdbc.JdbcColumn;
+import 
org.apache.gravitino.catalog.jdbc.converter.JdbcColumnDefaultValueConverter;
+import org.apache.gravitino.catalog.jdbc.converter.JdbcExceptionConverter;
+import org.apache.gravitino.catalog.starrocks.converter.StarRocksTypeConverter;
+import 
org.apache.gravitino.catalog.starrocks.operations.StarRocksTableOperations;
+import org.apache.gravitino.rel.expressions.NamedReference;
+import org.apache.gravitino.rel.expressions.distributions.Distribution;
+import org.apache.gravitino.rel.expressions.distributions.Distributions;
+import org.apache.gravitino.rel.expressions.literals.Literals;
+import org.apache.gravitino.rel.expressions.transforms.Transforms;
+import org.apache.gravitino.rel.indexes.Indexes;
+import org.apache.gravitino.rel.types.Types;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TestStarRocksTableOperationsSqlGeneration {
+
+  private static class TestableStarRocksTableOperations extends 
StarRocksTableOperations {
+
+    public TestableStarRocksTableOperations() {
+      super.exceptionMapper = new JdbcExceptionConverter();
+      super.typeConverter = new StarRocksTypeConverter();
+      super.columnDefaultValueConverter = new 
JdbcColumnDefaultValueConverter();
+    }
+
+    public String createTableSql(
+        String tableName, JdbcColumn[] columns, Distribution distribution) {
+      return generateCreateTableSql(
+          tableName,
+          columns,
+          "comment",
+          Collections.emptyMap(),
+          Transforms.EMPTY_TRANSFORM,
+          distribution,
+          Indexes.EMPTY_INDEXES);
+    }
+  }
+
+  @Test
+  public void testCreateTableWithEmptyStringDefaultValue() {
+    TestableStarRocksTableOperations ops = new 
TestableStarRocksTableOperations();
+    String tableName = "test_table";
+    JdbcColumn col1 =
+        JdbcColumn.builder()
+            .withName("col1")
+            .withType(Types.VarCharType.of(255))
+            .withNullable(false)
+            .withDefaultValue(Literals.of("", Types.VarCharType.of(255)))
+            .build();
+
+    // StarRocks requires distribution
+    Distribution distribution = Distributions.hash(1, 
NamedReference.field("col1"));
+
+    String sql = ops.createTableSql(tableName, new JdbcColumn[] {col1}, 
distribution);
+    JdbcColumnDefaultValueConverter converter = new 
JdbcColumnDefaultValueConverter();
+    Assertions.assertTrue(
+        sql.contains("DEFAULT " + 
converter.fromGravitino(col1.defaultValue())),
+        "Should contain DEFAULT '' but was: " + sql);
+  }
+
+  @Test
+  public void testCreateTableWithNonEmptyStringDefaultValue() {
+    TestableStarRocksTableOperations ops = new 
TestableStarRocksTableOperations();
+    String tableName = "test_table";
+    JdbcColumn col1 =
+        JdbcColumn.builder()
+            .withName("col1")
+            .withType(Types.VarCharType.of(255))
+            .withNullable(false)
+            .withDefaultValue(Literals.of("abc", Types.VarCharType.of(255)))
+            .build();
+
+    // StarRocks requires distribution
+    Distribution distribution = Distributions.hash(1, 
NamedReference.field("col1"));
+
+    String sql = ops.createTableSql(tableName, new JdbcColumn[] {col1}, 
distribution);
+    JdbcColumnDefaultValueConverter converter = new 
JdbcColumnDefaultValueConverter();
+    Assertions.assertTrue(
+        sql.contains("DEFAULT " + 
converter.fromGravitino(col1.defaultValue())),
+        "Should contain DEFAULT value but was: " + sql);
+  }
+
+  @Test
+  public void testCreateTableWithWhitespaceDefaultValue() {
+    TestableStarRocksTableOperations ops = new 
TestableStarRocksTableOperations();
+    String tableName = "test_table";
+    JdbcColumn col1 =
+        JdbcColumn.builder()
+            .withName("col1")
+            .withType(Types.VarCharType.of(255))
+            .withNullable(false)
+            .withDefaultValue(Literals.of("   ", Types.VarCharType.of(255)))
+            .build();
+
+    Distribution distribution = Distributions.hash(1, 
NamedReference.field("col1"));
+    String sql = ops.createTableSql(tableName, new JdbcColumn[] {col1}, 
distribution);
+    JdbcColumnDefaultValueConverter converter = new 
JdbcColumnDefaultValueConverter();
+    Assertions.assertTrue(
+        sql.contains("DEFAULT " + 
converter.fromGravitino(col1.defaultValue())),
+        "Should contain DEFAULT '   ' but was: " + sql);
+  }
+}


Reply via email to