You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by ji...@apache.org on 2023/06/09 03:34:58 UTC

[shardingsphere] branch master updated: Support table name backquote parse (#26079)

This is an automated email from the ASF dual-hosted git repository.

jianglongtao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new 0ad2e2237ef Support table name backquote parse (#26079)
0ad2e2237ef is described below

commit 0ad2e2237ef5ce6e41308f0f71fc8c3f663b9717
Author: niu niu <zi...@aliyun.com>
AuthorDate: Fri Jun 9 11:34:50 2023 +0800

    Support table name backquote parse (#26079)
    
    * Support table name backquote parse (#26035)
    
    * Add method Handle the actual table name enclosed in backticks (#26035)
    
    * Format code (#26035)
---
 .../src/main/antlr4/imports/mysql/BaseRule.g4      |  1 +
 .../src/main/antlr4/imports/mysql/Literals.g4      |  4 ++
 .../sql/parser/sql/common/util/SQLUtils.java       | 54 +++++++++++++++++-----
 .../sql/parser/sql/common/util/SQLUtilsTest.java   | 16 +++++++
 .../src/main/resources/case/ddl/create-table.xml   | 12 +++++
 .../resources/sql/supported/ddl/create-table.xml   |  2 +
 6 files changed, 78 insertions(+), 11 deletions(-)

diff --git a/parser/sql/dialect/mysql/src/main/antlr4/imports/mysql/BaseRule.g4 b/parser/sql/dialect/mysql/src/main/antlr4/imports/mysql/BaseRule.g4
index f92077d5075..41e4331fd13 100644
--- a/parser/sql/dialect/mysql/src/main/antlr4/imports/mysql/BaseRule.g4
+++ b/parser/sql/dialect/mysql/src/main/antlr4/imports/mysql/BaseRule.g4
@@ -113,6 +113,7 @@ identifier
     | customKeyword
     | DOUBLE_QUOTED_TEXT
     | UNDERSCORE_CHARSET
+    | BQUOTA_STRING
     ;
     
 identifierKeywordsUnambiguous
diff --git a/parser/sql/dialect/mysql/src/main/antlr4/imports/mysql/Literals.g4 b/parser/sql/dialect/mysql/src/main/antlr4/imports/mysql/Literals.g4
index fe0b64e9cc1..ae3814a59a5 100644
--- a/parser/sql/dialect/mysql/src/main/antlr4/imports/mysql/Literals.g4
+++ b/parser/sql/dialect/mysql/src/main/antlr4/imports/mysql/Literals.g4
@@ -31,6 +31,10 @@ DOUBLE_QUOTED_TEXT
     : DQ_ ( '\\'. | '""' | ~('"'| '\\') )* DQ_
     ;
 
+BQUOTA_STRING
+    : BQ_ ( '\\'. | '``' | ~('`'|'\\'))* BQ_
+    ;
+
 NCHAR_TEXT
     : N SINGLE_QUOTED_TEXT
     ;
diff --git a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/util/SQLUtils.java b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/util/SQLUtils.java
index 3149587f9e6..84914583e0a 100644
--- a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/util/SQLUtils.java
+++ b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/util/SQLUtils.java
@@ -47,13 +47,15 @@ import java.util.regex.Pattern;
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 public final class SQLUtils {
     
+    private static final String BACKTICK = "`";
+    
     private static final String SQL_END = ";";
     
     private static final String COMMENT_PREFIX = "/*";
     
     private static final String COMMENT_SUFFIX = "*/";
     
-    private static final String EXCLUDED_CHARACTERS = "[]`'\"";
+    private static final String EXCLUDED_CHARACTERS = "[]'\"";
     
     private static final Pattern SINGLE_CHARACTER_PATTERN = Pattern.compile("([^\\\\])_|^_");
     
@@ -91,14 +93,14 @@ public final class SQLUtils {
     
     /**
      * Get exactly value for SQL expression.
-     * 
+     *
      * <p>remove special char for SQL expression</p>
-     * 
+     *
      * @param value SQL expression
      * @return exactly SQL expression
      */
     public static String getExactlyValue(final String value) {
-        return null == value ? null : CharMatcher.anyOf(EXCLUDED_CHARACTERS).removeFrom(value);
+        return null == value ? null : tryGetRealContentInBackticks(CharMatcher.anyOf(EXCLUDED_CHARACTERS).removeFrom(value));
     }
     
     /**
@@ -106,7 +108,7 @@ public final class SQLUtils {
      *
      * <p>remove special char for SQL expression</p>
      *
-     * @param value SQL expression
+     * @param value              SQL expression
      * @param reservedCharacters characters to be reserved
      * @return exactly SQL expression
      */
@@ -118,6 +120,36 @@ public final class SQLUtils {
         return CharMatcher.anyOf(toBeExcludedCharacters).removeFrom(value);
     }
     
+    /**
+     * Try get exactly value for backticks string.
+     *
+     * <p>try get content containing backticks exactly value</p>
+     *
+     * @param value SQL expression
+     * @return exactly SQL expression
+     */
+    public static String tryGetRealContentInBackticks(final String value) {
+        if (null == value) {
+            return null;
+        }
+        if (value.startsWith(BACKTICK) && value.endsWith(BACKTICK)) {
+            int startIndex = 1;
+            int stopIndex = value.length() - 1;
+            StringBuilder exactlyTableName = new StringBuilder();
+            while (startIndex < stopIndex) {
+                if (value.charAt(startIndex) == '`' && (startIndex + 1 >= stopIndex || value.charAt(startIndex + 1) != '`')) {
+                    return value;
+                } else if (value.charAt(startIndex) == '`' && value.charAt(startIndex + 1) == '`') {
+                    startIndex++;
+                }
+                exactlyTableName.append(value.charAt(startIndex));
+                startIndex++;
+            }
+            return 0 == exactlyTableName.length() ? value : exactlyTableName.toString();
+        }
+        return value;
+    }
+    
     /**
      * Get exactly SQL expression.
      *
@@ -132,7 +164,7 @@ public final class SQLUtils {
     
     /**
      * Get exactly SQL expression without outside parentheses.
-     * 
+     *
      * @param value SQL expression
      * @return exactly SQL expression
      */
@@ -186,11 +218,11 @@ public final class SQLUtils {
     
     /**
      * Create literal expression.
-     * 
-     * @param astNode AST node
+     *
+     * @param astNode    AST node
      * @param startIndex start index
-     * @param stopIndex stop index
-     * @param text text
+     * @param stopIndex  stop index
+     * @param text       text
      * @return literal expression segment
      */
     public static ExpressionSegment createLiteralExpression(final ASTNode astNode, final int startIndex, final int stopIndex, final String text) {
@@ -241,7 +273,7 @@ public final class SQLUtils {
     
     /**
      * Convert like pattern to regex.
-     * 
+     *
      * @param pattern like pattern
      * @return regex
      */
diff --git a/parser/sql/statement/src/test/java/org/apache/shardingsphere/sql/parser/sql/common/util/SQLUtilsTest.java b/parser/sql/statement/src/test/java/org/apache/shardingsphere/sql/parser/sql/common/util/SQLUtilsTest.java
index edf9e76527d..e42168eab41 100644
--- a/parser/sql/statement/src/test/java/org/apache/shardingsphere/sql/parser/sql/common/util/SQLUtilsTest.java
+++ b/parser/sql/statement/src/test/java/org/apache/shardingsphere/sql/parser/sql/common/util/SQLUtilsTest.java
@@ -63,6 +63,8 @@ class SQLUtilsTest {
         assertThat(SQLUtils.getExactlyValue("[xxx]"), is("xxx"));
         assertThat(SQLUtils.getExactlyValue("\"xxx\""), is("xxx"));
         assertThat(SQLUtils.getExactlyValue("'xxx'"), is("xxx"));
+        assertThat(SQLUtils.getExactlyValue("`[xxx`"), is("xxx"));
+        assertThat(SQLUtils.getExactlyValue("```[xxx```"), is("`xxx`"));
     }
     
     @Test
@@ -153,4 +155,18 @@ class SQLUtilsTest {
         assertThat(SQLUtils.trimComment("/* This is a query with a semicolon */ SHOW DATABASES;"), is("SHOW DATABASES"));
         assertThat(SQLUtils.trimComment("/* This is a query with spaces */    SHOW DATABASES   "), is("SHOW DATABASES"));
     }
+    
+    @Test
+    void assertTryGetRealContentInBackticks() {
+        assertThat(SQLUtils.tryGetRealContentInBackticks("`"), is("`"));
+        assertThat(SQLUtils.tryGetRealContentInBackticks("``"), is("``"));
+        assertThat(SQLUtils.tryGetRealContentInBackticks("```"), is("```"));
+        assertThat(SQLUtils.tryGetRealContentInBackticks("t_order"), is("t_order"));
+        assertThat(SQLUtils.tryGetRealContentInBackticks("````"), is("`"));
+        assertThat(SQLUtils.tryGetRealContentInBackticks("`t_order`"), is("t_order"));
+        assertThat(SQLUtils.tryGetRealContentInBackticks("```t_order`"), is("`t_order"));
+        assertThat(SQLUtils.tryGetRealContentInBackticks("```````t_order```````"), is("```t_order```"));
+        assertThat(SQLUtils.tryGetRealContentInBackticks("``t_order`"), is("``t_order`"));
+        assertThat(SQLUtils.tryGetRealContentInBackticks("`````t_o``r``d``e``r```"), is("``t_o`r`d`e`r`"));
+    }
 }
diff --git a/test/it/parser/src/main/resources/case/ddl/create-table.xml b/test/it/parser/src/main/resources/case/ddl/create-table.xml
index 3a9e2d2e587..3830944e75f 100644
--- a/test/it/parser/src/main/resources/case/ddl/create-table.xml
+++ b/test/it/parser/src/main/resources/case/ddl/create-table.xml
@@ -17,6 +17,18 @@
   -->
 
 <sql-parser-test-cases>
+    <create-table sql-case-id="create_table_with_backtick">
+        <table name="`t_order" start-delimiter="`" end-delimiter="`" start-index="13" stop-index="23" />
+        <column-definition type="int" start-index="26" stop-index="30">
+            <column name="i" />
+        </column-definition>
+    </create-table>
+    <create-table sql-case-id="create_table_column_with_backtick">
+        <table name="``t_o`r`d`e`r`" start-delimiter="`" end-delimiter="`" start-index="13" stop-index="35" />
+        <column-definition type="int" start-delimiter="`" end-delimiter="`" start-index="38" stop-index="46">
+            <column name="`i" />
+        </column-definition>
+    </create-table>
     <create-table sql-case-id="create_table_with_like">
         <table name="t_log" start-index="13" stop-index="17" />
         <like-table name="t_old_log" start-index="24" stop-index="32" />
diff --git a/test/it/parser/src/main/resources/sql/supported/ddl/create-table.xml b/test/it/parser/src/main/resources/sql/supported/ddl/create-table.xml
index e87dab54f58..c67da6bc605 100644
--- a/test/it/parser/src/main/resources/sql/supported/ddl/create-table.xml
+++ b/test/it/parser/src/main/resources/sql/supported/ddl/create-table.xml
@@ -17,6 +17,8 @@
   -->
 
 <sql-cases>
+    <sql-case id="create_table_with_backtick" value="CREATE TABLE ```t_order` (i int)" db-types="MySQL" />
+    <sql-case id="create_table_column_with_backtick" value="create table `````t_o``r``d``e``r``` (```i` int)" db-types="MySQL" />
     <sql-case id="create_table_with_like" value="CREATE TABLE t_log LIKE t_old_log" db-types="MySQL" />
     <sql-case id="create_table" value="CREATE TABLE t_log(id int PRIMARY KEY, status varchar(10))" />
     <sql-case id="create_table_with_engin_charset" value="CREATE TABLE t_log(id int PRIMARY KEY, status varchar(10)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" db-types="MySQL" />