dtenedor commented on code in PR #59640:
URL: https://github.com/apache/spark/pull/59640#discussion_r4428430109


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/CheckAnalysis.scala:
##########
@@ -1014,6 +1037,25 @@ trait CheckAnalysis extends LookupCatalog with 
QueryErrorsBase with PlanToString
             create.tableSchema.foreach(f => 
TypeUtils.failWithIntervalType(f.dataType))
             TypeUtils.failUnsupportedDataType(create.tableSchema, SQLConf.get)
             SchemaUtils.checkIndeterminateCollationInSchema(create.tableSchema)
+            create match {
+              // The columns of CREATE TABLE AS SELECT come from its query, 
not from DDL.
+              case ctas: V2CreateTableAsSelectPlan =>
+                TypeUtils.checkNoUnknownFileTypeWrite(ctas.query.output)
+              case _ =>
+                TypeUtils.checkFileTypeHasQualifier(create.tableSchema)
+            }
+            // FILE has no defined ordering, so it cannot be a partition or 
clustering column.
+            create.partitioning.foreach { transform =>

Review Comment:
   **Low: after the rebase, FILE can be a write-ordering key.** SPARK-34586, 
now on master, adds `writeOrdering` to all four `V2CreateTablePlan` nodes and 
checks it only for unknown columns, but this loop checks only 
`create.partitioning`, so `ORDERED BY (f)`, `LOCALLY ORDERED BY (bucket(4, f))` 
or a struct key that contains a FILE will pass analysis in CREATE, CTAS, 
REPLACE and RTAS. On `testcat` and the other catalogs in this repository the 
statement then fails at planning with `UNSUPPORTED_FEATURE.TABLE_OPERATION` 
instead of a FILE error, and a catalog that advertises 
`SUPPORTS_CREATE_TABLE_WITH_WRITE_DISTRIBUTION_AND_ORDERING` would store a FILE 
sort key (V1 tables reject these clauses in `ResolveSessionCatalog`, and 
`DISTRIBUTED BY PARTITION` only distributes by partition columns, which this 
loop covers). Master leaves orderability to the catalog on purpose 
(`TableInfo.writeOrdering()`), but a catalog can't know that FILE has no 
ordering. Suggest checking the columns of `create.
 writeOrdering.flatMap(_.expression().references())` with 
`checkNoFileTypeInColumnUsage` after this loop, under a new 
`FILE_TYPE_UNSUPPORTED_COLUMN_USAGE.WRITE_ORDERING_COLUMN` subclass and with 
tests on `testcat` (analysis runs before the planner's capability check), or 
listing it with the follow-ups in the description.



##########
sql/core/src/test/scala/org/apache/spark/sql/FileTypeRestrictionsSuite.scala:
##########
@@ -0,0 +1,550 @@
+/*
+ * 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.spark.sql
+
+import org.apache.spark.SparkConf
+import org.apache.spark.api.python.{PythonBroadcast, PythonEvalType, 
SimplePythonFunction}
+import org.apache.spark.broadcast.Broadcast
+import org.apache.spark.sql.api.java.UDF1
+import org.apache.spark.sql.catalyst.TableIdentifier
+import org.apache.spark.sql.catalyst.catalog.{CatalogStorageFormat, 
CatalogTable, CatalogTableType}
+import org.apache.spark.sql.connector.catalog.InMemoryCatalog
+import org.apache.spark.sql.execution.python.{UserDefinedPythonFunction, 
UserDefinedPythonTableFunction}
+import org.apache.spark.sql.expressions.{MutableAggregationBuffer, 
UserDefinedAggregateFunction}
+import org.apache.spark.sql.functions.{col, udf}
+import org.apache.spark.sql.test.SharedSparkSession
+import org.apache.spark.sql.types.{DataType, FileType, IntegerType, MapType, 
StructType}
+
+/**
+ * Tests the rules on where the FILE type can be used: table columns must be 
FILE EXTERNAL,
+ * routines declare a plain FILE, and FILE has no defined ordering.
+ */
+class FileTypeRestrictionsSuite extends QueryTest with SharedSparkSession {
+
+  override protected def sparkConf: SparkConf =
+    super.sparkConf.set("spark.sql.catalog.testcat", 
classOf[InMemoryCatalog].getName)
+
+  // A FILE without a qualifier, at the top level and nested.
+  private val unqualifiedFileTypes = Seq(
+    "FILE",
+    "ARRAY<FILE>",
+    "MAP<STRING, FILE>",
+    "STRUCT<f1: FILE>",
+    "STRUCT<f1: INT, f2: STRUCT<f3: ARRAY<FILE>>>")
+
+  private val externalFile = "SELECT CAST(NULL AS FILE EXTERNAL) AS f"
+
+  test("a table column definition requires FILE EXTERNAL") {
+    Seq("testcat.t", "t").foreach { table =>
+      val provider = if (table.startsWith("testcat")) "" else "USING parquet"
+      unqualifiedFileTypes.foreach { dataType =>
+        withTable(table) {
+          checkError(
+            exception = intercept[AnalysisException] {
+              sql(s"CREATE TABLE $table (id INT, c $dataType) $provider")
+            },
+            condition = "FILE_TYPE_MISSING_QUALIFIER")
+        }
+      }
+    }
+    withTable("testcat.t") {
+      sql("CREATE TABLE testcat.t (id INT, c STRUCT<f1: ARRAY<FILE 
EXTERNAL>>)")
+    }
+  }
+
+  test("REPLACE TABLE requires FILE EXTERNAL") {
+    withTable("testcat.t") {
+      sql("CREATE TABLE testcat.t (id INT)")
+      checkError(
+        exception = intercept[AnalysisException] {
+          sql("REPLACE TABLE testcat.t (id INT, c FILE)")
+        },
+        condition = "FILE_TYPE_MISSING_QUALIFIER")
+    }
+  }
+
+  test("ALTER TABLE ADD COLUMNS and REPLACE COLUMNS require FILE EXTERNAL") {
+    withTable("testcat.t") {
+      sql("CREATE TABLE testcat.t (id INT)")
+      unqualifiedFileTypes.foreach { dataType =>
+        checkError(
+          exception = intercept[AnalysisException] {
+            sql(s"ALTER TABLE testcat.t ADD COLUMN c $dataType")
+          },
+          condition = "FILE_TYPE_MISSING_QUALIFIER")
+        checkError(
+          exception = intercept[AnalysisException] {
+            sql(s"ALTER TABLE testcat.t REPLACE COLUMNS (id INT, c $dataType)")
+          },
+          condition = "FILE_TYPE_MISSING_QUALIFIER")
+      }
+      sql("ALTER TABLE testcat.t ADD COLUMN c FILE EXTERNAL")
+    }
+  }
+
+  test("CREATE TABLE AS SELECT cannot store a FILE without a qualifier") {
+    Seq("testcat.t", "t").foreach { table =>
+      val provider = if (table.startsWith("testcat")) "" else "USING parquet"
+      withTable(table) {
+        checkError(
+          exception = intercept[AnalysisException] {
+            sql(s"CREATE TABLE $table $provider AS SELECT 1 AS id, CAST(NULL 
AS FILE) AS f")
+          },
+          condition = "FILE_TYPE_UNKNOWN_WRITE",
+          parameters = Map("colNames" -> "[`f`]"))
+      }
+    }
+  }
+
+  test("schema evolution cannot add a FILE without a qualifier") {
+    withTable("testcat.t") {
+      sql("CREATE TABLE testcat.t (id INT, s STRUCT<a: INT>)")
+      val schema = spark.table("testcat.t").schema
+      Seq(
+        "SELECT 1 AS id, named_struct('a', 1) AS s, CAST(NULL AS FILE) AS f" 
-> "[`f`]",
+        "SELECT 1 AS id, named_struct('a', 1, 'f', CAST(NULL AS FILE)) AS s" 
-> "[`s`.`f`]"
+      ).foreach { case (query, colNames) =>
+        checkError(
+          exception = intercept[AnalysisException] {
+            sql(s"INSERT WITH SCHEMA EVOLUTION INTO testcat.t $query")
+          },
+          condition = "FILE_TYPE_UNKNOWN_WRITE",
+          parameters = Map("colNames" -> colNames))
+        // The table is not changed.
+        assert(spark.table("testcat.t").schema === schema)
+      }
+      // A FILE EXTERNAL column can be added.
+      sql("INSERT WITH SCHEMA EVOLUTION INTO testcat.t " +
+        "SELECT 1 AS id, named_struct('a', 1) AS s, CAST(NULL AS FILE 
EXTERNAL) AS f")
+      assert(spark.table("testcat.t").schema === schema.add("f", 
FileType.external))
+    }
+  }
+
+  test("CREATE TABLE LIKE cannot copy a FILE without a qualifier from a view") 
{
+    withTempView("v") {
+      withView("pv") {
+        sql("CREATE TEMPORARY VIEW v AS SELECT 1 AS id, CAST(NULL AS FILE) AS 
f")
+        sql("CREATE VIEW pv AS SELECT 1 AS id, CAST(NULL AS FILE) AS f")
+        for (source <- Seq("v", "pv"); target <- Seq("t", "testcat.t")) {
+          withTable(target) {
+            checkError(
+              exception = intercept[AnalysisException] {
+                sql(s"CREATE TABLE $target LIKE $source")

Review Comment:
   **Low: these tests don't pin the move to analysis or the table-source 
branch.** `sql(...)` analyzes and then runs the command, so this test passes 
whether the check is in `CheckAnalysis` or back in `CreateTableLikeExec.run`, 
and every source is a view, so the new arm's `ResolvedTable` branch (the only 
one with its own schema conversion) and a V2 source copied to a session-catalog 
target never run. Suggest an analysis-only assertion such as 
`spark.sessionState.executePlan(spark.sessionState.sqlParser.parsePlan("CREATE 
TABLE testcat.t LIKE v")).assertAnalyzed()` expecting 
`FILE_TYPE_UNKNOWN_WRITE`, a `testcat.src` table holding a bare FILE created 
through the catalog API (as the `ALTER TABLE ... CLUSTER BY` test does for a 
session table) and copied to both `testcat.t` and `t`, and a positive control 
that copies a view holding `FILE EXTERNAL`.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/CheckAnalysis.scala:
##########
@@ -1044,6 +1086,20 @@ trait CheckAnalysis extends LookupCatalog with 
QueryErrorsBase with PlanToString
               }
             }
 
+          // A view can hold a FILE without a qualifier, which a table cannot 
store. A V1 target
+          // is checked by `CreateTableLikeCommand`, as the V1 command carries 
no resolved source.

Review Comment:
   **Low: this comment gets the V1 condition wrong.** `ResolveSessionCatalog` 
rewrites `CreateTableLike` into `CreateTableLikeCommand` only when both the 
target and the source are in the session catalog, so `CREATE TABLE t LIKE 
testcat.src` has a V1 target but is checked by this arm; the PR description 
uses the same "V1 target" wording. A correction to what I wrote in the previous 
round: the V1 check isn't limited to execution, because the rewrite in 
`ResolveSessionCatalog` still sees the resolved source, and that is where this 
PR already checks V1 `ALTER TABLE ... CLUSTER BY`. Suggest rewording to 
something like "When the target and source are both in the session catalog, 
`ResolveSessionCatalog` has already rewritten this into 
`CreateTableLikeCommand`, which checks the source when it runs"; moving the V1 
check into that rewrite, so both paths fail at analysis, is optional.



##########
sql/api/src/main/scala/org/apache/spark/sql/types/FileType.scala:
##########
@@ -25,30 +25,30 @@ import org.apache.spark.annotation.Unstable
 /**
  * The data type representing a reference to a file, with metadata describing 
the file.
  *
- * In SQL the type is named `FILE`, and the `EXTERNAL` keyword is planned to 
be required when
- * declaring a table column, as in `CREATE TABLE t (f FILE EXTERNAL)`; until 
then a bare `FILE` is
- * accepted wherever a type is. Its JSON representation is `"file external"` 
for
- * `FileType.external` and `"file unknown"` for `FileType()`, except that an 
external file in a
- * struct field is the plain `"file"`. A bare `"file"` is read as external 
inside a struct field
- * and as unknown elsewhere.
+ * In SQL the type is named `FILE`. A table column must be declared with the 
`EXTERNAL` keyword,
+ * as in `CREATE TABLE t (f FILE EXTERNAL)`, while the signature of a function 
declares a bare
+ * `FILE`. Its JSON representation is `"file external"` for 
`FileType.external` and
+ * `"file unknown"` for `FileType()`, except that an external file in a struct 
field is the plain
+ * `"file"`. A bare `"file"` is read as external inside a struct field and as 
unknown elsewhere.
  *
  * FileType is planned to be physically stored as a struct with the following 
fields (see
  * `FileType.FIELDS`), but it deliberately does not extend [[StructType]]:
- *   - uri (STRING): the opaque URI to the file
+ *   - uri (STRING): the URI of the referenced file, which may be absolute or 
relative
  *   - offset (BIGINT): the start of the referenced byte range
- *   - size (BIGINT): the size of the file in bytes
- *   - content_type (STRING): the MIME/content type of the file
- *   - checksum (STRING): an algorithm-tagged integrity token for the file, 
e.g. "ETAG:{etag}"
+ *   - size (BIGINT): the length of the referenced byte range
+ *   - content_type (STRING): the MIME/content type of the referenced bytes
+ *   - checksum (STRING): an algorithm-tagged integrity token for the 
referenced bytes, e.g.
+ *     "MD5:{digest}", or "ETAG:{etag}" for the whole file
  *   - inline (BINARY): the referenced bytes stored inline in the value
  *
  * FileType may be EXTERNAL (simple references, lifecycle independent of the 
table) or UNKNOWN
  * (mode not yet determined, such as the result of a cast or of a UDF). Mode 
is part of type
  * identity - files with different modes are distinct under `equals`.
  *
- * FileType is planned to be not comparable -- it cannot be used in join 
expressions, grouping
- * expressions, or as a partition/clustering column. Users can extract the uri 
field for such
- * operations. This type currently only guarantees the schema-level pieces 
(DDL and JSON); the
- * physical representation and most of the restrictions are added by later 
parts.
+ * FileType is not comparable -- it cannot be the key of a map built in a 
query or of a map in the
+ * return type of a function, and it cannot be used in join expressions, 
grouping expressions, set
+ * operations, or as a partition/clustering column. Users can extract the uri 
field for such

Review Comment:
   **Low: this list of where FILE can't be used is off.** "Set operations" is 
too broad, since `UNION ALL` is allowed, and the list leaves out sorting, 
hashing, repartition and `REBALANCE` keys and bucket columns, which the PR also 
rejects; after the rebase, write-ordering keys belong here too. Suggest stating 
the rule instead (an operation that compares, sorts, groups or hashes a FILE 
fails at analysis), followed by the DDL cases: partition, bucket, clustering 
and write-ordering columns.



##########
sql/core/src/test/scala/org/apache/spark/sql/FileTypeRestrictionsSuite.scala:
##########
@@ -0,0 +1,550 @@
+/*
+ * 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.spark.sql
+
+import org.apache.spark.SparkConf
+import org.apache.spark.api.python.{PythonBroadcast, PythonEvalType, 
SimplePythonFunction}
+import org.apache.spark.broadcast.Broadcast
+import org.apache.spark.sql.api.java.UDF1
+import org.apache.spark.sql.catalyst.TableIdentifier
+import org.apache.spark.sql.catalyst.catalog.{CatalogStorageFormat, 
CatalogTable, CatalogTableType}
+import org.apache.spark.sql.connector.catalog.InMemoryCatalog
+import org.apache.spark.sql.execution.python.{UserDefinedPythonFunction, 
UserDefinedPythonTableFunction}
+import org.apache.spark.sql.expressions.{MutableAggregationBuffer, 
UserDefinedAggregateFunction}
+import org.apache.spark.sql.functions.{col, udf}
+import org.apache.spark.sql.test.SharedSparkSession
+import org.apache.spark.sql.types.{DataType, FileType, IntegerType, MapType, 
StructType}
+
+/**
+ * Tests the rules on where the FILE type can be used: table columns must be 
FILE EXTERNAL,
+ * routines declare a plain FILE, and FILE has no defined ordering.
+ */
+class FileTypeRestrictionsSuite extends QueryTest with SharedSparkSession {
+
+  override protected def sparkConf: SparkConf =
+    super.sparkConf.set("spark.sql.catalog.testcat", 
classOf[InMemoryCatalog].getName)
+
+  // A FILE without a qualifier, at the top level and nested.
+  private val unqualifiedFileTypes = Seq(
+    "FILE",
+    "ARRAY<FILE>",
+    "MAP<STRING, FILE>",
+    "STRUCT<f1: FILE>",
+    "STRUCT<f1: INT, f2: STRUCT<f3: ARRAY<FILE>>>")
+
+  private val externalFile = "SELECT CAST(NULL AS FILE EXTERNAL) AS f"
+
+  test("a table column definition requires FILE EXTERNAL") {
+    Seq("testcat.t", "t").foreach { table =>
+      val provider = if (table.startsWith("testcat")) "" else "USING parquet"
+      unqualifiedFileTypes.foreach { dataType =>
+        withTable(table) {
+          checkError(
+            exception = intercept[AnalysisException] {
+              sql(s"CREATE TABLE $table (id INT, c $dataType) $provider")
+            },
+            condition = "FILE_TYPE_MISSING_QUALIFIER")
+        }
+      }
+    }
+    withTable("testcat.t") {
+      sql("CREATE TABLE testcat.t (id INT, c STRUCT<f1: ARRAY<FILE 
EXTERNAL>>)")
+    }
+  }
+
+  test("REPLACE TABLE requires FILE EXTERNAL") {
+    withTable("testcat.t") {
+      sql("CREATE TABLE testcat.t (id INT)")
+      checkError(
+        exception = intercept[AnalysisException] {
+          sql("REPLACE TABLE testcat.t (id INT, c FILE)")
+        },
+        condition = "FILE_TYPE_MISSING_QUALIFIER")
+    }
+  }
+
+  test("ALTER TABLE ADD COLUMNS and REPLACE COLUMNS require FILE EXTERNAL") {
+    withTable("testcat.t") {
+      sql("CREATE TABLE testcat.t (id INT)")
+      unqualifiedFileTypes.foreach { dataType =>
+        checkError(
+          exception = intercept[AnalysisException] {
+            sql(s"ALTER TABLE testcat.t ADD COLUMN c $dataType")
+          },
+          condition = "FILE_TYPE_MISSING_QUALIFIER")
+        checkError(
+          exception = intercept[AnalysisException] {
+            sql(s"ALTER TABLE testcat.t REPLACE COLUMNS (id INT, c $dataType)")
+          },
+          condition = "FILE_TYPE_MISSING_QUALIFIER")
+      }
+      sql("ALTER TABLE testcat.t ADD COLUMN c FILE EXTERNAL")
+    }
+  }
+
+  test("CREATE TABLE AS SELECT cannot store a FILE without a qualifier") {
+    Seq("testcat.t", "t").foreach { table =>
+      val provider = if (table.startsWith("testcat")) "" else "USING parquet"
+      withTable(table) {
+        checkError(
+          exception = intercept[AnalysisException] {
+            sql(s"CREATE TABLE $table $provider AS SELECT 1 AS id, CAST(NULL 
AS FILE) AS f")
+          },
+          condition = "FILE_TYPE_UNKNOWN_WRITE",
+          parameters = Map("colNames" -> "[`f`]"))
+      }
+    }
+  }
+
+  test("schema evolution cannot add a FILE without a qualifier") {
+    withTable("testcat.t") {
+      sql("CREATE TABLE testcat.t (id INT, s STRUCT<a: INT>)")
+      val schema = spark.table("testcat.t").schema
+      Seq(
+        "SELECT 1 AS id, named_struct('a', 1) AS s, CAST(NULL AS FILE) AS f" 
-> "[`f`]",
+        "SELECT 1 AS id, named_struct('a', 1, 'f', CAST(NULL AS FILE)) AS s" 
-> "[`s`.`f`]"
+      ).foreach { case (query, colNames) =>
+        checkError(
+          exception = intercept[AnalysisException] {
+            sql(s"INSERT WITH SCHEMA EVOLUTION INTO testcat.t $query")
+          },
+          condition = "FILE_TYPE_UNKNOWN_WRITE",
+          parameters = Map("colNames" -> colNames))
+        // The table is not changed.
+        assert(spark.table("testcat.t").schema === schema)
+      }
+      // A FILE EXTERNAL column can be added.
+      sql("INSERT WITH SCHEMA EVOLUTION INTO testcat.t " +
+        "SELECT 1 AS id, named_struct('a', 1) AS s, CAST(NULL AS FILE 
EXTERNAL) AS f")
+      assert(spark.table("testcat.t").schema === schema.add("f", 
FileType.external))
+    }
+  }
+
+  test("CREATE TABLE LIKE cannot copy a FILE without a qualifier from a view") 
{
+    withTempView("v") {
+      withView("pv") {
+        sql("CREATE TEMPORARY VIEW v AS SELECT 1 AS id, CAST(NULL AS FILE) AS 
f")
+        sql("CREATE VIEW pv AS SELECT 1 AS id, CAST(NULL AS FILE) AS f")
+        for (source <- Seq("v", "pv"); target <- Seq("t", "testcat.t")) {
+          withTable(target) {
+            checkError(
+              exception = intercept[AnalysisException] {
+                sql(s"CREATE TABLE $target LIKE $source")
+              },
+              condition = "FILE_TYPE_UNKNOWN_WRITE",
+              parameters = Map("colNames" -> "[`f`]"))
+            assert(!spark.catalog.tableExists(target))
+            // As for CREATE TABLE AS SELECT, IF NOT EXISTS does not skip the 
check when the
+            // table exists.

Review Comment:
   **Nit: test wording.** "As for CREATE TABLE AS SELECT" reads as a statement 
about CTAS; "As with" says what is meant, and no CTAS `IF NOT EXISTS` test 
backs the comparison yet. Two more in this file: the test name "a column cannot 
be altered to or from a FILE" (L215) over-claims, since a `VOID` column can 
become `FILE EXTERNAL`, and "Neither registration nor analysis runs Python" 
(L488) holds for that test but not in general, since analyzing a call to a UDTF 
with an `analyze` method does run Python. Suggest rewording all three and 
adding the CTAS `IF NOT EXISTS` case.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/CheckAnalysis.scala:
##########
@@ -29,7 +29,8 @@ import org.apache.spark.sql.catalyst.optimizer.InlineCTE
 import org.apache.spark.sql.catalyst.plans.logical._
 import 
org.apache.spark.sql.catalyst.trees.TreePattern.{LATERAL_COLUMN_ALIAS_REFERENCE,
 PLAN_EXPRESSION, UNRESOLVED_WINDOW_EXPRESSION}
 import org.apache.spark.sql.catalyst.util.{CharVarcharUtils, StringUtils, 
TypeUtils}
-import org.apache.spark.sql.connector.catalog.{CatalogManager, LookupCatalog, 
SupportsPartitionManagement}
+import org.apache.spark.sql.connector.catalog.{CatalogManager, CatalogV2Util, 
LookupCatalog, SupportsPartitionManagement}

Review Comment:
   **Nit: this import can go, which also removes a rebase conflict.** 
`CatalogV2Implicits._` is already imported, so the new `CreateTableLike` arm 
can use `table.columns.asSchema` instead of 
`CatalogV2Util.v2ColumnsToStructType(table.columns())`. This line sits next to 
master's SPARK-34586 import change, which is what makes this file conflict; 
with it reverted, a trial three-way merge of `CheckAnalysis.scala` with master 
is clean, leaving only the one-line import conflict in 
`ResolveSessionCatalog.scala`.



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

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to