cloud-fan commented on code in PR #52334:
URL: https://github.com/apache/spark/pull/52334#discussion_r2436032064
##########
sql/core/src/main/scala/org/apache/spark/sql/execution/SparkSqlParser.scala:
##########
@@ -50,8 +54,110 @@ class SparkSqlParser extends AbstractSqlParser {
private val substitutor = new VariableSubstitution()
+ /**
+ * Parse SQL with explicit parameter context, avoiding thread-local usage.
+ * This is the preferred method for parsing SQL with parameters.
+ *
+ * @param command The SQL text to parse
+ * @param parameterContext The parameter context containing parameter values
+ * @param toResult Function to convert the parser result
+ * @return The parsed result
+ */
+ def parseWithParameters[T](
+ command: String,
+ parameterContext: ParameterContext)
+ (toResult: SqlBaseParser => T): T = {
+ parseInternal(command, Some(parameterContext))(toResult)
+ }
+
+ /**
+ * Parse SQL plan with explicit parameter context, avoiding thread-local
usage.
+ * This is the preferred method for parsing SQL plans with parameters.
+ *
+ * @param sqlText The SQL text to parse
+ * @param parameterContext The parameter context containing parameter values
+ * @return The parsed logical plan
+ */
+ override def parsePlanWithParameters(
+ sqlText: String,
+ parameterContext: ParameterContext): LogicalPlan = {
+ parseWithParameters(sqlText, parameterContext) { parser =>
+ val ctx = parser.compoundOrSingleStatement()
+ withErrorHandling(ctx, Some(sqlText)) {
+ astBuilder.visitCompoundOrSingleStatement(ctx) match {
+ case compoundBody: CompoundPlanStatement => compoundBody
+ case plan: LogicalPlan => plan
+ case _ =>
+ val position = Origin(None, None)
+ throw QueryParsingErrors.sqlStatementUnsupportedError(sqlText,
position)
+ }
+ }
+ }
+ }
+
protected override def parse[T](command: String)(toResult: SqlBaseParser =>
T): T = {
- super.parse(substitutor.substitute(command))(toResult)
+ parseInternal(command, None)(toResult)
+ }
+
+ /**
+ * Internal parse method that handles both parameter substitution and
regular parsing.
+ *
+ * @param command The SQL text to parse
+ * @param parameterContext Optional parameter context for parameter
substitution
+ * @param toResult Function to convert the parser result
+ * @return The parsed result
+ */
+ private def parseInternal[T](
+ command: String,
+ parameterContext: Option[ParameterContext])
+ (toResult: SqlBaseParser => T): T = {
+
+ // Step 1: Apply variable substitution to expand any variable references.
+ val variableSubstituted = substitutor.substitute(command)
+
+ // Step 2: Apply parameter substitution if a parameter context is provided.
+ val (paramSubstituted, positionMapper, hasParameters) = parameterContext
match {
+ case Some(context) =>
+ if (SQLConf.get.legacyParameterSubstitutionConstantsOnly) {
+ // Legacy mode: Parameters are detected but substitution is deferred
to analysis phase.
+ (variableSubstituted, None, true)
+ } else {
+ // Modern mode: Perform parameter substitution during parsing.
+ val (substituted, mapper) =
+ ParameterHandler.substituteParameters(variableSubstituted, context)
+ (substituted, mapper, true)
+ }
+ case None =>
+ // No parameter context provided; skip parameter substitution.
+ (variableSubstituted, None, false)
+ }
+
+ // Step 3: Set up the origin with SQL text and position mapper to enable
+ // parameter-aware error reporting.
+ val currentOrigin = CurrentOrigin.get
+ val originToUse = if (positionMapper.isDefined || hasParameters) {
+ // Set up origin with the substituted SQL text and position mapper for
+ // proper error reporting.
+ currentOrigin.copy(
+ sqlText = Some(paramSubstituted),
+ startIndex = Some(0),
+ stopIndex = Some(paramSubstituted.length - 1),
+ positionMapper = positionMapper
+ )
+ } else {
+ // No substitution occurred; use the existing origin unchanged.
+ currentOrigin
+ }
+
+ // Parse with the origin containing position mapper, ensuring cleanup
afterwards.
+ CurrentOrigin.withOrigin(originToUse) {
+ try {
Review Comment:
we can remove the try-catch, as `CurrentOrigin.withOrigin` already does it.
--
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]