package com.core.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
/**
* Optimized pagination interceptor that avoids full-table COUNT queries
* for pages without WHERE conditions.
*
*
Strategy:
*
* - SQL WITH WHERE clause -> delegate to parent (normal COUNT(*), indexes help)
* - SQL WITHOUT WHERE clause -> rewrite to simple SELECT COUNT(*) FROM table,
* which lets InnoDB choose the smallest available index for the scan
*
*/
@Slf4j
public class FastPaginationInnerInterceptor extends PaginationInnerInterceptor {
public FastPaginationInnerInterceptor(DbType dbType) {
super(dbType);
}
@Override
public String autoCountSql(IPage> page, String sql) {
if (!page.optimizeCountSql()) {
return super.autoCountSql(page, sql);
}
try {
Statement statement = CCJSqlParserUtil.parse(sql);
if (!(statement instanceof Select)) {
return super.autoCountSql(page, sql);
}
Select select = (Select) statement;
PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
// If SQL has WHERE conditions, delegate to parent's full COUNT rewriting
if (plainSelect.getWhere() != null) {
return super.autoCountSql(page, sql);
}
// No WHERE clause — this is the "browse all records" case.
// Return minimal COUNT query so InnoDB picks the smallest index.
if (plainSelect.getFromItem() != null) {
String tableName = plainSelect.getFromItem().toString();
return "SELECT COUNT(*) FROM " + tableName;
}
} catch (JSQLParserException e) {
log.debug("SQL parsing failed for fast count, using default: {}", e.getMessage());
}
return super.autoCountSql(page, sql);
}
}