diff --git a/linkis-computation-governance/linkis-entrance/src/main/scala/org/apache/linkis/entrance/interceptor/impl/Explain.scala b/linkis-computation-governance/linkis-entrance/src/main/scala/org/apache/linkis/entrance/interceptor/impl/Explain.scala index 045cb51f88..7760c11a08 100644 --- a/linkis-computation-governance/linkis-entrance/src/main/scala/org/apache/linkis/entrance/interceptor/impl/Explain.scala +++ b/linkis-computation-governance/linkis-entrance/src/main/scala/org/apache/linkis/entrance/interceptor/impl/Explain.scala @@ -176,7 +176,7 @@ object SQLExplain extends Explain { } } } else { - tempCode.split(";") foreach { singleCode => + splitSqlWithRealSemicolon(tempCode) foreach { singleCode => if (isSelectCmd(singleCode)) { val trimCode = singleCode.trim if (isSelectCmdNoLimit(trimCode) && !isNoLimitAllowed) { @@ -230,6 +230,50 @@ object SQLExplain extends Explain { array.toArray } + private def splitSqlWithRealSemicolon(tempCode: String): Array[String] = { + // sql has been split by semicolons, but the semicolons within single quotes, double quotes, and backquotes are ignored + val splitSql = new ArrayBuffer[String] + val current = new StringBuilder + var inSingleQuote = false + var inDoubleQuote = false + var inBackQuote = false + var escapeNext = false + + for (char <- tempCode) { + if (escapeNext) { + current.append(char) + escapeNext = false + } else { + char match { + case '\\' => + current.append(char) + escapeNext = true + case '\'' if !inDoubleQuote && !inBackQuote => + current.append(char) + inSingleQuote = !inSingleQuote + case '"' if !inSingleQuote && !inBackQuote => + current.append(char) + inDoubleQuote = !inDoubleQuote + case '`' if !inSingleQuote && !inDoubleQuote => + current.append(char) + inBackQuote = !inBackQuote + case ';' if !inSingleQuote && !inDoubleQuote && !inBackQuote => + splitSql += current.toString() + current.clear() + case _ => + current.append(char) + } + } + } + + // Add the last fragment + if (current.nonEmpty) { + splitSql += current.toString() + } + splitSql.toArray + + } + private def addNoLimit(code: String) = code + NO_LIMIT_STRING protected def needNoLimit(code: String): Boolean = code.endsWith(NO_LIMIT_STRING) diff --git a/linkis-computation-governance/linkis-entrance/src/test/java/org/apache/linkis/entrance/interceptor/impl/SQLExplainTest.java b/linkis-computation-governance/linkis-entrance/src/test/java/org/apache/linkis/entrance/interceptor/impl/SQLExplainTest.java index c5efb5633e..49e65e964a 100644 --- a/linkis-computation-governance/linkis-entrance/src/test/java/org/apache/linkis/entrance/interceptor/impl/SQLExplainTest.java +++ b/linkis-computation-governance/linkis-entrance/src/test/java/org/apache/linkis/entrance/interceptor/impl/SQLExplainTest.java @@ -17,6 +17,7 @@ package org.apache.linkis.entrance.interceptor.impl; +import org.apache.linkis.governance.common.entity.job.JobRequest; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -52,4 +53,26 @@ void isSelectOverLimit() { res = SQLExplain.isSelectOverLimit(code); Assertions.assertEquals(false, res); } + + /** + * 未修复前代码进行拼接sql时,输出的sql为 + * select + * id, + * name, + * array_join(array_intersect(map_keys(info),array['abs','oda'],' limit 5000; + * ') as infos + * from ods.dim_ep22 + */ + @Test + void splicingLimitSql() { + String code = "select\n" + + "id,\n" + + "name,\n" + + "array_join(array_intersect(map_keys(info),array['abs','oda'],';') as infos\n" + + "from ods.dim_ep22"; + StringBuilder logAppender = new StringBuilder(); + JobRequest jobRequest = new JobRequest(); + SQLExplain.dealSQLLimit(code, jobRequest, logAppender); + Assertions.assertEquals(code+" limit 5000", jobRequest.getExecutionCode()); + } }