JsqlParserCountOptimize.java 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /**
  2. * Copyright (c) 2011-2014, hubin (jobob@qq.com).
  3. * <p>
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. * <p>
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. * <p>
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.baomidou.mybatisplus.plugins.pagination.optimize;
  17. import java.util.ArrayList;
  18. import java.util.List;
  19. import org.apache.ibatis.logging.Log;
  20. import org.apache.ibatis.logging.LogFactory;
  21. import org.apache.ibatis.reflection.MetaObject;
  22. import com.baomidou.mybatisplus.plugins.parser.ISqlParser;
  23. import com.baomidou.mybatisplus.plugins.parser.SqlInfo;
  24. import com.baomidou.mybatisplus.toolkit.CollectionUtils;
  25. import com.baomidou.mybatisplus.toolkit.SqlUtils;
  26. import net.sf.jsqlparser.expression.Expression;
  27. import net.sf.jsqlparser.expression.Function;
  28. import net.sf.jsqlparser.expression.LongValue;
  29. import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
  30. import net.sf.jsqlparser.parser.CCJSqlParserUtil;
  31. import net.sf.jsqlparser.statement.select.Distinct;
  32. import net.sf.jsqlparser.statement.select.OrderByElement;
  33. import net.sf.jsqlparser.statement.select.PlainSelect;
  34. import net.sf.jsqlparser.statement.select.Select;
  35. import net.sf.jsqlparser.statement.select.SelectExpressionItem;
  36. import net.sf.jsqlparser.statement.select.SelectItem;
  37. /**
  38. * <p>
  39. * JsqlParser Count Optimize
  40. * </p>
  41. *
  42. * @author hubin
  43. * @since 2017-06-20
  44. */
  45. public class JsqlParserCountOptimize implements ISqlParser {
  46. // 日志
  47. private final Log logger = LogFactory.getLog(JsqlParserCountOptimize.class);
  48. private static final List<SelectItem> countSelectItem = countSelectItem();
  49. @Override
  50. public SqlInfo optimizeSql(MetaObject metaObject, String sql) {
  51. if (logger.isDebugEnabled()) {
  52. logger.debug(" JsqlParserCountOptimize sql=" + sql);
  53. }
  54. SqlInfo sqlInfo = SqlInfo.newInstance();
  55. try {
  56. Select selectStatement = (Select) CCJSqlParserUtil.parse(sql);
  57. PlainSelect plainSelect = (PlainSelect) selectStatement.getSelectBody();
  58. Distinct distinct = plainSelect.getDistinct();
  59. List<Expression> groupBy = plainSelect.getGroupByColumnReferences();
  60. List<OrderByElement> orderBy = plainSelect.getOrderByElements();
  61. // 添加包含groupBy 不去除orderBy
  62. if (CollectionUtils.isEmpty(groupBy) && CollectionUtils.isNotEmpty(orderBy)) {
  63. plainSelect.setOrderByElements(null);
  64. sqlInfo.setOrderBy(false);
  65. }
  66. //#95 Github, selectItems contains #{} ${}, which will be translated to ?, and it may be in a function: power(#{myInt},2)
  67. for (SelectItem item : plainSelect.getSelectItems()) {
  68. if (item.toString().contains("?")) {
  69. sqlInfo.setSql(String.format(SqlUtils.SQL_BASE_COUNT, selectStatement.toString()));
  70. return sqlInfo;
  71. }
  72. }
  73. // 包含 distinct、groupBy不优化
  74. if (distinct != null || CollectionUtils.isNotEmpty(groupBy)) {
  75. sqlInfo.setSql(String.format(SqlUtils.SQL_BASE_COUNT, selectStatement.toString()));
  76. return sqlInfo;
  77. }
  78. // 优化 SQL
  79. plainSelect.setSelectItems(countSelectItem);
  80. sqlInfo.setSql(selectStatement.toString());
  81. return sqlInfo;
  82. } catch (Throwable e) {
  83. // 无法优化使用原 SQL
  84. sqlInfo.setSql(String.format(SqlUtils.SQL_BASE_COUNT, sql));
  85. return sqlInfo;
  86. }
  87. }
  88. /**
  89. * <p>
  90. * 获取jsqlparser中count的SelectItem
  91. * </p>
  92. */
  93. private static List<SelectItem> countSelectItem() {
  94. Function function = new Function();
  95. function.setName("COUNT");
  96. List<Expression> expressions = new ArrayList<>();
  97. LongValue longValue = new LongValue(1);
  98. ExpressionList expressionList = new ExpressionList();
  99. expressions.add(longValue);
  100. expressionList.setExpressions(expressions);
  101. function.setParameters(expressionList);
  102. List<SelectItem> selectItems = new ArrayList<>();
  103. SelectExpressionItem selectExpressionItem = new SelectExpressionItem(function);
  104. selectItems.add(selectExpressionItem);
  105. return selectItems;
  106. }
  107. }