peter-toth commented on code in PR #58153:
URL: https://github.com/apache/spark/pull/58153#discussion_r3824585772


##########
sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/v2/ShowCreateTableExec.scala:
##########
@@ -125,6 +126,45 @@ case class ShowCreateTableExec(
     }
   }
 
+  /**
+   * Emits the write distribution and ordering the table declares as the 
default for writes into it,
+   * so that a table created with those clauses can be recreated from this 
statement.
+   *
+   * The pair a connector may report is wider than the syntax can spell: 
`hash` on a table with no
+   * partitioning (the parser rejects `DISTRIBUTED BY PARTITION` there), a 
`range` distribution with
+   * no ordering, an ordering with no distribution, and a mode this Spark 
version does not know.
+   * Those are left out rather than guessed at, since emitting a clause that 
means something else --
+   * or one that does not parse at all -- would be worse than emitting none. 
DESCRIBE TABLE EXTENDED
+   * reports both values verbatim regardless.
+   */
+  private def showTableWriteDistributionAndOrdering(
+      table: Table,
+      builder: StringBuilder): Unit = {
+    val orderBy = if (table.writeOrdering().nonEmpty) {
+      Some(table.writeOrdering()
+        .map(WriteDistributionAndOrdering.describeSortOrder)
+        .mkString("ORDERED BY (", ", ", ")"))

Review Comment:
   **Finding 2.** The `hasPartitioning` guard below covers the distribution 
side of this method's own doc - "emitting a clause that means something else -- 
or one that does not parse at all -- would be worse than emitting none" - but 
nothing checks that the sort expressions are spellable. 
`SortOrder.expression()` is typed `Expression` and `Table.writeOrdering()`'s 
new contract does not narrow it, so a connector may report an expression the 
`writeOrderField : transform ...` rule cannot represent.
   
   Measured on this branch, with a table reporting mode `range` and `sort(a + 
1, ASCENDING, NULLS_FIRST)`:
   
       CREATE TABLE p.t (
         id INT)
       USING foo
       ORDERED BY (id + 1 ASC NULLS FIRST)
   
   Replaying that gives `[PARSE_SYNTAX_ERROR] Syntax error at or near '+'` at 
line 4, pos 15. The whole statement is unrunnable, not one clause lost, which 
is the worse failure the doc calls out.
   
   Same fix shape as the `hash` case: drop the pair when it cannot be spelled. 
Two things to get right. `CreateTableWriteOrderSuite` builds a bare 
`FieldReference`, not a `Transform`, and that one does round-trip, so the 
predicate has to admit it. And nulling out `orderBy` alone is not enough - 
`(none, None)` would then emit `UNORDERED`, declaring no ordering on a table 
that has one - so the whole method has to bail:
   
   ```scala
     private def isSpellable(e: V2Expression): Boolean = e match {
       case _: NamedReference => true
       // Mirrors `transformArgument : qualifiedName | constant`.
       case t: Transform =>
         t.arguments().forall(a => a.isInstanceOf[NamedReference] || 
a.isInstanceOf[Literal[_]])
       case _ => false
     }
   ```
   
   then wrap the existing body in `if (table.writeOrdering().forall(o => 
isSpellable(o.expression()))) { ... }`. `DESCRIBE TABLE EXTENDED` still reports 
both values verbatim, so nothing is hidden.
   



##########
docs/sql-ref-syntax-ddl-create-table-datasource.md:
##########
@@ -98,6 +106,60 @@ as any order. For example, you can write COMMENT 
table_comment after TBLPROPERTI
 
     A list of key-value pairs that is used to tag the table definition.
 
+* **DISTRIBUTED BY PARTITION**
+
+    Requests that every write to the table be clustered by the table's 
partitioning, so each
+    partition is written by a single task rather than by every task that holds 
rows for it.
+
+    Requires the table to actually be partitioned, with `PARTITIONED BY` or 
with
+    `CLUSTERED BY ... INTO ... BUCKETS`. Note that `CLUSTER BY` -- a different 
clause from
+    `CLUSTERED BY ... INTO ... BUCKETS` -- does **not** qualify: it lists 
clustering columns for the
+    data source to interpret rather than defining a partitioning, and it 
cannot be combined with
+    `PARTITIONED BY` or `CLUSTERED BY ... INTO ... BUCKETS`, so a table using 
it has no partitioning
+    to distribute by.
+
+* **ORDERED BY**
+
+    Requests a sort order for every write to the table, recorded on the table 
so that later writes
+    honor it too. `UNORDERED` asks for no ordering at all, which is different 
from omitting the
+    clause -- omitting it leaves the choice to the data source. The 
parentheses are optional:
+    `ORDERED BY (a, b)` and `ORDERED BY a, b` are the same. The sort keys must 
resolve against the
+    table's columns, so a `CREATE TABLE` with neither a column list nor `AS 
SELECT` cannot use this
+    clause.
+
+    The distribution decides how far the order reaches, and this clause picks 
one when
+    `DISTRIBUTED BY PARTITION` is absent: a bare `ORDERED BY` range-partitions 
each write, so the
+    order holds across the whole table, while `LOCALLY ORDERED BY` asks for it 
to hold within each
+    written file only, without a shuffle. `UNORDERED` on its own asks for no 
distribution either.
+
+    When `DISTRIBUTED BY PARTITION` is given it decides the distribution 
instead, and the order then
+    holds within each write task. `LOCALLY` therefore adds nothing beside it, 
and `UNORDERED` beside
+    it contributes only "no sort keys":
+
+    ```sql
+    -- range-partition each write by id, so the order holds across the whole 
table
+    CREATE TABLE t (id INT, c STRING) USING iceberg PARTITIONED BY (c) ORDERED 
BY (id);
+
+    -- cluster each write by partition instead, and sort by id within each task
+    CREATE TABLE t (id INT, c STRING) USING iceberg PARTITIONED BY (c)
+        DISTRIBUTED BY PARTITION ORDERED BY (id);
+
+    -- cluster each write by partition, with no sort order; UNORDERED here is 
the same as
+    -- omitting it, since DISTRIBUTED BY PARTITION already fixed the 
distribution
+    CREATE TABLE t (id INT, c STRING) USING iceberg PARTITIONED BY (c)
+        DISTRIBUTED BY PARTITION UNORDERED;
+    ```
+
+    Both clauses are passed to the data source, which has to support them: a 
data source that does

Review Comment:
   **Finding 4.** The advertiser is the catalog, not the data source. What 
gates this is `TableCatalog.capabilities()` returning 
`TableCatalogCapability.SUPPORTS_CREATE_TABLE_WITH_WRITE_DISTRIBUTION_AND_ORDERING`,
 checked in 
`WriteDistributionAndOrdering.validateCatalogForWriteDistributionAndOrdering`. 
A user who hits `UNSUPPORTED_FEATURE.TABLE_OPERATION` and follows this 
paragraph will inspect the `USING` provider, where there is nothing to inspect.
   
   It also makes the last sentence hard to act on. "The built-in data sources 
do not support them" is true, but the reason is that `V2SessionCatalog` does 
not advertise the capability and the v1 conversion in `ResolveSessionCatalog` 
rejects the request outright - nothing to do with parquet or ORC.
   
   Suggest saying catalog throughout: "Both clauses are passed to the catalog, 
which has to support them: a catalog that does not advertise support ... The 
built-in catalogs do not."
   



##########
docs/sql-ref-syntax-ddl-create-table-datasource.md:
##########
@@ -98,6 +106,60 @@ as any order. For example, you can write COMMENT 
table_comment after TBLPROPERTI
 
     A list of key-value pairs that is used to tag the table definition.
 
+* **DISTRIBUTED BY PARTITION**
+
+    Requests that every write to the table be clustered by the table's 
partitioning, so each
+    partition is written by a single task rather than by every task that holds 
rows for it.
+
+    Requires the table to actually be partitioned, with `PARTITIONED BY` or 
with
+    `CLUSTERED BY ... INTO ... BUCKETS`. Note that `CLUSTER BY` -- a different 
clause from
+    `CLUSTERED BY ... INTO ... BUCKETS` -- does **not** qualify: it lists 
clustering columns for the
+    data source to interpret rather than defining a partitioning, and it 
cannot be combined with
+    `PARTITIONED BY` or `CLUSTERED BY ... INTO ... BUCKETS`, so a table using 
it has no partitioning
+    to distribute by.
+
+* **ORDERED BY**
+
+    Requests a sort order for every write to the table, recorded on the table 
so that later writes
+    honor it too. `UNORDERED` asks for no ordering at all, which is different 
from omitting the
+    clause -- omitting it leaves the choice to the data source. The 
parentheses are optional:
+    `ORDERED BY (a, b)` and `ORDERED BY a, b` are the same. The sort keys must 
resolve against the
+    table's columns, so a `CREATE TABLE` with neither a column list nor `AS 
SELECT` cannot use this
+    clause.
+
+    The distribution decides how far the order reaches, and this clause picks 
one when
+    `DISTRIBUTED BY PARTITION` is absent: a bare `ORDERED BY` range-partitions 
each write, so the
+    order holds across the whole table, while `LOCALLY ORDERED BY` asks for it 
to hold within each
+    written file only, without a shuffle. `UNORDERED` on its own asks for no 
distribution either.

Review Comment:
   **Finding 6.** "within each written file only" here, "within each write 
task" three lines down at :136. A task can roll over several files, so these 
are different claims, and the second is the accurate one - it also matches 
`TableInfo.DISTRIBUTION_MODE_NONE`'s javadoc ("any ordering holds within a 
write task only"). `DISTRIBUTION_MODE_RANGE`'s javadoc has the same drift the 
other way ("across files, not only within one").
   



##########
common/utils/src/main/resources/error/error-conditions.json:
##########
@@ -9137,6 +9151,11 @@
         "message" : [
           "Write for the binary file data source."
         ]
+      },
+      "WRITE_ORDERING_WITH_NESTED_COLUMN_IS_UNSUPPORTED" : {

Review Comment:
   **Finding 3.** Both the name and the message describe cases this condition 
cannot report.
   
   A nested *struct* column is supported, and the suite asserts it - `CREATE 
TABLE testcat.t (p STRUCT<x: INT>) USING foo ORDERED BY p.x` is accepted. So 
`WITH_NESTED_COLUMN_IS_UNSUPPORTED` says the opposite of the tested behaviour.
   
   "or is in a map or array" is unreachable. `StructType.findNestedField` is 
called with the default `includeCollections = false`, which *throws* 
`INVALID_FIELD_NAME` on a path through a non-struct rather than returning 
`None`. Measured on this branch:
   
       ORDERED BY (m.key) on MAP<STRING, INT>
         -> [INVALID_FIELD_NAME] Field name `m`.`key` is invalid: `m` is not a 
struct
   
       ORDERED BY (a.element.x) on ARRAY<STRUCT<x: INT>>
         -> [INVALID_FIELD_NAME] Field name `a`.`element`.`x` is invalid: `a` 
is not a struct
   
       ORDERED BY (truncate(4, m.key)) on MAP<STRING, INT>
         -> [INVALID_FIELD_NAME] Field name `m`.`key` is invalid: `m` is not a 
struct
   
   The third one is raised from the `CheckAnalysis` check itself: 
`truncate(...)` is an `ApplyTransform`, so it is not rewritable and never 
reaches `PreprocessTableCreation`.
   
   What this condition actually reports is a reference that is not a column of 
the table. I know it is a faithful copy of 
`PARTITION_WITH_NESTED_COLUMN_IS_UNSUPPORTED`, where both faults are equally 
present, and consistency with the sibling is a real argument - it just does not 
carry to a name being introduced now. The sibling can be left alone; this one 
cannot be renamed after a release. Suggest 
`UNSUPPORTED_FEATURE.WRITE_ORDERING_WITH_UNKNOWN_COLUMN` with `"Invalid write 
ordering: <cols> is not a column of the table."`, or a 
non-`UNSUPPORTED_FEATURE` parent, since a missing column is not a feature gap.
   



##########
docs/sql-ref-syntax-ddl-create-table-datasource.md:
##########
@@ -98,6 +106,60 @@ as any order. For example, you can write COMMENT 
table_comment after TBLPROPERTI
 
     A list of key-value pairs that is used to tag the table definition.
 
+* **DISTRIBUTED BY PARTITION**
+
+    Requests that every write to the table be clustered by the table's 
partitioning, so each
+    partition is written by a single task rather than by every task that holds 
rows for it.
+
+    Requires the table to actually be partitioned, with `PARTITIONED BY` or 
with
+    `CLUSTERED BY ... INTO ... BUCKETS`. Note that `CLUSTER BY` -- a different 
clause from
+    `CLUSTERED BY ... INTO ... BUCKETS` -- does **not** qualify: it lists 
clustering columns for the
+    data source to interpret rather than defining a partitioning, and it 
cannot be combined with
+    `PARTITIONED BY` or `CLUSTERED BY ... INTO ... BUCKETS`, so a table using 
it has no partitioning
+    to distribute by.
+
+* **ORDERED BY**
+
+    Requests a sort order for every write to the table, recorded on the table 
so that later writes
+    honor it too. `UNORDERED` asks for no ordering at all, which is different 
from omitting the
+    clause -- omitting it leaves the choice to the data source. The 
parentheses are optional:
+    `ORDERED BY (a, b)` and `ORDERED BY a, b` are the same. The sort keys must 
resolve against the
+    table's columns, so a `CREATE TABLE` with neither a column list nor `AS 
SELECT` cannot use this
+    clause.
+
+    The distribution decides how far the order reaches, and this clause picks 
one when
+    `DISTRIBUTED BY PARTITION` is absent: a bare `ORDERED BY` range-partitions 
each write, so the
+    order holds across the whole table, while `LOCALLY ORDERED BY` asks for it 
to hold within each
+    written file only, without a shuffle. `UNORDERED` on its own asks for no 
distribution either.
+
+    When `DISTRIBUTED BY PARTITION` is given it decides the distribution 
instead, and the order then
+    holds within each write task. `LOCALLY` therefore adds nothing beside it, 
and `UNORDERED` beside
+    it contributes only "no sort keys":
+
+    ```sql
+    -- range-partition each write by id, so the order holds across the whole 
table
+    CREATE TABLE t (id INT, c STRING) USING iceberg PARTITIONED BY (c) ORDERED 
BY (id);
+
+    -- cluster each write by partition instead, and sort by id within each task
+    CREATE TABLE t (id INT, c STRING) USING iceberg PARTITIONED BY (c)
+        DISTRIBUTED BY PARTITION ORDERED BY (id);
+
+    -- cluster each write by partition, with no sort order; UNORDERED here is 
the same as
+    -- omitting it, since DISTRIBUTED BY PARTITION already fixed the 
distribution
+    CREATE TABLE t (id INT, c STRING) USING iceberg PARTITIONED BY (c)
+        DISTRIBUTED BY PARTITION UNORDERED;
+    ```
+
+    Both clauses are passed to the data source, which has to support them: a 
data source that does
+    not advertise support for a write distribution and ordering rejects the 
statement rather than
+    creating a table that silently lacks the requested layout. The built-in 
data sources do not
+    support them.
+
+    What the data source records is a *default* for later writes, not a 
statement about the data
+    already in the table: an individual write may override it, and rewriting 
existing data to match
+    a newly requested layout is a separate operation. `SHOW CREATE TABLE` 
reproduces the clauses and

Review Comment:
   **Finding 5.** `SHOW CREATE TABLE` reproduces the clauses only for pairs the 
syntax can spell, and emits nothing at all for the rest. That caveat is in the 
PR description and in `ShowCreateTableExec`'s scaladoc, but not here, and this 
page is what users read.
   
   It is not a corner case. A connector that records a sort order without 
touching its distribution mode reports `(null, non-empty)`, which has no clause 
form. Measured on this branch, with a table reporting mode `null` and ordering 
`id DESC NULLS LAST`:
   
       CREATE TABLE n.t (
         id INT)
       USING foo
   
   while `DESCRIBE TABLE EXTENDED` on the same table shows `Ordering` = `id 
DESC NULLS LAST`. So that DDL runs and creates a table without the ordering.
   
   One sentence covers it: `SHOW CREATE TABLE` reproduces the clauses when the 
recorded pair has a clause form, and `DESCRIBE TABLE EXTENDED` reports both 
values in every case.
   



##########
sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/ThriftServerWithSparkContextSuite.scala:
##########
@@ -214,7 +214,7 @@ trait ThriftServerWithSparkContextSuite extends 
SharedThriftServer {
       val sessionHandle = client.openSession(user, "")
       val infoValue = client.getInfo(sessionHandle, 
GetInfoType.CLI_ODBC_KEYWORDS)
       // scalastyle:off line.size.limit
-      assert(infoValue.getStringValue == 
"ADD,AFTER,AGGREGATE,ALIGN,ALL,ALTER,ALWAYS,ANALYZE,AND,ANTI,ANY,ANY_VALUE,APPLY,APPROX,ARCHIVE,ARRAY,AS,ASC,ASENSITIVE,ASOF,AT,ATOMIC,AUTHORIZATION,AUTO,BEGIN,BERNOULLI,BETWEEN,BIGINT,BIN,BINARY,BINDING,BIN_DISTRIBUTE_RATIO,BIN_END,BIN_START,BOOLEAN,BOTH,BUCKET,BUCKETS,BY,BYTE,CACHE,CALL,CALLED,CASCADE,CASE,CAST,CATALOG,CATALOGS,CDC,CHANGE,CHANGES,CHAR,CHARACTER,CHECK,CLEAR,CLOSE,CLUSTER,CLUSTERED,CODEGEN,COLLATE,COLLATION,COLLATIONS,COLLECTION,COLUMN,COLUMNS,COMMENT,COMMIT,COMPACT,COMPACTIONS,COMPENSATION,COMPUTE,CONCATENATE,CONDITION,CONSTRAINT,CONTAINS,CONTINUE,COST,CREATE,CROSS,CUBE,CURRENT,CURRENT_DATABASE,CURRENT_DATE,CURRENT_PATH,CURRENT_SCHEMA,CURRENT_TIME,CURRENT_TIMESTAMP,CURRENT_USER,CURSOR,DATA,DATABASE,DATABASES,DATE,DATEADD,DATEDIFF,DATE_ADD,DATE_DIFF,DAY,DAYOFYEAR,DAYS,DBPROPERTIES,DEC,DECIMAL,DECLARE,DEFAULT,DEFAULT_PATH,DEFINED,DEFINER,DELAY,DELETE,DELIMITED,DESC,DESCRIBE,DETERMINISTIC,DFS,DIRECTORIES,DIRECTORY,DISTANCE,DIST
 
INCT,DISTRIBUTE,DIV,DO,DOUBLE,DROP,ELSE,ELSEIF,EMPTY,END,ENFORCED,ERROR,ESCAPE,ESCAPED,EVOLUTION,EXACT,EXCEPT,EXCHANGE,EXCLUDE,EXCLUSIVE,EXECUTE,EXISTS,EXIT,EXPLAIN,EXPORT,EXTEND,EXTENDED,EXTERNAL,EXTRACT,FALSE,FETCH,FIELDS,FILEFORMAT,FILTER,FIRST,FLOAT,FLOW,FOLLOWING,FOR,FOREIGN,FORMAT,FORMATTED,FOUND,FROM,FULL,FUNCTION,FUNCTIONS,GENERATED,GEOGRAPHY,GEOMETRY,GLOBAL,GRANT,GROUP,GROUPING,HANDLER,HAVING,HISTORY,HOUR,HOURS,IDENTIFIED,IDENTIFIER,IDENTITY,IF,IGNORE,ILIKE,IMMEDIATE,IMPORT,IN,INCLUDE,INCLUSIVE,INCREMENT,INDEX,INDEXES,INNER,INPATH,INPUT,INPUTFORMAT,INSENSITIVE,INSERT,INT,INTEGER,INTERSECT,INTERVAL,INTO,INVOKER,IS,ITEMS,ITERATE,JOIN,JSON,JSON_EXISTS,JSON_TABLE,JSON_VALUE,KEY,KEYS,LANGUAGE,LAST,LATERAL,LAZY,LEADING,LEAVE,LEFT,LEVEL,LIKE,LIMIT,LINES,LIST,LOAD,LOCAL,LOCALTIME,LOCATION,LOCK,LOCKS,LOGICAL,LONG,LOOP,MACRO,MAP,MATCHED,MATCH_CONDITION,MATERIALIZED,MAX,MEASURE,MERGE,METRICS,MICROSECOND,MICROSECONDS,MILLISECOND,MILLISECONDS,MINUS,MINUTE,MINUTES,MODIFIES,MONTH,MONTHS,M
 
SCK,NAME,NAMESPACE,NAMESPACES,NANOSECOND,NANOSECONDS,NATURAL,NEAREST,NEXT,NO,NONE,NORELY,NOT,NULL,NULLS,NUMERIC,OF,OFFSET,ON,ONLY,OPEN,OPTION,OPTIONS,OR,ORDER,ORDINALITY,OUT,OUTER,OUTPUTFORMAT,OVER,OVERLAPS,OVERLAY,OVERWRITE,PARTITION,PARTITIONED,PARTITIONS,PATH,PERCENT,PIVOT,PLACING,POSITION,PRECEDING,PRIMARY,PRINCIPALS,PROCEDURE,PROCEDURES,PROPERTIES,PURGE,QUALIFY,QUARTER,QUERY,RANGE,READ,READS,REAL,RECORDREADER,RECORDWRITER,RECOVER,RECURSION,RECURSIVE,REDUCE,REFERENCES,REFRESH,RELY,RENAME,REPAIR,REPEAT,REPEATABLE,REPLACE,RESET,RESPECT,RESTRICT,RETURN,RETURNING,RETURNS,REVOKE,RIGHT,ROLE,ROLES,ROLLBACK,ROLLUP,ROW,ROWS,SCD,SCHEMA,SCHEMAS,SECOND,SECONDS,SECURITY,SELECT,SEMI,SEPARATED,SEQUENCE,SERDE,SERDEPROPERTIES,SESSION_USER,SET,SETS,SHORT,SHOW,SIMILARITY,SINGLE,SKEWED,SMALLINT,SOME,SORT,SORTED,SOURCE,SPECIFIC,SQL,SQLEXCEPTION,SQLSTATE,START,STATISTICS,STORED,STRATIFY,STREAM,STREAMING,STRING,STRUCT,SUBSTR,SUBSTRING,SYNC,SYSTEM,SYSTEM_PATH,SYSTEM_TIME,SYSTEM_VERSION,TABLE,TABLES,TAB
 
LESAMPLE,TARGET,TBLPROPERTIES,TERMINATED,THEN,TIME,TIMEDIFF,TIMESTAMP,TIMESTAMPADD,TIMESTAMPDIFF,TIMESTAMP_LTZ,TIMESTAMP_NTZ,TINYINT,TO,TOUCH,TRACK,TRAILING,TRANSACTION,TRANSACTIONS,TRANSFORM,TRIM,TRUE,TRUNCATE,TRY_CAST,TYPE,UNARCHIVE,UNBOUNDED,UNCACHE,UNIFORM,UNION,UNIQUE,UNKNOWN,UNLOCK,UNNEST,UNPIVOT,UNSET,UNTIL,UPDATE,USE,USER,USING,VALUE,VALUES,VAR,VARCHAR,VARIABLE,VARIANT,VERSION,VIEW,VIEWS,VOID,WATERMARK,WEEK,WEEKS,WHEN,WHERE,WHILE,WIDTH,WINDOW,WITH,WITHIN,WITHOUT,X,YEAR,YEARS,ZONE")
+      assert(infoValue.getStringValue == 
"ADD,AFTER,AGGREGATE,ALIGN,ALL,ALTER,ALWAYS,ANALYZE,AND,ANTI,ANY,ANY_VALUE,APPLY,APPROX,ARCHIVE,ARRAY,AS,ASC,ASENSITIVE,ASOF,AT,ATOMIC,AUTHORIZATION,AUTO,BEGIN,BERNOULLI,BETWEEN,BIGINT,BIN,BINARY,BINDING,BIN_DISTRIBUTE_RATIO,BIN_END,BIN_START,BOOLEAN,BOTH,BUCKET,BUCKETS,BY,BYTE,CACHE,CALL,CALLED,CASCADE,CASE,CAST,CATALOG,CATALOGS,CDC,CHANGE,CHANGES,CHAR,CHARACTER,CHECK,CLEAR,CLOSE,CLUSTER,CLUSTERED,CODEGEN,COLLATE,COLLATION,COLLATIONS,COLLECTION,COLUMN,COLUMNS,COMMENT,COMMIT,COMPACT,COMPACTIONS,COMPENSATION,COMPUTE,CONCATENATE,CONDITION,CONSTRAINT,CONTAINS,CONTINUE,COST,CREATE,CROSS,CUBE,CURRENT,CURRENT_DATABASE,CURRENT_DATE,CURRENT_PATH,CURRENT_SCHEMA,CURRENT_TIME,CURRENT_TIMESTAMP,CURRENT_USER,CURSOR,DATA,DATABASE,DATABASES,DATE,DATEADD,DATEDIFF,DATE_ADD,DATE_DIFF,DAY,DAYOFYEAR,DAYS,DBPROPERTIES,DEC,DECIMAL,DECLARE,DEFAULT,DEFAULT_PATH,DEFINED,DEFINER,DELAY,DELETE,DELIMITED,DESC,DESCRIBE,DETERMINISTIC,DFS,DIRECTORIES,DIRECTORY,DISTANCE,DIST
 
INCT,DISTRIBUTE,DISTRIBUTED,DIV,DO,DOUBLE,DROP,ELSE,ELSEIF,EMPTY,END,ENFORCED,ERROR,ESCAPE,ESCAPED,EVOLUTION,EXACT,EXCEPT,EXCHANGE,EXCLUDE,EXCLUSIVE,EXECUTE,EXISTS,EXIT,EXPLAIN,EXPORT,EXTEND,EXTENDED,EXTERNAL,EXTRACT,FALSE,FETCH,FIELDS,FILEFORMAT,FILTER,FIRST,FLOAT,FLOW,FOLLOWING,FOR,FOREIGN,FORMAT,FORMATTED,FOUND,FROM,FULL,FUNCTION,FUNCTIONS,GENERATED,GEOGRAPHY,GEOMETRY,GLOBAL,GRANT,GROUP,GROUPING,HANDLER,HAVING,HISTORY,HOUR,HOURS,IDENTIFIED,IDENTIFIER,IDENTITY,IF,IGNORE,ILIKE,IMMEDIATE,IMPORT,IN,INCLUDE,INCLUSIVE,INCREMENT,INDEX,INDEXES,INNER,INPATH,INPUT,INPUTFORMAT,INSENSITIVE,INSERT,INT,INTEGER,INTERSECT,INTERVAL,INTO,INVOKER,IS,ITEMS,ITERATE,JOIN,JSON,JSON_EXISTS,JSON_TABLE,JSON_VALUE,KEY,KEYS,LANGUAGE,LAST,LATERAL,LAZY,LEADING,LEAVE,LEFT,LEVEL,LIKE,LIMIT,LINES,LIST,LOAD,LOCAL,LOCALLY,LOCALTIME,LOCATION,LOCK,LOCKS,LOGICAL,LONG,LOOP,MACRO,MAP,MATCHED,MATCH_CONDITION,MATERIALIZED,MAX,MEASURE,MERGE,METRICS,MICROSECOND,MICROSECONDS,MILLISECOND,MILLISECONDS,MINUS,MINUTE,MINUTES,MOD
 
IFIES,MONTH,MONTHS,MSCK,NAME,NAMESPACE,NAMESPACES,NANOSECOND,NANOSECONDS,NATURAL,NEAREST,NEXT,NO,NONE,NORELY,NOT,NULL,NULLS,NUMERIC,OF,OFFSET,ON,ONLY,OPEN,OPTION,OPTIONS,OR,ORDER,ORDERED,ORDINALITY,OUT,OUTER,OUTPUTFORMAT,OVER,OVERLAPS,OVERLAY,OVERWRITE,PARTITION,PARTITIONED,PARTITIONS,PATH,PERCENT,PIVOT,PLACING,POSITION,PRECEDING,PRIMARY,PRINCIPALS,PROCEDURE,PROCEDURES,PROPERTIES,PURGE,QUALIFY,QUARTER,QUERY,RANGE,READ,READS,REAL,RECORDREADER,RECORDWRITER,RECOVER,RECURSION,RECURSIVE,REDUCE,REFERENCES,REFRESH,RELY,RENAME,REPAIR,REPEAT,REPEATABLE,REPLACE,RESET,RESPECT,RESTRICT,RETURN,RETURNING,RETURNS,REVOKE,RIGHT,ROLE,ROLES,ROLLBACK,ROLLUP,ROW,ROWS,SCD,SCHEMA,SCHEMAS,SECOND,SECONDS,SECURITY,SELECT,SEMI,SEPARATED,SEQUENCE,SERDE,SERDEPROPERTIES,SESSION_USER,SET,SETS,SHORT,SHOW,SIMILARITY,SINGLE,SKEWED,SMALLINT,SOME,SORT,SORTED,SOURCE,SPECIFIC,SQL,SQLEXCEPTION,SQLSTATE,START,STATISTICS,STORED,STRATIFY,STREAM,STREAMING,STRING,STRUCT,SUBSTR,SUBSTRING,SYNC,SYSTEM,SYSTEM_PATH,SYSTEM_TIME,SYS
 
TEM_VERSION,TABLE,TABLES,TABLESAMPLE,TARGET,TBLPROPERTIES,TERMINATED,THEN,TIME,TIMEDIFF,TIMESTAMP,TIMESTAMPADD,TIMESTAMPDIFF,TIMESTAMP_LTZ,TIMESTAMP_NTZ,TINYINT,TO,TOUCH,TRACK,TRAILING,TRANSACTION,TRANSACTIONS,TRANSFORM,TRIM,TRUE,TRUNCATE,TRY_CAST,TYPE,UNARCHIVE,UNBOUNDED,UNCACHE,UNIFORM,UNION,UNIQUE,UNKNOWN,UNLOCK,UNNEST,UNORDERED,UNPIVOT,UNSET,UNTIL,UPDATE,USE,USER,USING,VALUE,VALUES,VAR,VARCHAR,VARIABLE,VARIANT,VERSION,VIEW,VIEWS,VOID,WATERMARK,WEEK,WEEKS,WHEN,WHERE,WHILE,WIDTH,WINDOW,WITH,WITHIN,WITHOUT,X,YEAR,YEARS,ZONE")

Review Comment:
   **Finding 1.** This list got the four new keywords, but its Spark Connect 
JDBC sibling did not, and CI is red on it.
   
   `SparkConnectDatabaseMetaDataSuite."SparkConnectDatabaseMetaData 
getSQLKeywords"` asserts its own hardcoded list at 
`sql/connect/client/jdbc/src/test/scala/org/apache/spark/sql/connect/client/jdbc/SparkConnectDatabaseMetaDataSuite.scala:213`.
 It is the only failing test on `c6adea5c405` - one annotation on the "Report 
test results" check run, and the failing "Build modules: ... connect ..." job 
is the same test.
   
   `getSQLKeywords` drops SQL:2003 reserved words, and all four new keywords 
are non-reserved, so all four need adding:
   
   - `...,DISTRIBUTE,DISTRIBUTED,DIV,...`
   - `...,LOAD,LOCALLY,LOCATION,...`
   - `...,OPTIONS,ORDERED,ORDINALITY,...`
   - `...,UNLOCK,UNORDERED,UNPIVOT,...`
   



-- 
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