Forráskód Böngészése

Merge pull request #3928 from Hccake/3.0

:bug: fix left join 条件构造会多一个的问题,以及对于尾缀多个 OnExpression 类似的连接 SQL 支持
qmdx 3 éve
szülő
commit
c02272b531

+ 55 - 6
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/plugins/inner/TenantLineInnerInterceptor.java

@@ -41,8 +41,12 @@ import org.apache.ibatis.session.RowBounds;
 
 import java.sql.Connection;
 import java.sql.SQLException;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Properties;
+import java.util.stream.Collectors;
 
 /**
  * @author hubin
@@ -249,10 +253,7 @@ public class TenantLineInnerInterceptor extends JsqlParserSupport implements Inn
         }
         List<Join> joins = plainSelect.getJoins();
         if (CollectionUtils.isNotEmpty(joins)) {
-            joins.forEach(j -> {
-                processJoin(j);
-                processFromItem(j.getRightItem());
-            });
+            processJoins(joins);
         }
     }
 
@@ -351,7 +352,7 @@ public class TenantLineInnerInterceptor extends JsqlParserSupport implements Inn
         if (fromItem instanceof SubJoin) {
             SubJoin subJoin = (SubJoin) fromItem;
             if (subJoin.getJoinList() != null) {
-                subJoin.getJoinList().forEach(this::processJoin);
+                processJoins(subJoin.getJoinList());
             }
             if (subJoin.getLeft() != null) {
                 processFromItem(subJoin.getLeft());
@@ -374,6 +375,50 @@ public class TenantLineInnerInterceptor extends JsqlParserSupport implements Inn
         }
     }
 
+    /**
+     * 处理 joins
+     *
+     * @param joins join 集合
+     */
+    private void processJoins(List<Join> joins) {
+        //对于 on 表达式写在最后的 join,需要记录下前面多个 on 的表名
+        Deque<Table> tables = new LinkedList<>();
+        for (Join join : joins) {
+            // 处理 on 表达式
+            FromItem fromItem = join.getRightItem();
+            if (fromItem instanceof Table) {
+                Table fromTable = (Table) fromItem;
+                // 获取 join 尾缀的 on 表达式列表
+                Collection<Expression> originOnExpressions = join.getOnExpressions();
+                // 正常 join on 表达式只有一个,立刻处理
+                if (originOnExpressions.size() == 1) {
+                    processJoin(join);
+                    continue;
+                }
+                // 当前表是否忽略
+                boolean needIgnore = tenantLineHandler.ignoreTable(fromTable.getName());
+                // 表名压栈,忽略的表压入 null,以便后续不处理
+                tables.push(needIgnore ? null : fromTable);
+                // 尾缀多个 on 表达式的时候统一处理
+                if (originOnExpressions.size() > 1) {
+                    Collection<Expression> onExpressions = new LinkedList<>();
+                    for (Expression originOnExpression : originOnExpressions) {
+                        Table currentTable = tables.poll();
+                        if (currentTable == null) {
+                            onExpressions.add(originOnExpression);
+                        } else {
+                            onExpressions.add(builderExpression(originOnExpression, currentTable));
+                        }
+                    }
+                    join.setOnExpressions(onExpressions);
+                }
+            } else {
+                // 处理右边连接的子表达式
+                processFromItem(fromItem);
+            }
+        }
+    }
+
     /**
      * 处理联接语句
      */
@@ -384,7 +429,11 @@ public class TenantLineInnerInterceptor extends JsqlParserSupport implements Inn
                 // 过滤退出执行
                 return;
             }
-            join.setOnExpression(builderExpression(join.getOnExpression(), fromTable));
+            // 走到这里说明 on 表达式肯定只有一个
+            Collection<Expression> originOnExpressions = join.getOnExpressions();
+            List<Expression> onExpressions = new LinkedList<>();
+            onExpressions.add(builderExpression(originOnExpressions.iterator().next(), fromTable));
+            join.setOnExpressions(onExpressions);
         }
     }
 

+ 28 - 1
mybatis-plus-extension/src/test/java/com/baomidou/mybatisplus/extension/plugins/inner/TenantLineInnerInterceptorTest.java

@@ -157,7 +157,7 @@ class TenantLineInnerInterceptorTest {
     }
 
     @Test
-    void selectBodySubSelect(){
+    void selectBodySubSelect() {
         assertSql("select t1.col1,(select t2.col2 from t2 t2 where t1.col1=t2.col1) from t1 t1",
             "SELECT t1.col1, (SELECT t2.col2 FROM t2 t2 WHERE t1.col1 = t2.col1 AND t2.tenant_id = 1) FROM t1 t1 WHERE t1.tenant_id = 1");
     }
@@ -180,6 +180,32 @@ class TenantLineInnerInterceptorTest {
                 "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
     }
 
+    @Test
+    void selectLeftJoinMultipleTrailingOn() {
+        // 多个 on 尾缀的
+        assertSql("SELECT * FROM entity e " +
+                "LEFT JOIN entity1 e1 " +
+                "LEFT JOIN entity2 e2 ON e2.id = e1.id " +
+                "ON e1.id = e.id " +
+                "WHERE (e.id = ? OR e.NAME = ?)",
+            "SELECT * FROM entity e " +
+                "LEFT JOIN entity1 e1 " +
+                "LEFT JOIN entity2 e2 ON e2.id = e1.id AND e2.tenant_id = 1 " +
+                "ON e1.id = e.id AND e1.tenant_id = 1 " +
+                "WHERE (e.id = ? OR e.NAME = ?) AND e.tenant_id = 1");
+
+        assertSql("SELECT * FROM entity e " +
+                "LEFT JOIN entity1 e1 " +
+                "LEFT JOIN with_as_A e2 ON e2.id = e1.id " +
+                "ON e1.id = e.id " +
+                "WHERE (e.id = ? OR e.NAME = ?)",
+            "SELECT * FROM entity e " +
+                "LEFT JOIN entity1 e1 " +
+                "LEFT JOIN with_as_A e2 ON e2.id = e1.id " +
+                "ON e1.id = e.id AND e1.tenant_id = 1 " +
+                "WHERE (e.id = ? OR e.NAME = ?) AND e.tenant_id = 1");
+    }
+
     @Test
     void selectInnerJoin() {
         // inner join
@@ -205,6 +231,7 @@ class TenantLineInnerInterceptorTest {
 //                "WHERE (e.id = ? OR e.name = ?) AND e.tenant_id = 1");
     }
 
+
     @Test
     void selectWithAs() {
         assertSql("with with_as_A as (select * from entity) select * from with_as_A",