This is an automated email from the ASF dual-hosted git repository.
michaelsmith pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/impala.git
The following commit(s) were added to refs/heads/master by this push:
new 6a0eedf4a IMPALA-13299: Support CREATE TABLE LIKE for Iceberg from
HDFS sources
6a0eedf4a is described below
commit 6a0eedf4af137828257529501ace360208af0a3c
Author: Arnab Karmakar <[email protected]>
AuthorDate: Tue Dec 2 23:17:38 2025 +0530
IMPALA-13299: Support CREATE TABLE LIKE for Iceberg from HDFS sources
This patch enables creating Iceberg tables from non-Iceberg HDFS source
tables (Parquet, ORC, etc.) using CREATE TABLE LIKE with STORED BY ICEBERG.
This provides a metadata-only operation to convert table schemas to Iceberg
format without copying data.
Supported source types: Parquet, ORC, Avro, Text, and other HDFS-based
formats
Not supported: Kudu tables, JDBC tables, Paimon tables
Use case: This is particularly useful for Apache Hive 3.1 environments where
CTAS (CREATE TABLE AS SELECT) with STORED BY ICEBERG is not supported - that
feature requires Hive 4.0+. Users can use CREATE TABLE LIKE to create the
Iceberg schema, then use INSERT INTO to migrate data.
Testing:
- Comprehensive tests covering schema conversion with various data types,
partitioned and external tables, complex types (STRUCT, ARRAY, MAP)
- Bidirectional conversion tests (non-Iceberg → Iceberg and reverse)
- Hive interoperability tests verifying data round-trips correctly
Change-Id: Id162f217e49e9f396419b09815b92eb7f351881e
Reviewed-on: http://gerrit.cloudera.org:8080/23733
Reviewed-by: Impala Public Jenkins <[email protected]>
Tested-by: Impala Public Jenkins <[email protected]>
---
docs/topics/impala_iceberg.xml | 46 ++-
.../impala/analysis/CreateTableLikeStmt.java | 18 +-
.../apache/impala/service/CatalogOpExecutor.java | 69 ++++
.../org/apache/impala/analysis/AnalyzeDDLTest.java | 19 ++
.../iceberg-create-table-like-non-iceberg.test | 349 +++++++++++++++++++++
.../queries/QueryTest/iceberg-negative.test | 3 +-
tests/query_test/test_iceberg.py | 6 +
7 files changed, 497 insertions(+), 13 deletions(-)
diff --git a/docs/topics/impala_iceberg.xml b/docs/topics/impala_iceberg.xml
index f2d474032..70e6b446d 100644
--- a/docs/topics/impala_iceberg.xml
+++ b/docs/topics/impala_iceberg.xml
@@ -1054,15 +1054,53 @@ ORDER BY made_current_at;
<conbody>
<p>
Use <codeph>CREATE TABLE ... LIKE ...</codeph> to create an empty
Iceberg table
- based on the definition of another Iceberg table, including any column
attributes in
- the original table:
+ based on the definition of another table, including any column
attributes in
+ the original table. When cloning from an Iceberg table, the
<codeph>STORED BY
+ ICEBERG</codeph> clause is optional (the format is inherited). When
cloning from
+ a non-Iceberg table, you must explicitly specify <codeph>STORED BY
ICEBERG</codeph>:
<codeblock>
+ -- From an Iceberg table (format inherited)
CREATE TABLE new_ice_tbl LIKE orig_ice_tbl;
+
+ -- From a non-Iceberg table (must specify format)
+ CREATE TABLE new_ice_tbl LIKE parquet_tbl STORED BY ICEBERG;
+ </codeblock>
+ </p>
+ <p>
+ When creating from a non-Iceberg source table, Impala automatically
converts
+ the schema to Iceberg's format. All supported Impala types (including
complex
+ types like STRUCT, ARRAY, and MAP) are converted to their Iceberg
equivalents.
+ If the source table has partition columns, they are converted to
identity-partitioned
+ columns in the new Iceberg table.
+ </p>
+ <p>
+ Example creating an Iceberg table from a Parquet table:
+ <codeblock>
+ CREATE TABLE my_ice_tbl LIKE functional_parquet.complextypestbl
STORED BY ICEBERG;
</codeblock>
</p>
<p>
- Because of the Data Types of Iceberg and Impala do not correspond one
by one, Impala
- can only clone between Iceberg tables.
+ <b>Limitations for CREATE TABLE LIKE with Iceberg:</b>
+ </p>
+ <p>
+ <b>Unsupported table types:</b>
+ <ul>
+ <li><b>Kudu tables:</b> CREATE TABLE LIKE is not supported between
Kudu and
+ Iceberg tables because Kudu-specific features (hash partitioning,
range
+ partitioning, primary key uniqueness constraints) do not have
direct equivalents
+ in Iceberg's partitioning model.</li>
+ <li><b>JDBC tables:</b> Cannot be created as target tables with
CREATE TABLE LIKE.</li>
+ <li><b>Paimon tables:</b> Cannot be used as source or target for
CREATE TABLE LIKE.</li>
+ <li><b>Iceberg to non-Iceberg:</b> Creating non-Iceberg tables
(Parquet, ORC, Text, etc.)
+ from Iceberg sources is not currently supported.</li>
+ </ul>
+ </p>
+ <p>
+ <b>Unsupported data types:</b>
+ <ul>
+ <li><b>TINYINT:</b> Iceberg does not support TINYINT type. Use INT
instead.</li>
+ <li><b>SMALLINT:</b> Iceberg does not support SMALLINT type. Use INT
instead.</li>
+ </ul>
</p>
</conbody>
</concept>
diff --git
a/fe/src/main/java/org/apache/impala/analysis/CreateTableLikeStmt.java
b/fe/src/main/java/org/apache/impala/analysis/CreateTableLikeStmt.java
index 026b817a5..4b829fa66 100644
--- a/fe/src/main/java/org/apache/impala/analysis/CreateTableLikeStmt.java
+++ b/fe/src/main/java/org/apache/impala/analysis/CreateTableLikeStmt.java
@@ -175,19 +175,21 @@ public class CreateTableLikeStmt extends StatementBase {
validateCreateKuduTableParams(srcTable);
- // Only clone between Iceberg tables because the Data Types of Iceberg and
Impala
- // do not correspond one by one, the transformation logic is in
- // org.apache.impala.util.IcebergSchemaConverter.fromImpalaType method.
- if (fileFormat_ == THdfsFileFormat.ICEBERG && !IcebergTable.isIcebergTable(
- srcTable.getMetaStoreTable())) {
- throw new AnalysisException(srcTable.getFullName() + " cannot be cloned
into an "
- + "Iceberg table because it is not an Iceberg table.");
- } else if (fileFormat_ == THdfsFileFormat.JDBC) {
+ // Validate table format restrictions:
+ // - JDBC tables cannot be created with CREATE TABLE LIKE (target
restriction)
+ // - Paimon tables cannot be used as source or target
+ // - Iceberg tables cannot be used to create non-Iceberg tables
+ if (fileFormat_ == THdfsFileFormat.JDBC) {
throw new AnalysisException("CREATE TABLE LIKE is not supported for JDBC
tables.");
} else if (fileFormat_ == THdfsFileFormat.PAIMON
|| srcTable instanceof FePaimonTable) {
throw new AnalysisException("CREATE TABLE LIKE is not supported for " +
"PAIMON tables.");
+ } else if (IcebergTable.isIcebergTable(srcTable.getMetaStoreTable())
+ && fileFormat_ != null && fileFormat_ != THdfsFileFormat.ICEBERG) {
+ throw new AnalysisException(String.format(
+ "CREATE TABLE LIKE is not supported for creating %s table from
Iceberg " +
+ "table %s.", fileFormat_.toString(), srcTable.getFullName()));
}
srcDbName_ = srcTable.getDb().getName();
diff --git a/fe/src/main/java/org/apache/impala/service/CatalogOpExecutor.java
b/fe/src/main/java/org/apache/impala/service/CatalogOpExecutor.java
index 6c4319136..979983c2e 100644
--- a/fe/src/main/java/org/apache/impala/service/CatalogOpExecutor.java
+++ b/fe/src/main/java/org/apache/impala/service/CatalogOpExecutor.java
@@ -233,7 +233,10 @@ import org.apache.impala.thrift.THdfsCachingOp;
import org.apache.impala.thrift.THdfsFileFormat;
import org.apache.impala.thrift.TIcebergCatalog;
import org.apache.impala.thrift.TImpalaTableType;
+import org.apache.impala.thrift.TIcebergPartitionField;
import org.apache.impala.thrift.TIcebergPartitionSpec;
+import org.apache.impala.thrift.TIcebergPartitionTransform;
+import org.apache.impala.thrift.TIcebergPartitionTransformType;
import org.apache.impala.thrift.TKuduPartitionParam;
import org.apache.impala.thrift.TPaimonCatalog;
import org.apache.impala.thrift.TPartitionDef;
@@ -4662,6 +4665,46 @@ public class CatalogOpExecutor {
params.if_not_exists, columns, partitionSpec,
Lists.newArrayList(srcIceTable.getIcebergSchema().identifierFieldNames()),
tableProperties, params.getComment(), debugAction);
+ } else if (!IcebergTable.isIcebergTable(srcTable.getMetaStoreTable())
+ && IcebergTable.isIcebergTable(tbl)) {
+ // Creating an Iceberg table from a non-Iceberg source table
+ // Kudu tables should have been rejected during analysis
+ // in validateCreateKuduTableParams()
+ Preconditions.checkState(!(srcTable instanceof KuduTable),
+ "Kudu tables should be rejected in analysis phase");
+
+ // For Iceberg, all columns (including partition columns) must be in the
schema
+ // Column order matters: non-partitioning columns first, then
partitioning columns
+ // This matches Hive's convention for INSERT and Iceberg's flat schema
model
+ List<TColumn> columns = new ArrayList<>();
+ for (Column col: srcTable.getColumnsInHiveOrder()) {
+ TColumn tcol = col.toThrift();
+ // Default to nullable for Iceberg (optional fields) if not explicitly
set
+ if (!tcol.isSetIs_nullable()) {
+ tcol.setIs_nullable(true);
+ }
+ columns.add(tcol);
+ }
+
+ // Convert partition keys to Iceberg partition spec with identity
transforms
+ TIcebergPartitionSpec partitionSpec = null;
+ if (srcTable.getMetaStoreTable().isSetPartitionKeys()
+ && !srcTable.getMetaStoreTable().getPartitionKeys().isEmpty()) {
+ partitionSpec = createIdentityPartitionSpec(
+ srcTable.getMetaStoreTable().getPartitionKeys());
+ }
+
+ // Clear partition keys from the HMS table - Iceberg uses partition
transforms
+ // instead. The partition columns are already included in the schema
above
+ tbl.getPartitionKeys().clear();
+
+ // Use empty table properties since we're creating from a non-Iceberg
source
+ Map<String, String> tableProperties = new HashMap<>();
+
+ createIcebergTable(tbl, wantMinimalResult, response, catalogTimeline,
+ params.if_not_exists, columns, partitionSpec,
+ new ArrayList<>(), // No primary keys for non-Iceberg source
+ tableProperties, params.getComment(), debugAction);
} else if (srcTable instanceof KuduTable && KuduTable.isKuduTable(tbl)) {
TCreateTableParams createTableParams =
extractKuduCreateTableParams(params, tblName, (KuduTable) srcTable,
tbl);
@@ -4674,6 +4717,32 @@ public class CatalogOpExecutor {
}
}
+ /**
+ * Creates a TIcebergPartitionSpec with IDENTITY transforms
+ * for the given partition keys. This is used when creating an
+ * Iceberg table from a non-Iceberg source table.
+ */
+ private TIcebergPartitionSpec createIdentityPartitionSpec(
+ List<FieldSchema> partitionKeys) {
+ TIcebergPartitionSpec partitionSpec = new TIcebergPartitionSpec();
+ List<TIcebergPartitionField> partitionFields = new ArrayList<>();
+
+ for (FieldSchema partitionKey : partitionKeys) {
+ TIcebergPartitionField field = new TIcebergPartitionField();
+ field.setOrig_field_name(partitionKey.getName());
+ field.setField_name(partitionKey.getName());
+
+ TIcebergPartitionTransform transform = new TIcebergPartitionTransform();
+ transform.setTransform_type(TIcebergPartitionTransformType.IDENTITY);
+ field.setTransform(transform);
+
+ partitionFields.add(field);
+ }
+
+ partitionSpec.setPartition_fields(partitionFields);
+ return partitionSpec;
+ }
+
/**
* Build TCreateTableParams by source
*/
diff --git a/fe/src/test/java/org/apache/impala/analysis/AnalyzeDDLTest.java
b/fe/src/test/java/org/apache/impala/analysis/AnalyzeDDLTest.java
index 412e930a6..7369aff50 100644
--- a/fe/src/test/java/org/apache/impala/analysis/AnalyzeDDLTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/AnalyzeDDLTest.java
@@ -2905,6 +2905,25 @@ public class AnalyzeDDLTest extends FrontendTestBase {
AnalysisError("create table test_like like
functional_parquet.paimon_partitioned" +
" STORED BY PAIMON",
"CREATE TABLE LIKE is not supported for PAIMON tables.");
+
+ // Test creating Iceberg tables from non-Iceberg sources
+ // Non-partitioned table to Iceberg
+ AnalyzesOk("create table functional.ice_tbl like " +
+ "functional_parquet.complextypestbl stored by iceberg");
+ // Partitioned table to Iceberg
+ AnalyzesOk("create table functional.ice_part_tbl like " +
+ "functional.alltypes stored by iceberg");
+ // With IF NOT EXISTS
+ AnalyzesOk("create table if not exists functional.ice_tbl2 like " +
+ "functional_parquet.complextypestbl stored by iceberg");
+ // External Iceberg table from non-Iceberg source
+ AnalyzesOk("create external table functional.ice_external like " +
+ "functional.alltypes stored by iceberg");
+ // Kudu to Iceberg should fail (not supported)
+ AnalysisError("create table ice_from_kudu like functional_kudu.alltypes " +
+ "stored by iceberg",
+ "functional_kudu.alltypes cannot be cloned into a ICEBERG table:
CREATE TABLE " +
+ "LIKE is not supported between Kudu tables and non-Kudu tables.");
}
@Test
diff --git
a/testdata/workloads/functional-query/queries/QueryTest/iceberg-create-table-like-non-iceberg.test
b/testdata/workloads/functional-query/queries/QueryTest/iceberg-create-table-like-non-iceberg.test
new file mode 100644
index 000000000..97e2db5b1
--- /dev/null
+++
b/testdata/workloads/functional-query/queries/QueryTest/iceberg-create-table-like-non-iceberg.test
@@ -0,0 +1,349 @@
+====
+---- QUERY
+# Test creating Iceberg table from non-Iceberg table (non-partitioned)
+# Create source table with various types
+CREATE TABLE non_ice_src (
+ id INT COMMENT 'id column',
+ name STRING,
+ age BIGINT,
+ score DOUBLE,
+ active BOOLEAN,
+ created_date DATE,
+ created_ts TIMESTAMP,
+ price DECIMAL(10,2),
+ `data` BINARY
+) STORED AS PARQUET;
+---- RESULTS
+'Table has been created.'
+====
+---- QUERY
+# Create Iceberg table from non-Iceberg source
+CREATE TABLE ice_from_non_ice LIKE non_ice_src STORED BY ICEBERG;
+---- RESULTS
+'Table has been created.'
+====
+---- QUERY
+# Verify the Iceberg table schema matches source
+DESCRIBE ice_from_non_ice;
+---- RESULTS
+'id','int','id column','true'
+'name','string','','true'
+'age','bigint','','true'
+'score','double','','true'
+'active','boolean','','true'
+'created_date','date','','true'
+'created_ts','timestamp','','true'
+'price','decimal(10,2)','','true'
+'data','binary','','true'
+---- TYPES
+STRING,STRING,STRING,STRING
+====
+---- QUERY
+# Verify it's an Iceberg table
+DESCRIBE FORMATTED ice_from_non_ice;
+---- RESULTS: VERIFY_IS_SUBSET
+'# col_name ','data_type ','comment '
+'','NULL','NULL'
+'id','int','id column'
+'name','string','NULL'
+'age','bigint','NULL'
+'score','double','NULL'
+'active','boolean','NULL'
+'created_date','date','NULL'
+'created_ts','timestamp','NULL'
+'price','decimal(10,2)','NULL'
+'data','binary','NULL'
+'Location:
','$NAMENODE/test-warehouse/$DATABASE.db/ice_from_non_ice','NULL'
+'','storage_handler
','org.apache.iceberg.mr.hive.HiveIcebergStorageHandler'
+'SerDe Library: ','org.apache.iceberg.mr.hive.HiveIcebergSerDe','NULL'
+'InputFormat:
','org.apache.iceberg.mr.hive.HiveIcebergInputFormat','NULL'
+'OutputFormat:
','org.apache.iceberg.mr.hive.HiveIcebergOutputFormat','NULL'
+---- TYPES
+string, string, string
+====
+---- QUERY
+# Insert data into the Iceberg table to verify it works
+INSERT INTO ice_from_non_ice VALUES (1, 'Alice', 30, 95.5, true, '2024-01-01',
'2024-01-01 10:00:00', 100.50, cast('test' as binary));
+---- RUNTIME_PROFILE
+row_regex: .*NumModifiedRows: 1.*
+---- LABELS
+====
+---- QUERY
+# Query the data back
+SELECT id, name, age, score, active FROM ice_from_non_ice ORDER BY id;
+---- RESULTS
+1,'Alice',30,95.5,true
+---- TYPES
+INT,STRING,BIGINT,DOUBLE,BOOLEAN
+====
+---- QUERY
+# Test with partitioned source table
+CREATE TABLE part_src (
+ id INT,
+ name STRING,
+ value DOUBLE
+) PARTITIONED BY (year INT, month INT)
+STORED AS PARQUET;
+---- RESULTS
+'Table has been created.'
+====
+---- QUERY
+# Insert data to create partitions
+INSERT INTO part_src PARTITION(year=2024, month=1) VALUES (1, 'Q1', 100.0);
+---- RUNTIME_PROFILE
+row_regex: .*NumModifiedRows: 1.*
+---- LABELS
+====
+---- QUERY
+# Create Iceberg table from partitioned source
+CREATE TABLE part_ice LIKE part_src STORED BY ICEBERG;
+---- RESULTS
+'Table has been created.'
+====
+---- QUERY
+# Verify schema - note that partition columns become regular columns
+DESCRIBE part_ice;
+---- RESULTS
+'id','int','','true'
+'name','string','','true'
+'value','double','','true'
+'year','int','','true'
+'month','int','','true'
+---- TYPES
+STRING,STRING,STRING,STRING
+====
+---- QUERY
+# Verify partition transform information (should have identity transforms for
year and month)
+DESCRIBE FORMATTED part_ice;
+---- RESULTS: VERIFY_IS_SUBSET
+'# col_name ','data_type ','comment '
+'','NULL','NULL'
+'id','int','NULL'
+'name','string','NULL'
+'value','double','NULL'
+'year','int','NULL'
+'month','int','NULL'
+'# Partition Transform Information','NULL','NULL'
+'# col_name ','transform_type ','NULL'
+'year','IDENTITY','NULL'
+'month','IDENTITY','NULL'
+'','storage_handler
','org.apache.iceberg.mr.hive.HiveIcebergStorageHandler'
+---- TYPES
+string, string, string
+====
+---- QUERY
+# Insert data into partitioned Iceberg table
+INSERT INTO part_ice VALUES (2, 'Q2', 200.0, 2024, 2);
+---- RUNTIME_PROFILE
+row_regex: .*NumModifiedRows: 1.*
+---- LABELS
+====
+---- QUERY
+# Query partitioned data
+SELECT id, name, value, year, month FROM part_ice ORDER BY id;
+---- RESULTS
+2,'Q2',200,2024,2
+---- TYPES
+INT,STRING,DOUBLE,INT,INT
+====
+---- QUERY
+# Test with external table
+CREATE EXTERNAL TABLE ext_ice LIKE non_ice_src STORED BY ICEBERG;
+---- RESULTS
+'Table has been created.'
+====
+---- QUERY
+# Verify external table properties
+DESCRIBE FORMATTED ext_ice;
+---- RESULTS: VERIFY_IS_SUBSET
+'# col_name ','data_type ','comment '
+'','NULL','NULL'
+'id','int','id column'
+'Table Type: ','EXTERNAL_TABLE ','NULL'
+'','storage_handler
','org.apache.iceberg.mr.hive.HiveIcebergStorageHandler'
+---- TYPES
+string, string, string
+====
+---- QUERY
+# Test with complex types from functional_parquet.complextypestbl
+CREATE TABLE complex_ice LIKE functional_parquet.complextypestbl STORED BY
ICEBERG;
+---- RESULTS
+'Table has been created.'
+====
+---- QUERY
+# Verify complex types are preserved in the schema
+DESCRIBE complex_ice;
+---- RESULTS
+'id','bigint','','true'
+'int_array','array<int>','','true'
+'int_array_array','array<array<int>>','','true'
+'int_map','map<string,int>','','true'
+'int_map_array','array<map<string,int>>','','true'
+'nested_struct','struct<\n a:int,\n b:array<int>,\n c:struct<\n
d:array<array<struct<\n e:int,\n f:string\n >>>\n >,\n
g:map<string,struct<\n h:struct<\n i:array<double>\n >\n
>>\n>','','true'
+---- TYPES
+STRING,STRING,STRING,STRING
+====
+---- QUERY
+# Verify Iceberg table properties
+DESCRIBE FORMATTED complex_ice;
+---- RESULTS: VERIFY_IS_SUBSET
+'# col_name ','data_type ','comment '
+'','NULL','NULL'
+'id','bigint','NULL'
+'','storage_handler
','org.apache.iceberg.mr.hive.HiveIcebergStorageHandler'
+---- TYPES
+string, string, string
+====
+---- HIVE_QUERY
+use $DATABASE;
+INSERT INTO complex_ice (id, int_array, int_map) VALUES
+ (1, array(1,2,3), map('k1', 10)),
+ (2, array(4,5,6), map('k2', 20)),
+ (3, array(7,8,9), map('k3', 30));
+====
+---- QUERY
+# Refresh metadata to see Hive changes
+REFRESH complex_ice;
+====
+---- QUERY
+# Verify Impala can query the actual complex type data inserted via Hive
+SELECT id, int_array, int_map FROM complex_ice ORDER BY id;
+---- RESULTS
+1,'[1,2,3]','{"k1":10}'
+2,'[4,5,6]','{"k2":20}'
+3,'[7,8,9]','{"k3":30}'
+---- TYPES
+BIGINT,STRING,STRING
+====
+---- QUERY
+# Test IF NOT EXISTS
+CREATE TABLE IF NOT EXISTS ice_from_non_ice LIKE non_ice_src STORED BY ICEBERG;
+---- RESULTS
+'Table already exists.'
+====
+---- QUERY
+# Negative test: Kudu to Iceberg should fail
+CREATE TABLE ice_from_kudu LIKE functional_kudu.alltypes STORED BY ICEBERG;
+---- CATCH
+functional_kudu.alltypes cannot be cloned into a ICEBERG table: CREATE TABLE
LIKE is not supported between Kudu tables and non-Kudu tables.
+====
+---- QUERY
+# Test with table that has comments
+CREATE TABLE commented_src (
+ col1 INT COMMENT 'first column',
+ col2 STRING COMMENT 'second column'
+) COMMENT 'source table comment' STORED AS PARQUET;
+---- RESULTS
+'Table has been created.'
+====
+---- QUERY
+# Create Iceberg table and verify comments are preserved
+CREATE TABLE commented_ice LIKE commented_src STORED BY ICEBERG;
+---- RESULTS
+'Table has been created.'
+====
+---- QUERY
+# Verify column comments are preserved
+DESCRIBE commented_ice;
+---- RESULTS
+'col1','int','first column','true'
+'col2','string','second column','true'
+---- TYPES
+STRING,STRING,STRING,STRING
+====
+---- QUERY
+# Test with ORC source format
+CREATE TABLE orc_src (
+ id INT,
+ name STRING,
+ score DOUBLE
+) STORED AS ORC;
+---- RESULTS
+'Table has been created.'
+====
+---- QUERY
+# Create Iceberg table from ORC source
+CREATE TABLE ice_from_orc LIKE orc_src STORED BY ICEBERG;
+---- RESULTS
+'Table has been created.'
+====
+---- QUERY
+# Verify schema from ORC source
+DESCRIBE ice_from_orc;
+---- RESULTS
+'id','int','','true'
+'name','string','','true'
+'score','double','','true'
+---- TYPES
+STRING,STRING,STRING,STRING
+====
+---- QUERY
+# Test with Avro source format - create a simple Avro table
+CREATE TABLE avro_src (
+ id INT,
+ value BIGINT,
+ description STRING
+) STORED AS AVRO;
+---- RESULTS
+'Table has been created.'
+====
+---- QUERY
+# Create Iceberg table from Avro source
+CREATE TABLE ice_from_avro LIKE avro_src STORED BY ICEBERG;
+---- RESULTS
+'Table has been created.'
+====
+---- QUERY
+# Verify schema from Avro source
+DESCRIBE ice_from_avro;
+---- RESULTS
+'id','int','from deserializer','true'
+'value','bigint','from deserializer','true'
+'description','string','from deserializer','true'
+---- TYPES
+STRING,STRING,STRING,STRING
+====
+---- QUERY
+# Test with Text source format - create a simple Text table
+CREATE TABLE text_src (
+ id INT,
+ name STRING,
+ age INT
+) STORED AS TEXTFILE;
+---- RESULTS
+'Table has been created.'
+====
+---- QUERY
+# Create Iceberg table from Text source
+CREATE TABLE ice_from_text LIKE text_src STORED BY ICEBERG;
+---- RESULTS
+'Table has been created.'
+====
+---- QUERY
+# Verify schema from Text source
+DESCRIBE ice_from_text;
+---- RESULTS
+'id','int','','true'
+'name','string','','true'
+'age','int','','true'
+---- TYPES
+STRING,STRING,STRING,STRING
+====
+---- QUERY
+# Negative test: Creating non-Iceberg table from Iceberg source should fail
+CREATE TABLE parquet_from_ice LIKE ice_from_non_ice STORED AS PARQUET;
+---- CATCH
+CREATE TABLE LIKE is not supported for creating PARQUET table from Iceberg
table
+====
+---- QUERY
+# Negative test: Creating ORC table from Iceberg source should fail
+CREATE TABLE orc_from_ice LIKE ice_from_non_ice STORED AS ORC;
+---- CATCH
+CREATE TABLE LIKE is not supported for creating ORC table from Iceberg table
+====
+---- QUERY
+# Negative test: Creating Text table from Iceberg source should fail
+CREATE TABLE text_from_ice LIKE ice_from_non_ice STORED AS TEXTFILE;
+---- CATCH
+CREATE TABLE LIKE is not supported for creating TEXT table from Iceberg table
+====
diff --git
a/testdata/workloads/functional-query/queries/QueryTest/iceberg-negative.test
b/testdata/workloads/functional-query/queries/QueryTest/iceberg-negative.test
index 1f5d68760..18505ed8b 100644
---
a/testdata/workloads/functional-query/queries/QueryTest/iceberg-negative.test
+++
b/testdata/workloads/functional-query/queries/QueryTest/iceberg-negative.test
@@ -678,9 +678,10 @@ ALTER TABLE iceberg_alter_part SET PARTITION SPEC
(HOUR(d));
ImpalaRuntimeException: Failed to ALTER table 'iceberg_alter_part': Cannot
bind: hour cannot transform date values from 'd'
====
---- QUERY
+# TINYINT, SMALLINT not supported in Iceberg
CREATE TABLE clone_ice LIKE functional_parquet.alltypestiny STORED AS ICEBERG;
---- CATCH
-functional_parquet.alltypestiny cannot be cloned into an Iceberg table because
it is not an Iceberg table.
+Type TINYINT is not supported in Iceberg
====
---- QUERY
select * from functional_parquet.iceberg_alltypes_part for system_time as of
'2000-01-01 01:02:03';
diff --git a/tests/query_test/test_iceberg.py b/tests/query_test/test_iceberg.py
index be72fac13..87e8bddc4 100644
--- a/tests/query_test/test_iceberg.py
+++ b/tests/query_test/test_iceberg.py
@@ -1287,6 +1287,12 @@ class TestIcebergTable(IcebergTestSuite):
self.run_test_case('QueryTest/iceberg-create-table-like-table', vector,
use_db=unique_database)
+ @SkipIfFS.hive
+ def test_create_table_like_non_iceberg(self, vector, unique_database):
+ """Test creating Iceberg table from non-Iceberg source"""
+ self.run_test_case('QueryTest/iceberg-create-table-like-non-iceberg',
vector,
+ use_db=unique_database)
+
def test_table_owner(self, vector, unique_database):
self.run_table_owner_test(vector, unique_database, "some_random_user")
self.run_table_owner_test(vector, unique_database, "another_random_user")