cloud-fan commented on code in PR #58530:
URL: https://github.com/apache/spark/pull/58530#discussion_r3940933503


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/SqlStatementSplitter.scala:
##########
@@ -158,6 +190,36 @@ object SqlStatementSplitter {
     // interpretation (e.g. `double_quoted_identifiers`).
     val conf = SqlApiConf.get
 
+    def appendToken(token: Token): Unit = {
+      if (buffer.isEmpty) {
+        // CodePointCharStream token offsets count Unicode code points, while
+        // String offsets and lengths count UTF-16 code units.
+        bufferStart = sqlText.offsetByCodePoints(0, token.getStartIndex)

Review Comment:
   **Non-blocking (P2):** This conversion starts at index 0 for every 
statement, and `tryParseRegion` performs the same from-zero conversion for 
candidate boundaries. A batch of many short statements therefore rescans 
progressively larger prefixes, making ordinary splitting quadratic despite the 
documented O(n) contract. Please build the code-point-to-UTF-16 boundary 
mapping once, or maintain equivalent incremental offsets, so token-boundary 
lookup is constant time.



##########
sql/core/src/main/scala/org/apache/spark/sql/catalyst/expressions/ParseSql.scala:
##########
@@ -27,34 +27,37 @@ import org.apache.spark.sql.types.{AbstractDataType, 
DataType, StringType}
 import org.apache.spark.unsafe.types.UTF8String
 
 /**
- * Parses a SQL statement string and returns a compact JSON description of the
- * unresolved statement (identifier/code, lineage references, select-list 
names,
- * parameters), or a STANDARD-format error object when the statement does not
- * parse.
+ * Parses a SQL batch string and returns a compact JSON array describing its
+ * unresolved statements (source position, identifier/code, lineage references,
+ * select-list names, parameters). A statement that does not parse is 
represented
+ * by a STANDARD-format error object at its position in the array.
  *
  * Behind [[SQLConf.PARSE_SQL_ENABLED]] while the JSON contract is still
  * evolving. Designed for batch evaluation over DataFrames of SQL text.
  * User-facing parse errors become JSON; unexpected internal failures 
propagate.
  */
 // scalastyle:off line.size.limit
 @ExpressionDescription(
-  usage = """_FUNC_(sqlStmt) - Parses `sqlStmt` with the stock Spark SQL 
parser and
-    returns a JSON string describing the statement (parse success, Table 39 
statement
-    identifier/code, target and source table references for lineage, 
select-list column
-    names, and parameter markers). Session parser extensions are not applied.
+  usage = """_FUNC_(sqlStmt) - Splits `sqlStmt` into SQL statements, parses 
each with
+    the stock Spark SQL parser, and returns a JSON array describing them 
(1-based start

Review Comment:
   **Non-blocking (P2):** The returned `start` and `length` values are UTF-16 
code-unit coordinates, but this public description does not name that unit. For 
`SELECT '😀😀'; SELECT 2;`, the API reports the first length as 13 and the second 
start as 16, while code-point-indexed clients reasonably expect 11 and 14 and 
will slice the wrong text. Please state explicitly that `start` is a 1-based 
UTF-16 code-unit offset and `length` is a UTF-16 code-unit count, and include a 
non-BMP example so clients can interpret the fields reliably.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/parser/SqlStatementSplitter.scala:
##########
@@ -158,6 +190,36 @@ object SqlStatementSplitter {
     // interpretation (e.g. `double_quoted_identifiers`).
     val conf = SqlApiConf.get
 
+    def appendToken(token: Token): Unit = {
+      if (buffer.isEmpty) {
+        // CodePointCharStream token offsets count Unicode code points, while
+        // String offsets and lengths count UTF-16 code units.
+        bufferStart = sqlText.offsetByCodePoints(0, token.getStartIndex)
+      }
+      buffer.append(token.getText)
+    }
+
+    def resetBuffer(): Unit = {
+      buffer.setLength(0)
+      bufferStart = -1
+      bufferHasContent = false
+    }
+
+    def positionedStatement(terminator: String): 
Option[PositionedSqlStatement] = {
+      val raw = buffer.toString
+      val statement = raw.trim

Review Comment:
   **Non-blocking (P2):** `String.trim` only removes characters up to U+0020, 
but the Spark SQL lexer also treats Unicode spaces such as U+00A0 as 
whitespace. Consequently, `parse_sql("\u00a0SELECT 1\u00a0;")` retains both 
NBSPs and reports start 1/length 10 instead of the promised trimmed span at 
start 2/length 8. Please trim with the lexer's whitespace semantics and derive 
the leading UTF-16 offset from the same boundary.



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