|
@@ -0,0 +1,347 @@
|
|
|
+/*
|
|
|
+ * Copyright (c) 2011-2020, baomidou (jobob@qq.com).
|
|
|
+ * <p>
|
|
|
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
|
+ * use this file except in compliance with the License. You may obtain a copy of
|
|
|
+ * the License at
|
|
|
+ * <p>
|
|
|
+ * https://www.apache.org/licenses/LICENSE-2.0
|
|
|
+ * <p>
|
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
+ * License for the specific language governing permissions and limitations under
|
|
|
+ * the License.
|
|
|
+ */
|
|
|
+package com.baomidou.mybatisplus.extension.plugins.inner;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.parser.SqlParserHelper;
|
|
|
+import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.ClassUtils;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
|
|
|
+import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
|
|
|
+import com.baomidou.mybatisplus.extension.toolkit.PropertyMapper;
|
|
|
+import lombok.*;
|
|
|
+import net.sf.jsqlparser.expression.BinaryExpression;
|
|
|
+import net.sf.jsqlparser.expression.Expression;
|
|
|
+import net.sf.jsqlparser.expression.Parenthesis;
|
|
|
+import net.sf.jsqlparser.expression.ValueListExpression;
|
|
|
+import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
|
|
+import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
|
|
+import net.sf.jsqlparser.expression.operators.relational.*;
|
|
|
+import net.sf.jsqlparser.schema.Column;
|
|
|
+import net.sf.jsqlparser.schema.Table;
|
|
|
+import net.sf.jsqlparser.statement.delete.Delete;
|
|
|
+import net.sf.jsqlparser.statement.insert.Insert;
|
|
|
+import net.sf.jsqlparser.statement.select.*;
|
|
|
+import net.sf.jsqlparser.statement.update.Update;
|
|
|
+import org.apache.ibatis.executor.Executor;
|
|
|
+import org.apache.ibatis.executor.statement.StatementHandler;
|
|
|
+import org.apache.ibatis.mapping.BoundSql;
|
|
|
+import org.apache.ibatis.mapping.MappedStatement;
|
|
|
+import org.apache.ibatis.mapping.SqlCommandType;
|
|
|
+import org.apache.ibatis.session.ResultHandler;
|
|
|
+import org.apache.ibatis.session.RowBounds;
|
|
|
+
|
|
|
+import java.sql.Connection;
|
|
|
+import java.sql.SQLException;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Properties;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author hubin
|
|
|
+ * @since 3.4.0
|
|
|
+ * @deprecated 只为了过度 TenantSqlParser
|
|
|
+ */
|
|
|
+@Deprecated
|
|
|
+@Data
|
|
|
+@NoArgsConstructor
|
|
|
+@AllArgsConstructor
|
|
|
+@ToString(callSuper = true)
|
|
|
+@EqualsAndHashCode(callSuper = true)
|
|
|
+@SuppressWarnings({"rawtypes"})
|
|
|
+public class FakeTenantLineInnerInterceptor extends JsqlParserSupport implements InnerInterceptor {
|
|
|
+
|
|
|
+ private TenantHandler tenantHandler;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
|
|
|
+ if (InterceptorIgnoreHelper.willIgnoreTenantLine(ms.getId())) return;
|
|
|
+ if (SqlParserHelper.getSqlParserInfo(ms)) return;
|
|
|
+ PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
|
|
|
+ mpBs.sql(parserSingle(mpBs.sql(), null));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
|
|
|
+ PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
|
|
|
+ MappedStatement ms = mpSh.mappedStatement();
|
|
|
+ SqlCommandType sct = ms.getSqlCommandType();
|
|
|
+ if (sct == SqlCommandType.INSERT || sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) {
|
|
|
+ if (InterceptorIgnoreHelper.willIgnoreTenantLine(ms.getId())) return;
|
|
|
+ if (SqlParserHelper.getSqlParserInfo(ms)) return;
|
|
|
+ PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
|
|
|
+ mpBs.sql(parserMulti(mpBs.sql(), null));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void processSelect(Select select, int index, String sql, Object obj) {
|
|
|
+ processSelectBody(select.getSelectBody());
|
|
|
+ }
|
|
|
+
|
|
|
+ protected void processSelectBody(SelectBody selectBody) {
|
|
|
+ if (selectBody instanceof PlainSelect) {
|
|
|
+ processPlainSelect((PlainSelect) selectBody);
|
|
|
+ } else if (selectBody instanceof WithItem) {
|
|
|
+ WithItem withItem = (WithItem) selectBody;
|
|
|
+ if (withItem.getSelectBody() != null) {
|
|
|
+ processSelectBody(withItem.getSelectBody());
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ SetOperationList operationList = (SetOperationList) selectBody;
|
|
|
+ if (operationList.getSelects() != null && operationList.getSelects().size() > 0) {
|
|
|
+ operationList.getSelects().forEach(this::processSelectBody);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void processInsert(Insert insert, int index, String sql, Object obj) {
|
|
|
+ if (tenantHandler.doTableFilter(insert.getTable().getName())) {
|
|
|
+ // 过滤退出执行
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ insert.getColumns().add(new Column(tenantHandler.getTenantIdColumn()));
|
|
|
+ if (insert.getSelect() != null) {
|
|
|
+ processPlainSelect((PlainSelect) insert.getSelect().getSelectBody(), true);
|
|
|
+ } else if (insert.getItemsList() != null) {
|
|
|
+ // fixed github pull/295
|
|
|
+ ItemsList itemsList = insert.getItemsList();
|
|
|
+ if (itemsList instanceof MultiExpressionList) {
|
|
|
+ ((MultiExpressionList) itemsList).getExprList().forEach(el -> el.getExpressions().add(tenantHandler.getTenantId(false)));
|
|
|
+ } else {
|
|
|
+ ((ExpressionList) insert.getItemsList()).getExpressions().add(tenantHandler.getTenantId(false));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ throw ExceptionUtils.mpe("Failed to process multiple-table update, please exclude the tableName or statementId");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * update 语句处理
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ protected void processUpdate(Update update, int index, String sql, Object obj) {
|
|
|
+ final Table table = update.getTable();
|
|
|
+ if (tenantHandler.doTableFilter(table.getName())) {
|
|
|
+ // 过滤退出执行
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ update.setWhere(this.andExpression(table, update.getWhere()));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * delete 语句处理
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ protected void processDelete(Delete delete, int index, String sql, Object obj) {
|
|
|
+ if (tenantHandler.doTableFilter(delete.getTable().getName())) {
|
|
|
+ // 过滤退出执行
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ delete.setWhere(this.andExpression(delete.getTable(), delete.getWhere()));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * delete update 语句 where 处理
|
|
|
+ */
|
|
|
+ protected BinaryExpression andExpression(Table table, Expression where) {
|
|
|
+ //获得where条件表达式
|
|
|
+ EqualsTo equalsTo = new EqualsTo();
|
|
|
+ equalsTo.setLeftExpression(this.getAliasColumn(table));
|
|
|
+ equalsTo.setRightExpression(tenantHandler.getTenantId(false));
|
|
|
+ if (null != where) {
|
|
|
+ if (where instanceof OrExpression) {
|
|
|
+ return new AndExpression(equalsTo, new Parenthesis(where));
|
|
|
+ } else {
|
|
|
+ return new AndExpression(equalsTo, where);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return equalsTo;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理 PlainSelect
|
|
|
+ */
|
|
|
+ protected void processPlainSelect(PlainSelect plainSelect) {
|
|
|
+ processPlainSelect(plainSelect, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理 PlainSelect
|
|
|
+ *
|
|
|
+ * @param plainSelect ignore
|
|
|
+ * @param addColumn 是否添加租户列,insert into select语句中需要
|
|
|
+ */
|
|
|
+ protected void processPlainSelect(PlainSelect plainSelect, boolean addColumn) {
|
|
|
+ FromItem fromItem = plainSelect.getFromItem();
|
|
|
+ if (fromItem instanceof Table) {
|
|
|
+ Table fromTable = (Table) fromItem;
|
|
|
+ if (!tenantHandler.doTableFilter(fromTable.getName())) {
|
|
|
+ //#1186 github
|
|
|
+ plainSelect.setWhere(builderExpression(plainSelect.getWhere(), fromTable));
|
|
|
+ if (addColumn) {
|
|
|
+ plainSelect.getSelectItems().add(new SelectExpressionItem(new Column(tenantHandler.getTenantIdColumn())));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ processFromItem(fromItem);
|
|
|
+ }
|
|
|
+ List<Join> joins = plainSelect.getJoins();
|
|
|
+ if (joins != null && joins.size() > 0) {
|
|
|
+ joins.forEach(j -> {
|
|
|
+ processJoin(j);
|
|
|
+ processFromItem(j.getRightItem());
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理子查询等
|
|
|
+ */
|
|
|
+ protected void processFromItem(FromItem fromItem) {
|
|
|
+ if (fromItem instanceof SubJoin) {
|
|
|
+ SubJoin subJoin = (SubJoin) fromItem;
|
|
|
+ if (subJoin.getJoinList() != null) {
|
|
|
+ subJoin.getJoinList().forEach(this::processJoin);
|
|
|
+ }
|
|
|
+ if (subJoin.getLeft() != null) {
|
|
|
+ processFromItem(subJoin.getLeft());
|
|
|
+ }
|
|
|
+ } else if (fromItem instanceof SubSelect) {
|
|
|
+ SubSelect subSelect = (SubSelect) fromItem;
|
|
|
+ if (subSelect.getSelectBody() != null) {
|
|
|
+ processSelectBody(subSelect.getSelectBody());
|
|
|
+ }
|
|
|
+ } else if (fromItem instanceof ValuesList) {
|
|
|
+ logger.debug("Perform a subquery, if you do not give us feedback");
|
|
|
+ } else if (fromItem instanceof LateralSubSelect) {
|
|
|
+ LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem;
|
|
|
+ if (lateralSubSelect.getSubSelect() != null) {
|
|
|
+ SubSelect subSelect = lateralSubSelect.getSubSelect();
|
|
|
+ if (subSelect.getSelectBody() != null) {
|
|
|
+ processSelectBody(subSelect.getSelectBody());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理联接语句
|
|
|
+ */
|
|
|
+ protected void processJoin(Join join) {
|
|
|
+ if (join.getRightItem() instanceof Table) {
|
|
|
+ Table fromTable = (Table) join.getRightItem();
|
|
|
+ if (this.tenantHandler.doTableFilter(fromTable.getName())) {
|
|
|
+ // 过滤退出执行
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ join.setOnExpression(builderExpression(join.getOnExpression(), fromTable));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理条件:
|
|
|
+ * 支持 getTenantHandler().getTenantId()是一个完整的表达式:tenant in (1,2)
|
|
|
+ * 默认tenantId的表达式: LongValue(1)这种依旧支持
|
|
|
+ */
|
|
|
+ protected Expression builderExpression(Expression currentExpression, Table table) {
|
|
|
+ final Expression tenantExpression = tenantHandler.getTenantId(true);
|
|
|
+ Expression appendExpression = this.processTableAlias4CustomizedTenantIdExpression(tenantExpression, table);
|
|
|
+ if (currentExpression == null) {
|
|
|
+ return appendExpression;
|
|
|
+ }
|
|
|
+ if (currentExpression instanceof BinaryExpression) {
|
|
|
+ BinaryExpression binaryExpression = (BinaryExpression) currentExpression;
|
|
|
+ doExpression(binaryExpression.getLeftExpression());
|
|
|
+ doExpression(binaryExpression.getRightExpression());
|
|
|
+ } else if (currentExpression instanceof InExpression) {
|
|
|
+ InExpression inExp = (InExpression) currentExpression;
|
|
|
+ ItemsList rightItems = inExp.getRightItemsList();
|
|
|
+ if (rightItems instanceof SubSelect) {
|
|
|
+ processSelectBody(((SubSelect) rightItems).getSelectBody());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (currentExpression instanceof OrExpression) {
|
|
|
+ return new AndExpression(new Parenthesis(currentExpression), appendExpression);
|
|
|
+ } else {
|
|
|
+ return new AndExpression(currentExpression, appendExpression);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ protected void doExpression(Expression expression) {
|
|
|
+ if (expression instanceof FromItem) {
|
|
|
+ processFromItem((FromItem) expression);
|
|
|
+ } else if (expression instanceof InExpression) {
|
|
|
+ InExpression inExp = (InExpression) expression;
|
|
|
+ ItemsList rightItems = inExp.getRightItemsList();
|
|
|
+ if (rightItems instanceof SubSelect) {
|
|
|
+ processSelectBody(((SubSelect) rightItems).getSelectBody());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 目前: 针对自定义的tenantId的条件表达式[tenant_id in (1,2,3)],无法处理多租户的字段加上表别名
|
|
|
+ * select a.id, b.name
|
|
|
+ * from a
|
|
|
+ * join b on b.aid = a.id and [b.]tenant_id in (1,2) --别名[b.]无法加上 TODO
|
|
|
+ *
|
|
|
+ * @param expression
|
|
|
+ * @param table
|
|
|
+ * @return 加上别名的多租户字段表达式
|
|
|
+ */
|
|
|
+ protected Expression processTableAlias4CustomizedTenantIdExpression(Expression expression, Table table) {
|
|
|
+ Expression target;
|
|
|
+ if (expression instanceof ValueListExpression) {
|
|
|
+ InExpression inExpression = new InExpression();
|
|
|
+ inExpression.setLeftExpression(this.getAliasColumn(table));
|
|
|
+ inExpression.setRightItemsList(((ValueListExpression) expression).getExpressionList());
|
|
|
+ target = inExpression;
|
|
|
+ } else {
|
|
|
+ EqualsTo equalsTo = new EqualsTo();
|
|
|
+ equalsTo.setLeftExpression(this.getAliasColumn(table));
|
|
|
+ equalsTo.setRightExpression(expression);
|
|
|
+ target = equalsTo;
|
|
|
+ }
|
|
|
+ return target;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 租户字段别名设置
|
|
|
+ * <p>tenantId 或 tableAlias.tenantId</p>
|
|
|
+ *
|
|
|
+ * @param table 表对象
|
|
|
+ * @return 字段
|
|
|
+ */
|
|
|
+ protected Column getAliasColumn(Table table) {
|
|
|
+ StringBuilder column = new StringBuilder();
|
|
|
+ if (table.getAlias() != null) {
|
|
|
+ column.append(table.getAlias().getName()).append(StringPool.DOT);
|
|
|
+ }
|
|
|
+ column.append(tenantHandler.getTenantIdColumn());
|
|
|
+ return new Column(column.toString());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void setProperties(Properties properties) {
|
|
|
+ PropertyMapper.newInstance(properties)
|
|
|
+ .whenNotBlack("tenantHandler", ClassUtils::newInstance, this::setTenantHandler);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|