[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\nindent_style = space\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nend_of_line = lf\n\n[*.java]\nij_java_align_group_field_declarations = true\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: abel533\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: ['https://mybatis.io/donates.html'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\n"
  },
  {
    "path": ".github/issue_template.md",
    "content": "---\nname: PageHelper issue report template\nabout: If you would like to report a issue to PageHelper, please use this template.\n\n---\n\n- [ ] 我已在 [issues](https://github.com/pagehelper/Mybatis-PageHelper/issues) 搜索类似问题，并且不存在相同的问题.\n\n## 异常模板\n\n### 使用环境\n\n* PageHelper 版本: xxx\n* 数据库类型和版本: xxx\n* JDBC_URL: xxx\n\n### SQL 解析错误\n\n#### 分页参数\n\n```java\nPageHelper.startPage(1, 10);\nxxMapper.select(model);\n```\n\n#### 原 SQL\n\n```sql\nselect * from xxx where xxx = xxx\n```\n\n#### 期望的结果：\n\n```sql\nselect * from xxx where xxx = xxx limit 10\n```\n\n### 完整异常信息\n\n```\n异常信息放在这里\n```\n\n### 其他类型的错误\n\n## 功能建议\n\n详细说明，尽可能提供(伪)代码示例。\n"
  },
  {
    "path": ".github/workflows/pull-request.yml",
    "content": "name: Maven verify\non:\n  pull_request:\n    types: [ opened, reopened, edited ]\njobs:\n  mvn_verify:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - name: Set up Maven Central Repository\n        uses: actions/setup-java@v2\n        with:\n          java-version: '8'\n          distribution: 'adopt'\n      - name: Run the Maven verify phase\n        run: mvn --batch-mode --update-snapshots -P dev verify -Dsurefire.useFile=false -DdisableXmlReport=true\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Publish package to the Maven Central Repository\non:\n  push:\n    tags: [ \"*\" ]\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n      - name: Set up Maven Central Repository\n        uses: actions/setup-java@v2\n        with:\n          java-version: '8'\n          distribution: 'adopt'\n          server-id: ossrh\n          server-username: MAVEN_USERNAME\n          server-password: MAVEN_PASSWORD\n      - id: install-secret-key\n        name: Install gpg secret key\n        run: |\n          cat <(echo -e \"${{ secrets.OSSRH_GPG_SECRET_KEY }}\") | gpg --batch --import\n          gpg --list-secret-keys --keyid-format LONG\n      - name: Publish package\n        env:\n          MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}\n          MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}\n        run: |\n          mvn --batch-mode -Dgpg.passphrase=${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} -P release clean deploy\n"
  },
  {
    "path": ".gitignore",
    "content": "# Maven #\ntarget/\ndependency-reduced-pom.xml\n\n# IDEA #\n.idea/\n*.iml\n\n# Eclipse #\n.settings/\n.classpath\n.project\n\n.vscode/\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014-2022 abel533@gmail.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "![MyBatis Pagination - PageHelper](logo.png)\n# MyBatis 分页插件 - PageHelper\n\n[![Build Status](https://travis-ci.org/pagehelper/Mybatis-PageHelper.svg?branch=master)](https://travis-ci.org/pagehelper/Mybatis-PageHelper)\n[![Maven central](https://maven-badges.herokuapp.com/maven-central/com.github.pagehelper/pagehelper/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.pagehelper/pagehelper)\n\n[English](README_en.md)\n\n如果你也在用 MyBatis，建议尝试该分页插件，这一定是<b>最方便</b>使用的分页插件。\n\n分页插件支持任何复杂的单表、多表分页，部分特殊情况请看[重要提示](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Important.md)。\n\n想要使用分页插件？请看[如何使用分页插件](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md)。\n\n## 《MyBatis 从入门到精通》\n\n![MyBatis 从入门到精通](https://github.com/mybatis-book/book/raw/master/book.png)\n\n[京东](https://item.jd.com/12103309.html) ，[当当](http://product.dangdang.com/25098208.html)\n，[亚马逊](https://www.amazon.cn/MyBatis从入门到精通-刘增辉/dp/B072RC11DM/ref=sr_1_18?ie=UTF8&qid=1498007125&sr=8-18&keywords=mybatis)\n\nCSDN博客：http://blog.csdn.net/isea533/article/details/73555400\n\nGitHub项目：https://github.com/mybatis-book/book\n\n## 支持 [MyBatis 3.1.0+](https://github.com/mybatis/mybatis-3)\n\n## PageHelper 6 支持 jdk8+\n\n## PageHelper 5 支持 jdk6+\n\n## 物理分页\n\n该插件目前支持以下数据库的<b>物理分页</b> [PageAutoDialect](src/main/java/com/github/pagehelper/page/PageAutoDialect.java):\n\n```java\nstatic {\n    //注册别名\n    registerDialectAlias(\"hsqldb\",HsqldbDialect.class);\n    registerDialectAlias(\"h2\",HsqldbDialect.class);\n    registerDialectAlias(\"phoenix\",HsqldbDialect.class);\n\n    registerDialectAlias(\"postgresql\",PostgreSqlDialect.class);\n\n    registerDialectAlias(\"mysql\",MySqlDialect.class);\n    registerDialectAlias(\"mariadb\",MySqlDialect.class);\n    registerDialectAlias(\"sqlite\",MySqlDialect.class);\n\n    registerDialectAlias(\"herddb\",HerdDBDialect.class);\n\n    registerDialectAlias(\"oracle\",OracleDialect.class);\n    registerDialectAlias(\"oracle9i\",Oracle9iDialect.class);\n    registerDialectAlias(\"db2\",Db2Dialect.class);\n    registerDialectAlias(\"as400\",AS400Dialect.class);\n    registerDialectAlias(\"informix\",InformixDialect.class);\n    //解决 informix-sqli #129，仍然保留上面的\n    registerDialectAlias(\"informix-sqli\",InformixDialect.class);\n\n    registerDialectAlias(\"sqlserver\",SqlServerDialect.class);\n    registerDialectAlias(\"sqlserver2012\",SqlServer2012Dialect.class);\n\n    registerDialectAlias(\"derby\",SqlServer2012Dialect.class);\n    //达梦数据库,https://github.com/mybatis-book/book/issues/43\n    registerDialectAlias(\"dm\",OracleDialect.class);\n    //阿里云PPAS数据库,https://github.com/pagehelper/Mybatis-PageHelper/issues/281\n    registerDialectAlias(\"edb\",OracleDialect.class);\n    //神通数据库\n    registerDialectAlias(\"oscar\",OscarDialect.class);\n    registerDialectAlias(\"clickhouse\",MySqlDialect.class);\n    //瀚高数据库\n    registerDialectAlias(\"highgo\",HsqldbDialect.class);\n    //虚谷数据库\n    registerDialectAlias(\"xugu\",HsqldbDialect.class);\n    registerDialectAlias(\"impala\",HsqldbDialect.class);\n    registerDialectAlias(\"firebirdsql\",FirebirdDialect.class);\n    //人大金仓数据库\n    registerDialectAlias(\"kingbase\",PostgreSqlDialect.class);\n    // 人大金仓新版本kingbase8\n    registerDialectAlias(\"kingbase8\",PostgreSqlDialect.class);\n    //行云数据库\n    registerDialectAlias(\"xcloud\",CirroDataDialect.class);\n\n    //openGauss数据库\n    registerDialectAlias(\"opengauss\",PostgreSqlDialect.class);\n\n    //注册 AutoDialect\n    //想要实现和以前版本相同的效果时，可以配置 autoDialectClass=old\n    registerAutoDialectAlias(\"old\",DefaultAutoDialect.class);\n    registerAutoDialectAlias(\"hikari\",HikariAutoDialect.class);\n    registerAutoDialectAlias(\"druid\",DruidAutoDialect.class);\n    registerAutoDialectAlias(\"tomcat-jdbc\",TomcatAutoDialect.class);\n    registerAutoDialectAlias(\"dbcp\",DbcpAutoDialect.class);\n    registerAutoDialectAlias(\"c3p0\",C3P0AutoDialect.class);\n    //不配置时，默认使用 DataSourceNegotiationAutoDialect\n    registerAutoDialectAlias(\"default\",DataSourceNegotiationAutoDialect.class);\n}\n```\n\n> 如果你使用的数据库不在这个列表时，你可以配置 `dialectAlias` 参数。\n>\n>这个参数允许配置自定义实现的别名，可以用于根据 JDBCURL 自动获取对应实现，允许通过此种方式覆盖已有的实现，配置示例如（多个配置时使用分号隔开）：\n>\n>```xml\n><property name=\"dialectAlias\" value=\"oracle=com.github.pagehelper.dialect.helper.OracleDialect\"/>\n><!-- 6.0支持下面的引用方式，引用 Oracle9iDialect.class 的实现 -->\n><property name=\"dialectAlias\" value=\"oracle=oracle9i\"/>\n><!-- 6.0支持下面的引用方式，达梦使用oracle语法分页，简化类全名写法 -->\n><property name=\"dialectAlias\" value=\"dm=oracle\"/>\n>```\n\n## 使用 [QueryInterceptor 规范](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/src/main/java/com/github/pagehelper/QueryInterceptor.java)\n\n[Executor 拦截器高级教程 - QueryInterceptor 规范](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Interceptor.md)\n\n## 集成\n\n使用 PageHelper 你只需要在 classpath\n中包含 [pagehelper-x.y.z.jar](http://repo1.maven.org/maven2/com/github/pagehelper/pagehelper/)\n和 [jsqlparser-x.y.z.jar](http://repo1.maven.org/maven2/com/github/jsqlparser/jsqlparser/)。\n\n> pagehelper 和 jsqlparser 对应关系参考 pom.xml 中的依赖版本。\n\n如果你使用 Maven，你只需要在 pom.xml 中添加下面的依赖：\n\n```xml\n\n<dependency>\n    <groupId>com.github.pagehelper</groupId>\n    <artifactId>pagehelper</artifactId>\n    <version>最新版本</version>\n</dependency>\n```\n\n如果你使用 Spring Boot 可以参考： [pagehelper-spring-boot-starter](https://github.com/pagehelper/pagehelper-spring-boot)\n\n[继续查看配置和用法](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md)\n\n## 文档：\n\n- [如何使用分页插件](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md)\n- [更新日志](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Changelog.md)\n- [重要提示](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Important.md)\n\n## Spring 集成示例\n\n- [集成 Spring 3.x](https://github.com/abel533/Mybatis-Spring/tree/spring3.x)\n- [集成 Spring 4.x](https://github.com/abel533/Mybatis-Spring)\n- [集成 Spring Boot](https://github.com/abel533/MyBatis-Spring-Boot)\n\n## 提交 BUG\n\nhttps://github.com/pagehelper/Mybatis-PageHelper/issues/new\n\n## 微信公众号\n\n<img src=\"wx_mybatis.jpg\" height=\"300\"/>\n\n## 项目的发展离不开你的支持\n\n### 请作者喝杯咖啡吧！\n\n<img src=\"ali_pay.png\" height=\"300\"/>\n\n<img src=\"wx_pay.png\" height=\"300\"/>\n\n## 作者信息\n\n网站：https://mybatis.io\n\n作者博客：http://blog.csdn.net/isea533\n\n作者邮箱： abel533@gmail.com\n\n如需加群，请通过 http://mybatis.io 首页按钮加群。\n\n本项目在 github 的项目地址：https://github.com/pagehelper/Mybatis-PageHelper\n\n本项目在 gitosc 的项目地址：http://git.oschina.net/free/Mybatis_PageHelper\n\n## MyBatis-3\n\n- 项目：https://github.com/mybatis/mybatis-3\n- 文档：http://mybatis.github.io/mybatis-3/zh/index.html\n\nMyBatis 专栏：\n\n- [MyBatis示例](http://blog.csdn.net/column/details/mybatis-sample.html)\n- [MyBatis问题集](http://blog.csdn.net/column/details/mybatisqa.html)\n\n## 感谢所有项目贡献者！\n\n<a href=\"https://github.com/pagehelper/Mybatis-PageHelper/graphs/contributors\">\n  <img src=\"https://contributors-img.web.app/image?repo=pagehelper/Mybatis-PageHelper\" />\n</a>"
  },
  {
    "path": "README_en.md",
    "content": "![MyBatis Pagination - PageHelper](logo.png)\n\n# MyBatis Pagination - PageHelper\n\n[![Build Status](https://travis-ci.org/pagehelper/Mybatis-PageHelper.svg?branch=master)](https://travis-ci.org/pagehelper/Mybatis-PageHelper)\n[![Maven central](https://maven-badges.herokuapp.com/maven-central/com.github.pagehelper/pagehelper/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.pagehelper/pagehelper)\n\n[中文版文档](README.md)\n\nIf you are using MyBatis, it is recommended to try this pagination plugin. This must be the **MOST CONVENIENT**\npagination plugin.\n\nPageHelper supports any complex single-table, multi-table queries.\nAs to some special cases, please refer to the [**Important\nnote**](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/en/Important.md).\n\nWant to use PageHelper?\nPlease check out [**How to use\nPageHelper**](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/en/HowToUse.md).\n\n## New JavaDoc\n\nhttps://apidoc.gitee.com/free/Mybatis_PageHelper\n\nAPIs: https://apidoc.gitee.com/free/Mybatis_PageHelper/com/github/pagehelper/page/PageMethod.html\n\n## 《MyBatis 从入门到精通》\n\n![MyBatis 从入门到精通](https://github.com/mybatis-book/book/raw/master/book.png)\n\n[京东](https://item.jd.com/12103309.html) ，[当当](http://product.dangdang.com/25098208.html)\n，[Amazon](https://www.amazon.cn/MyBatis从入门到精通-刘增辉/dp/B072RC11DM/ref=sr_1_18?ie=UTF8&qid=1498007125&sr=8-18&keywords=mybatis)\n\nCSDN Blog：http://blog.csdn.net/isea533/article/details/73555400\n\nGitHub：https://github.com/mybatis-book/book\n\n## Support [MyBatis 3.1.0+](https://github.com/mybatis/mybatis-3)\n\n## PageHelper 6 Support jdk8+\n\n## PageHelper 5 Support jdk6+\n\n## Physical Paging\n\nPageHelper supports the following\ndatabases [PageAutoDialect](src/main/java/com/github/pagehelper/page/PageAutoDialect.java):\n\n```java\nstatic {\n    //register alias\n    registerDialectAlias(\"hsqldb\",HsqldbDialect.class);\n    registerDialectAlias(\"h2\",HsqldbDialect.class);\n    registerDialectAlias(\"phoenix\",HsqldbDialect.class);\n\n    registerDialectAlias(\"postgresql\",PostgreSqlDialect.class);\n\n    registerDialectAlias(\"mysql\",MySqlDialect.class);\n    registerDialectAlias(\"mariadb\",MySqlDialect.class);\n    registerDialectAlias(\"sqlite\",MySqlDialect.class);\n\n    registerDialectAlias(\"herddb\",HerdDBDialect.class);\n\n    registerDialectAlias(\"oracle\",OracleDialect.class);\n    registerDialectAlias(\"oracle9i\",Oracle9iDialect.class);\n    registerDialectAlias(\"db2\",Db2Dialect.class);\n    registerDialectAlias(\"as400\",AS400Dialect.class);\n    registerDialectAlias(\"informix\",InformixDialect.class);\n    //Solve informix-sqli #129, still keep the above\n    registerDialectAlias(\"informix-sqli\",InformixDialect.class);\n\n    registerDialectAlias(\"sqlserver\",SqlServerDialect.class);\n    registerDialectAlias(\"sqlserver2012\",SqlServer2012Dialect.class);\n\n    registerDialectAlias(\"derby\",SqlServer2012Dialect.class);\n    //达梦数据库,https://github.com/mybatis-book/book/issues/43\n    registerDialectAlias(\"dm\",OracleDialect.class);\n    //阿里云PPAS数据库,https://github.com/pagehelper/Mybatis-PageHelper/issues/281\n    registerDialectAlias(\"edb\",OracleDialect.class);\n    //神通数据库\n    registerDialectAlias(\"oscar\",OscarDialect.class);\n    registerDialectAlias(\"clickhouse\",MySqlDialect.class);\n    //瀚高数据库\n    registerDialectAlias(\"highgo\",HsqldbDialect.class);\n    //虚谷数据库\n    registerDialectAlias(\"xugu\",HsqldbDialect.class);\n    registerDialectAlias(\"impala\",HsqldbDialect.class);\n    registerDialectAlias(\"firebirdsql\",FirebirdDialect.class);\n    //人大金仓数据库\n    registerDialectAlias(\"kingbase\",PostgreSqlDialect.class);\n    // 人大金仓新版本kingbase8\n    registerDialectAlias(\"kingbase8\",PostgreSqlDialect.class);\n    //行云数据库\n    registerDialectAlias(\"xcloud\",CirroDataDialect.class);\n\n    //openGauss数据库\n    registerDialectAlias(\"opengauss\",PostgreSqlDialect.class);\n\n    //注册 AutoDialect\n    //If you want to achieve the same effect as the previous version, you can configure it autoDialectClass=old\n    registerAutoDialectAlias(\"old\",DefaultAutoDialect.class);\n    registerAutoDialectAlias(\"hikari\",HikariAutoDialect.class);\n    registerAutoDialectAlias(\"druid\",DruidAutoDialect.class);\n    registerAutoDialectAlias(\"tomcat-jdbc\",TomcatAutoDialect.class);\n    registerAutoDialectAlias(\"dbcp\",DbcpAutoDialect.class);\n    registerAutoDialectAlias(\"c3p0\",C3P0AutoDialect.class);\n    //If not configured, it is used by default DataSourceNegotiationAutoDialect\n    registerAutoDialectAlias(\"default\",DataSourceNegotiationAutoDialect.class);\n}\n```\n\n> If the database you are using is not in this list, you can configure the `dialectAlias` parameter.\n>\n> This parameter allows to configure the alias of a custom implementation,\n> which can be used to automatically obtain the corresponding implementation according to the JDBCURL,\n> and allows to overwrite the existing implementation in this way.\n> The configuration example is as follows (use semicolons to separate multiple alias):\n>\n>```xml\n><property name=\"dialectAlias\" value=\"oracle=com.github.pagehelper.dialect.helper.OracleDialect\"/>\n><!-- 6.0 The following reference is supported, referencing the implementation of Oracle9iDialect.class -->\n><property name=\"dialectAlias\" value=\"oracle=oracle9i\"/>\n><!-- 6.0 To support the following citation methods, DM uses oracle syntax for pagination to simplify the writing of the full name of the class -->\n><property name=\"dialectAlias\" value=\"dm=oracle\"/>\n>```\n\n## Use [QueryInterceptor spec](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/src/main/java/com/github/pagehelper/QueryInterceptor.java)\n\n## Installation\n\nTo use PageHelper, you just need to include the\n[pagehelper-x.y.z.jar](http://repo1.maven.org/maven2/com/github/pagehelper/pagehelper/)\nand [jsqlparser-x.y.z.jar](http://repo1.maven.org/maven2/com/github/jsqlparser/jsqlparser/) file in the classpath.\n\n> For version matching relation, please refer to the dependent version in pom.\n\nIf you are using Maven, you could just add the following dependency to your `pom.xml`:\n\n```xml\n\n<dependency>\n    <groupId>com.github.pagehelper</groupId>\n    <artifactId>pagehelper</artifactId>\n    <version>latest version</version>\n</dependency>\n```\n\nIf you are using Spring Boot, You can refer to\nthe [pagehelper-spring-boot-starter](https://github.com/pagehelper/pagehelper-spring-boot)\n\n[More...](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/en/HowToUse.md)\n\n## Documentation\n\n- [How to use the PageHelper](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/en/HowToUse.md)\n- [Changelog](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/en/Changelog.md)\n- [Important note](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/en/Important.md)\n\n## Spring integration sample\n\n- [Integration Spring 3.x](https://github.com/abel533/Mybatis-Spring/tree/spring3.x)\n- [Integration Spring 4.x](https://github.com/abel533/Mybatis-Spring)\n- [Integration Spring Boot](https://github.com/abel533/MyBatis-Spring-Boot)\n\n## Submit BUG\n\nhttps://github.com/pagehelper/Mybatis-PageHelper/issues/new\n\n## 微信公众号\n\n<img src=\"wx_mybatis.jpg\" height=\"300\"/>\n\n## Thank you for your support\n\n\n### Buy the author a cup of coffee!\n\n\n<img src=\"ali_pay.png\" height=\"300\"/>\n\n<img src=\"wx_pay.png\" height=\"300\"/>\n\n## Author Info\n\nWeb: https://mybatis.io\n\nBlog: http://blog.csdn.net/isea533\n\nEmail: abel533@gmail.com\n\nPageHelper on github:https://github.com/pagehelper/Mybatis-PageHelper\n\nPageHelper on gitosc:http://git.oschina.net/free/Mybatis_PageHelper\n\n## MyBatis-3\n\n- Project：https://github.com/mybatis/mybatis-3\n- Document：https://mybatis.org/mybatis-3/index.html\n\nMyBatis 专栏：\n\n- [MyBatis Sample](http://blog.csdn.net/column/details/mybatis-sample.html)\n- [MyBatis QA](http://blog.csdn.net/column/details/mybatisqa.html)\n\n## Thanks to all the people who already contributed!\n\n<a href=\"https://github.com/pagehelper/Mybatis-PageHelper/graphs/contributors\">\n  <img src=\"https://contributors-img.web.app/image?repo=pagehelper/Mybatis-PageHelper\" />\n</a>"
  },
  {
    "path": "jsqlparser4_7兼容性改动.patch",
    "content": "Subject: [PATCH] jsqlparser4.7兼容性改动\n---\nIndex: src/main/java/com/github/pagehelper/parser/OrderByParser.java\nIDEA additional info:\nSubsystem: com.intellij.openapi.diff.impl.patch.CharsetEP\n<+>UTF-8\n===================================================================\ndiff --git a/src/main/java/com/github/pagehelper/parser/OrderByParser.java b/src/main/java/com/github/pagehelper/parser/OrderByParser.java\n--- a/src/main/java/com/github/pagehelper/parser/OrderByParser.java\t(revision 1ae113e493b480452c69af931124ebd5c1ce09f6)\n+++ b/src/main/java/com/github/pagehelper/parser/OrderByParser.java\t(date 1700463025360)\n@@ -56,9 +56,8 @@\n         try {\n             stmt = jSqlParser.parse(sql);\n             Select select = (Select) stmt;\n-            SelectBody selectBody = select.getSelectBody();\n             //处理body-去最外层order by\n-            List<OrderByElement> orderByElements = extraOrderBy(selectBody);\n+            List<OrderByElement> orderByElements = extraOrderBy(select);\n             String defaultOrderBy = PlainSelect.orderByToString(orderByElements);\n             if (defaultOrderBy.indexOf('?') != -1) {\n                 throw new PageException(\"The order by in the original SQL[\" + sql + \"] contains parameters, so it cannot be modified using the OrderBy plugin!\");\n@@ -85,25 +84,16 @@\n     /**\n      * extra order by and set default orderby to null\n      *\n-     * @param selectBody\n+     * @param select\n      */\n-    public static List<OrderByElement> extraOrderBy(SelectBody selectBody) {\n-        if (selectBody != null) {\n-            if (selectBody instanceof PlainSelect) {\n-                List<OrderByElement> orderByElements = ((PlainSelect) selectBody).getOrderByElements();\n-                ((PlainSelect) selectBody).setOrderByElements(null);\n+    public static List<OrderByElement> extraOrderBy(Select select) {\n+        if (select != null) {\n+            if (select instanceof PlainSelect || select instanceof SetOperationList) {\n+                List<OrderByElement> orderByElements = select.getOrderByElements();\n+                select.setOrderByElements(null);\n                 return orderByElements;\n-            } else if (selectBody instanceof WithItem) {\n-                WithItem withItem = (WithItem) selectBody;\n-                if (withItem.getSubSelect() != null) {\n-                    return extraOrderBy(withItem.getSubSelect().getSelectBody());\n-                }\n-            } else {\n-                SetOperationList operationList = (SetOperationList) selectBody;\n-                if (operationList.getSelects() != null && operationList.getSelects().size() > 0) {\n-                    List<SelectBody> plainSelects = operationList.getSelects();\n-                    return extraOrderBy(plainSelects.get(plainSelects.size() - 1));\n-                }\n+            } else if (select instanceof ParenthesedSelect) {\n+                extraOrderBy(((ParenthesedSelect) select).getSelect());\n             }\n         }\n         return null;\nIndex: src/main/java/com/github/pagehelper/parser/SqlServerParser.java\nIDEA additional info:\nSubsystem: com.intellij.openapi.diff.impl.patch.CharsetEP\n<+>UTF-8\n===================================================================\ndiff --git a/src/main/java/com/github/pagehelper/parser/SqlServerParser.java b/src/main/java/com/github/pagehelper/parser/SqlServerParser.java\n--- a/src/main/java/com/github/pagehelper/parser/SqlServerParser.java\t(revision 1ae113e493b480452c69af931124ebd5c1ce09f6)\n+++ b/src/main/java/com/github/pagehelper/parser/SqlServerParser.java\t(date 1700466304213)\n@@ -138,64 +138,62 @@\n      * @return\n      */\n     protected Select getPageSelect(Select select) {\n-        SelectBody selectBody = select.getSelectBody();\n-        if (selectBody instanceof SetOperationList) {\n-            selectBody = wrapSetOperationList((SetOperationList) selectBody);\n+        if (select instanceof SetOperationList) {\n+            select = wrapSetOperationList((SetOperationList) select);\n         }\n         //这里的selectBody一定是PlainSelect\n-        if (((PlainSelect) selectBody).getTop() != null) {\n+        if (((PlainSelect) select).getTop() != null) {\n             throw new PageException(\"The pagination statement already contains the top, and can no longer be used to query the pagination plugin!\");\n         }\n         //获取查询列\n-        List<SelectItem> selectItems = getSelectItems((PlainSelect) selectBody);\n+        List<SelectItem<?>> selectItems = getSelectItems((PlainSelect) select);\n         //对一层的SQL增加ROW_NUMBER()\n-        List<SelectItem> autoItems = new ArrayList<SelectItem>();\n-        SelectItem orderByColumn = addRowNumber((PlainSelect) selectBody, autoItems);\n+        List<SelectItem<?>> autoItems = new ArrayList<>();\n+        SelectItem<?> orderByColumn = addRowNumber((PlainSelect) select, autoItems);\n         //加入自动生成列\n-        ((PlainSelect) selectBody).addSelectItems(autoItems.toArray(new SelectItem[autoItems.size()]));\n+        ((PlainSelect) select).addSelectItems(autoItems.toArray(new SelectItem[0]));\n         //处理子语句中的order by\n-        processSelectBody(selectBody, 0);\n+        processSelectBody(select, 0);\n \n         //中层子查询\n         PlainSelect innerSelectBody = new PlainSelect();\n         //PAGE_ROW_NUMBER\n         innerSelectBody.addSelectItems(orderByColumn);\n-        innerSelectBody.addSelectItems(selectItems.toArray(new SelectItem[selectItems.size()]));\n+        innerSelectBody.addSelectItems(selectItems.toArray(new SelectItem[0]));\n         //将原始查询作为内层子查询\n-        SubSelect fromInnerItem = new SubSelect();\n-        fromInnerItem.setSelectBody(selectBody);\n+        ParenthesedSelect fromInnerItem = new ParenthesedSelect();\n+        fromInnerItem.setSelect(select);\n         fromInnerItem.setAlias(PAGE_TABLE_ALIAS);\n         innerSelectBody.setFromItem(fromInnerItem);\n \n         //新建一个select\n-        Select newSelect = new Select();\n-        PlainSelect newSelectBody = new PlainSelect();\n+        PlainSelect newSelect = new PlainSelect();\n         //设置top\n         Top top = new Top();\n         top.setExpression(new LongValue(Long.MAX_VALUE));\n-        newSelectBody.setTop(top);\n+        newSelect.setTop(top);\n         //设置order by\n         List<OrderByElement> orderByElements = new ArrayList<OrderByElement>();\n         OrderByElement orderByElement = new OrderByElement();\n         orderByElement.setExpression(PAGE_ROW_NUMBER_COLUMN);\n         orderByElements.add(orderByElement);\n-        newSelectBody.setOrderByElements(orderByElements);\n+        newSelect.setOrderByElements(orderByElements);\n         //设置where\n         GreaterThan greaterThan = new GreaterThan();\n         greaterThan.setLeftExpression(PAGE_ROW_NUMBER_COLUMN);\n         greaterThan.setRightExpression(new LongValue(Long.MIN_VALUE));\n-        newSelectBody.setWhere(greaterThan);\n+        newSelect.setWhere(greaterThan);\n         //设置selectItems\n-        newSelectBody.setSelectItems(selectItems);\n+        newSelect.setSelectItems(selectItems);\n         //设置fromIterm\n-        SubSelect fromItem = new SubSelect();\n-        fromItem.setSelectBody(innerSelectBody); //中层子查询\n+        ParenthesedSelect fromItem = new ParenthesedSelect();\n+        fromItem.setSelect(innerSelectBody); //中层子查询\n         fromItem.setAlias(PAGE_TABLE_ALIAS);\n-        newSelectBody.setFromItem(fromItem);\n+        newSelect.setFromItem(fromItem);\n \n-        newSelect.setSelectBody(newSelectBody);\n         if (isNotEmptyList(select.getWithItemsList())) {\n             newSelect.setWithItemsList(select.getWithItemsList());\n+            select.setWithItemsList(null);\n         }\n         return newSelect;\n     }\n@@ -206,20 +204,20 @@\n      * @param setOperationList\n      * @return\n      */\n-    protected SelectBody wrapSetOperationList(SetOperationList setOperationList) {\n+    protected Select wrapSetOperationList(SetOperationList setOperationList) {\n         //获取最后一个plainSelect\n-        SelectBody setSelectBody = setOperationList.getSelects().get(setOperationList.getSelects().size() - 1);\n+        Select setSelectBody = setOperationList.getSelects().get(setOperationList.getSelects().size() - 1);\n         if (!(setSelectBody instanceof PlainSelect)) {\n             throw new PageException(\"Unable to process the SQL, you can submit issues in GitHub for help.!\");\n         }\n         PlainSelect plainSelect = (PlainSelect) setSelectBody;\n         PlainSelect selectBody = new PlainSelect();\n-        List<SelectItem> selectItems = getSelectItems(plainSelect);\n+        List<SelectItem<?>> selectItems = getSelectItems(plainSelect);\n         selectBody.setSelectItems(selectItems);\n \n         //设置fromIterm\n-        SubSelect fromItem = new SubSelect();\n-        fromItem.setSelectBody(setOperationList);\n+        ParenthesedSelect fromItem = new ParenthesedSelect();\n+        fromItem.setSelect(setOperationList);\n         fromItem.setAlias(new Alias(WRAP_TABLE));\n         selectBody.setFromItem(fromItem);\n         //order by\n@@ -236,33 +234,27 @@\n      * @param plainSelect\n      * @return\n      */\n-    protected List<SelectItem> getSelectItems(PlainSelect plainSelect) {\n+    protected List<SelectItem<?>> getSelectItems(PlainSelect plainSelect) {\n         //设置selectItems\n-        List<SelectItem> selectItems = new ArrayList<SelectItem>();\n-        for (SelectItem selectItem : plainSelect.getSelectItems()) {\n-            //别名需要特殊处理\n-            if (selectItem instanceof SelectExpressionItem) {\n-                SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem;\n-                if (selectExpressionItem.getAlias() != null) {\n-                    //直接使用别名\n-                    Column column = new Column(selectExpressionItem.getAlias().getName());\n-                    SelectExpressionItem expressionItem = new SelectExpressionItem(column);\n-                    selectItems.add(expressionItem);\n-                } else if (selectExpressionItem.getExpression() instanceof Column) {\n-                    Column column = (Column) selectExpressionItem.getExpression();\n-                    SelectExpressionItem item = null;\n-                    if (column.getTable() != null) {\n-                        Column newColumn = new Column(column.getColumnName());\n-                        item = new SelectExpressionItem(newColumn);\n-                        selectItems.add(item);\n-                    } else {\n-                        selectItems.add(selectItem);\n-                    }\n+        List<SelectItem<?>> selectItems = new ArrayList<>();\n+        for (SelectItem<?> selectItem : plainSelect.getSelectItems()) {\n+            if (selectItem.getExpression() instanceof AllTableColumns) {\n+                selectItems.add(new SelectItem<>(new AllColumns()));\n+            } else if (selectItem.getAlias() != null) {\n+                //直接使用别名\n+                Column column = new Column(selectItem.getAlias().getName());\n+                SelectItem<?> expressionItem = new SelectItem<>(column);\n+                selectItems.add(expressionItem);\n+            } else if (selectItem.getExpression() instanceof Column) {\n+                Column column = (Column) selectItem.getExpression();\n+                SelectItem<?> item = null;\n+                if (column.getTable() != null) {\n+                    Column newColumn = new Column(column.getColumnName());\n+                    item = new SelectItem<>(newColumn);\n+                    selectItems.add(item);\n                 } else {\n                     selectItems.add(selectItem);\n                 }\n-            } else if (selectItem instanceof AllTableColumns) {\n-                selectItems.add(new AllColumns());\n             } else {\n                 selectItems.add(selectItem);\n             }\n@@ -272,8 +264,8 @@\n         // SELECT * FROM (SELECT *, 1 AS alias FROM TEST)\n         // 不应该为\n         // SELECT *, alias FROM (SELECT *, 1 AS alias FROM TEST)\n-        for (SelectItem selectItem : selectItems) {\n-            if (selectItem instanceof AllColumns) {\n+        for (SelectItem<?> selectItem : selectItems) {\n+            if (selectItem.getExpression() instanceof AllColumns) {\n                 return Collections.singletonList(selectItem);\n             }\n         }\n@@ -287,7 +279,7 @@\n      * @param autoItems   自动生成的查询列\n      * @return ROW_NUMBER() 列\n      */\n-    protected SelectItem addRowNumber(PlainSelect plainSelect, List<SelectItem> autoItems) {\n+    protected SelectItem<?> addRowNumber(PlainSelect plainSelect, List<SelectItem<?>> autoItems) {\n         //增加ROW_NUMBER()\n         StringBuilder orderByBuilder = new StringBuilder();\n         orderByBuilder.append(\"ROW_NUMBER() OVER (\");\n@@ -301,28 +293,28 @@\n         }\n         orderByBuilder.append(\") \");\n         orderByBuilder.append(PAGE_ROW_NUMBER);\n-        return new SelectExpressionItem(new Column(orderByBuilder.toString()));\n+        return new SelectItem<>(new Column(orderByBuilder.toString()));\n     }\n \n     /**\n      * 处理selectBody去除Order by\n      *\n-     * @param selectBody\n+     * @param select\n      */\n-    protected void processSelectBody(SelectBody selectBody, int level) {\n-        if (selectBody != null) {\n-            if (selectBody instanceof PlainSelect) {\n-                processPlainSelect((PlainSelect) selectBody, level + 1);\n-            } else if (selectBody instanceof WithItem) {\n-                WithItem withItem = (WithItem) selectBody;\n-                if (withItem.getSubSelect() != null) {\n-                    processSelectBody(withItem.getSubSelect().getSelectBody(), level + 1);\n+    protected void processSelectBody(Select select, int level) {\n+        if (select != null) {\n+            if (select instanceof PlainSelect) {\n+                processPlainSelect((PlainSelect) select, level + 1);\n+            } else if (select instanceof WithItem) {\n+                WithItem withItem = (WithItem) select;\n+                if (withItem.getSelect() != null) {\n+                    processSelectBody(withItem.getSelect(), level + 1);\n                 }\n             } else {\n-                SetOperationList operationList = (SetOperationList) selectBody;\n-                if (operationList.getSelects() != null && operationList.getSelects().size() > 0) {\n-                    List<SelectBody> plainSelects = operationList.getSelects();\n-                    for (SelectBody plainSelect : plainSelects) {\n+                SetOperationList operationList = (SetOperationList) select;\n+                if (operationList.getSelects() != null && !operationList.getSelects().isEmpty()) {\n+                    List<Select> plainSelects = operationList.getSelects();\n+                    for (Select plainSelect : plainSelects) {\n                         processSelectBody(plainSelect, level + 1);\n                     }\n                 }\n@@ -346,7 +338,7 @@\n         if (plainSelect.getFromItem() != null) {\n             processFromItem(plainSelect.getFromItem(), level + 1);\n         }\n-        if (plainSelect.getJoins() != null && plainSelect.getJoins().size() > 0) {\n+        if (plainSelect.getJoins() != null && !plainSelect.getJoins().isEmpty()) {\n             List<Join> joins = plainSelect.getJoins();\n             for (Join join : joins) {\n                 if (join.getRightItem() != null) {\n@@ -362,33 +354,14 @@\n      * @param fromItem\n      */\n     protected void processFromItem(FromItem fromItem, int level) {\n-        if (fromItem instanceof SubJoin) {\n-            SubJoin subJoin = (SubJoin) fromItem;\n-            if (subJoin.getJoinList() != null && subJoin.getJoinList().size() > 0) {\n-                for (Join join : subJoin.getJoinList()) {\n-                    if (join.getRightItem() != null) {\n-                        processFromItem(join.getRightItem(), level + 1);\n-                    }\n-                }\n-            }\n-            if (subJoin.getLeft() != null) {\n-                processFromItem(subJoin.getLeft(), level + 1);\n-            }\n-        } else if (fromItem instanceof SubSelect) {\n-            SubSelect subSelect = (SubSelect) fromItem;\n-            if (subSelect.getSelectBody() != null) {\n-                processSelectBody(subSelect.getSelectBody(), level + 1);\n-            }\n-        } else if (fromItem instanceof ValuesList) {\n-\n-        } else if (fromItem instanceof LateralSubSelect) {\n-            LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem;\n-            if (lateralSubSelect.getSubSelect() != null) {\n-                SubSelect subSelect = lateralSubSelect.getSubSelect();\n-                if (subSelect.getSelectBody() != null) {\n-                    processSelectBody(subSelect.getSelectBody(), level + 1);\n-                }\n-            }\n+        if (fromItem instanceof LateralSubSelect) {\n+            processSelectBody(((LateralSubSelect) fromItem).getSelect(), level + 1);\n+        } else if (fromItem instanceof ParenthesedSelect) {\n+            processSelectBody(((ParenthesedSelect) fromItem).getSelect(), level + 1);\n+        } else if (fromItem instanceof Select) {\n+            processSelectBody((Select) fromItem, level + 1);\n+        }  else if (fromItem instanceof ParenthesedFromItem) {\n+            processFromItem(((ParenthesedFromItem) fromItem).getFromItem(), level + 1);\n         }\n         //Table时不用处理\n     }\n@@ -400,7 +373,7 @@\n      * @return\n      */\n     public boolean isNotEmptyList(List<?> list) {\n-        if (list == null || list.size() == 0) {\n+        if (list == null || list.isEmpty()) {\n             return false;\n         }\n         return true;\n@@ -441,13 +414,13 @@\n      * @return 新的排序列表\n      */\n     protected List<OrderByElement> getOrderByElements(PlainSelect plainSelect,\n-                                                      List<SelectItem> autoItems) {\n+                                                      List<SelectItem<?>> autoItems) {\n         List<OrderByElement> orderByElements = plainSelect.getOrderByElements();\n         ListIterator<OrderByElement> iterator = orderByElements.listIterator();\n         OrderByElement orderByElement;\n \n         // 非 `*` 且 非 `t.*` 查询列集合\n-        Map<String, SelectExpressionItem> selectMap = new HashMap<String, SelectExpressionItem>();\n+        Map<String, SelectItem<?>> selectMap = new HashMap<>();\n         // 别名集合\n         Set<String> aliases = new HashSet<String>();\n         // 是否包含 `*` 查询列\n@@ -455,21 +428,18 @@\n         // `t.*` 查询列的表名集合\n         Set<String> allColumnsTables = new HashSet<String>();\n \n-        for (SelectItem item : plainSelect.getSelectItems()) {\n-            if (item instanceof SelectExpressionItem) {\n-                SelectExpressionItem expItem = (SelectExpressionItem) item;\n-                selectMap.put(expItem.getExpression().toString(), expItem);\n-\n-                Alias alias = expItem.getAlias();\n+        for (SelectItem<?> item : plainSelect.getSelectItems()) {\n+            Expression expression = item.getExpression();\n+            if (expression instanceof AllTableColumns) {\n+                allColumnsTables.add(((AllTableColumns) expression).getTable().getName());\n+            } else if (expression instanceof AllColumns) {\n+                allColumns = true;\n+            } else {\n+                selectMap.put(expression.toString(), item);\n+                Alias alias = item.getAlias();\n                 if (alias != null) {\n                     aliases.add(alias.getName());\n                 }\n-\n-            } else if (item instanceof AllColumns) {\n-                allColumns = true;\n-\n-            } else if (item instanceof AllTableColumns) {\n-                allColumnsTables.add(((AllTableColumns) item).getTable().getName());\n             }\n         }\n \n@@ -478,7 +448,7 @@\n         while (iterator.hasNext()) {\n             orderByElement = iterator.next();\n             Expression expression = orderByElement.getExpression();\n-            SelectExpressionItem selectExpressionItem = selectMap.get(expression.toString());\n+            SelectItem<?> selectExpressionItem = selectMap.get(expression.toString());\n             if (selectExpressionItem != null) { // OrderByElement 在查询列表中\n                 Alias alias = selectExpressionItem.getAlias();\n                 if (alias != null) { // 查询列含有别名时用查询列别名\n@@ -527,8 +497,7 @@\n                 // 将排序列加入查询列中\n                 String aliasName = PAGE_COLUMN_ALIAS_PREFIX + aliasNo++;\n \n-                SelectExpressionItem item = new SelectExpressionItem();\n-                item.setExpression(expression);\n+                SelectItem<?> item = new SelectItem<>(expression);\n                 item.setAlias(new Alias(aliasName));\n                 autoItems.add(item);\n \nIndex: src/test/java/com/github/pagehelper/sql/FunctionCountTest.java\nIDEA additional info:\nSubsystem: com.intellij.openapi.diff.impl.patch.CharsetEP\n<+>UTF-8\n===================================================================\ndiff --git a/src/test/java/com/github/pagehelper/sql/FunctionCountTest.java b/src/test/java/com/github/pagehelper/sql/FunctionCountTest.java\n--- a/src/test/java/com/github/pagehelper/sql/FunctionCountTest.java\t(revision 1ae113e493b480452c69af931124ebd5c1ce09f6)\n+++ b/src/test/java/com/github/pagehelper/sql/FunctionCountTest.java\t(date 1700464930289)\n@@ -31,7 +31,6 @@\n import net.sf.jsqlparser.statement.Statement;\n import net.sf.jsqlparser.statement.select.PlainSelect;\n import net.sf.jsqlparser.statement.select.Select;\n-import net.sf.jsqlparser.statement.select.SelectExpressionItem;\n import net.sf.jsqlparser.statement.select.SelectItem;\n import org.junit.Test;\n \n@@ -57,17 +56,13 @@\n     @Test\n     public void test() {\n         Select select = select(\"select max(name),code,min(aa),nvl(ab,0),heh from user where a > 100\");\n-        List<SelectItem> selectItems = ((PlainSelect) select.getSelectBody()).getSelectItems();\n+        List<SelectItem<?>> selectItems = ((PlainSelect) select.getSelectBody()).getSelectItems();\n         for (SelectItem item : selectItems) {\n-            if (item instanceof SelectExpressionItem) {\n-                Expression exp = ((SelectExpressionItem) item).getExpression();\n-                if (exp instanceof Function) {\n-                    System.out.println(\"Function:\" + item.toString());\n-                } else {\n-                    System.out.println(\"Not a function:\" + exp.toString());\n-                }\n-            } else {\n-                System.out.println(\"Not a function:\" + item.toString());\n+            Expression exp = item.getExpression();\n+            if (exp instanceof Function) {\n+                System.out.println(\"Function:\" + item.toString());\n+            } else {\n+                System.out.println(\"Not a function:\" + exp.toString());\n             }\n         }\n     }\n@@ -75,9 +70,9 @@\n     @Test\n     public void test2() {\n         Select select = select(\"select distinct(name) from user where a > 100\");\n-        List<SelectItem> selectItems = ((PlainSelect) select.getSelectBody()).getSelectItems();\n+        List<SelectItem<?>> selectItems = ((PlainSelect) select.getSelectBody()).getSelectItems();\n         for (SelectItem item : selectItems) {\n-            if (item instanceof Function) {\n+            if (item.getExpression() instanceof Function) {\n                 System.out.println(\"Function:\" + item.toString());\n             } else {\n                 System.out.println(\"Not a function:\" + item.toString());\nIndex: src/test/java/com/github/pagehelper/sql/SqlTest.java\nIDEA additional info:\nSubsystem: com.intellij.openapi.diff.impl.patch.CharsetEP\n<+>UTF-8\n===================================================================\ndiff --git a/src/test/java/com/github/pagehelper/sql/SqlTest.java b/src/test/java/com/github/pagehelper/sql/SqlTest.java\n--- a/src/test/java/com/github/pagehelper/sql/SqlTest.java\t(revision 1ae113e493b480452c69af931124ebd5c1ce09f6)\n+++ b/src/test/java/com/github/pagehelper/sql/SqlTest.java\t(date 1700463025400)\n@@ -30,7 +30,6 @@\n import net.sf.jsqlparser.parser.CCJSqlParserUtil;\n import net.sf.jsqlparser.statement.Statement;\n import net.sf.jsqlparser.statement.select.Select;\n-import net.sf.jsqlparser.statement.select.SelectBody;\n import org.junit.Assert;\n import org.junit.Test;\n \n@@ -158,8 +157,7 @@\n             return;\n         }\n         Select select = (Select) stmt;\n-        SelectBody selectBody = select.getSelectBody();\n-        sql = selectBody.toString();\n+        sql = select.toString();\n \n         sql = sql.replaceAll(\"\\\\s*(\\\\w*?)_PAGEWITHNOLOCK\", \" $1 WITH(NOLOCK)\");\n         Assert.assertEquals(\"SELECT * FROM A WITH(NOLOCK) INNER JOIN B WITH(NOLOCK) ON A.TypeId = B.Id\", sql);\nIndex: pom.xml\nIDEA additional info:\nSubsystem: com.intellij.openapi.diff.impl.patch.CharsetEP\n<+>UTF-8\n===================================================================\ndiff --git a/pom.xml b/pom.xml\n--- a/pom.xml\t(revision 1ae113e493b480452c69af931124ebd5c1ce09f6)\n+++ b/pom.xml\t(date 1700442371317)\n@@ -56,7 +56,7 @@\n     </scm>\n \n     <properties>\n-        <pagehelper-version>6.0.1-SNAPSHOT</pagehelper-version>\n+        <pagehelper-version>6.0.1</pagehelper-version>\n         <version-suffix></version-suffix>\n \n         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n@@ -68,7 +68,7 @@\n         <dependency>\n             <groupId>com.github.jsqlparser</groupId>\n             <artifactId>jsqlparser</artifactId>\n-            <version>4.5</version>\n+            <version>4.7</version>\n         </dependency>\n         <dependency>\n             <groupId>org.mybatis</groupId>\nIndex: src/main/java/com/github/pagehelper/parser/DefaultCountSqlParser.java\nIDEA additional info:\nSubsystem: com.intellij.openapi.diff.impl.patch.CharsetEP\n<+>UTF-8\n===================================================================\ndiff --git a/src/main/java/com/github/pagehelper/parser/DefaultCountSqlParser.java b/src/main/java/com/github/pagehelper/parser/DefaultCountSqlParser.java\n--- a/src/main/java/com/github/pagehelper/parser/DefaultCountSqlParser.java\t(revision 1ae113e493b480452c69af931124ebd5c1ce09f6)\n+++ b/src/main/java/com/github/pagehelper/parser/DefaultCountSqlParser.java\t(date 1700465554724)\n@@ -85,10 +85,9 @@\n             return getSimpleCountSql(sql, countColumn);\n         }\n         Select select = (Select) stmt;\n-        SelectBody selectBody = select.getSelectBody();\n         try {\n             //处理body-去order by\n-            processSelectBody(selectBody);\n+            processSelect(select);\n         } catch (Exception e) {\n             //当 sql 包含 group by 时，不去除 order by\n             return getSimpleCountSql(sql, countColumn);\n@@ -96,10 +95,10 @@\n         //处理with-去order by\n         processWithItemsList(select.getWithItemsList());\n         //处理为count查询\n-        sqlToCount(select, countColumn);\n-        String result = select.toString();\n-        if (selectBody instanceof PlainSelect) {\n-            Token token = ((PlainSelect) selectBody).getASTNode().jjtGetFirstToken().specialToken;\n+        Select countSelect = sqlToCount(select, countColumn);\n+        String result = countSelect.toString();\n+        if (select instanceof PlainSelect) {\n+            Token token = select.getASTNode().jjtGetFirstToken().specialToken;\n             if (token != null) {\n                 String hints = token.toString().trim();\n                 // 这里判断是否存在hint, 且result是不包含hint的\n@@ -142,21 +141,25 @@\n      *\n      * @param select\n      */\n-    public void sqlToCount(Select select, String name) {\n-        SelectBody selectBody = select.getSelectBody();\n+    public Select sqlToCount(Select select, String name) {\n         // 是否能简化count查询\n-        List<SelectItem> COUNT_ITEM = new ArrayList<SelectItem>();\n-        COUNT_ITEM.add(new SelectExpressionItem(new Column(\"count(\" + name + \")\")));\n-        if (selectBody instanceof PlainSelect && isSimpleCount((PlainSelect) selectBody)) {\n-            ((PlainSelect) selectBody).setSelectItems(COUNT_ITEM);\n+        List<SelectItem<?>> COUNT_ITEM = new ArrayList<>();\n+        COUNT_ITEM.add(new SelectItem(new Column(\"count(\" + name + \")\")));\n+        if (select instanceof PlainSelect && isSimpleCount((PlainSelect) select)) {\n+            ((PlainSelect) select).setSelectItems(COUNT_ITEM);\n+            return select;\n         } else {\n             PlainSelect plainSelect = new PlainSelect();\n-            SubSelect subSelect = new SubSelect();\n-            subSelect.setSelectBody(selectBody);\n+            ParenthesedSelect subSelect = new ParenthesedSelect();\n+            subSelect.setSelect(select);\n             subSelect.setAlias(TABLE_ALIAS);\n             plainSelect.setFromItem(subSelect);\n             plainSelect.setSelectItems(COUNT_ITEM);\n-            select.setSelectBody(plainSelect);\n+            if(select.getWithItemsList() != null) {\n+                plainSelect.setWithItemsList(select.getWithItemsList());\n+                select.setWithItemsList(null);\n+            }\n+            return plainSelect;\n         }\n     }\n \n@@ -179,37 +182,35 @@\n         if (select.getHaving() != null) {\n             return false;\n         }\n-        for (SelectItem item : select.getSelectItems()) {\n+        for (SelectItem<?> item : select.getSelectItems()) {\n             //select列中包含参数的时候不可以，否则会引起参数个数错误\n             if (item.toString().contains(\"?\")) {\n                 return false;\n             }\n             //如果查询列中包含函数，也不可以，函数可能会聚合列\n-            if (item instanceof SelectExpressionItem) {\n-                Expression expression = ((SelectExpressionItem) item).getExpression();\n-                if (expression instanceof Function) {\n-                    String name = ((Function) expression).getName();\n-                    if (name != null) {\n-                        String NAME = name.toUpperCase();\n-                        if (skipFunctions.contains(NAME)) {\n-                            //go on\n-                        } else if (falseFunctions.contains(NAME)) {\n-                            return false;\n-                        } else {\n-                            for (String aggregateFunction : AGGREGATE_FUNCTIONS) {\n-                                if (NAME.startsWith(aggregateFunction)) {\n-                                    falseFunctions.add(NAME);\n-                                    return false;\n-                                }\n-                            }\n-                            skipFunctions.add(NAME);\n-                        }\n-                    }\n-                } else if (expression instanceof Parenthesis && ((SelectExpressionItem) item).getAlias() != null) {\n-                    //#555，当存在 (a+b) as c 时，c 如果出现了 order by 或者 having 中时，会找不到对应的列，\n-                    // 这里想要更智能，需要在整个SQL中查找别名出现的位置，暂时不考虑，直接排除\n-                    return false;\n-                }\n+            Expression expression = item.getExpression();\n+            if (expression instanceof Function) {\n+                String name = ((Function) expression).getName();\n+                if (name != null) {\n+                    String NAME = name.toUpperCase();\n+                    if (skipFunctions.contains(NAME)) {\n+                        //go on\n+                    } else if (falseFunctions.contains(NAME)) {\n+                        return false;\n+                    } else {\n+                        for (String aggregateFunction : AGGREGATE_FUNCTIONS) {\n+                            if (NAME.startsWith(aggregateFunction)) {\n+                                falseFunctions.add(NAME);\n+                                return false;\n+                            }\n+                        }\n+                        skipFunctions.add(NAME);\n+                    }\n+                }\n+            } else if (expression instanceof Parenthesis && item.getAlias() != null) {\n+                //#555，当存在 (a+b) as c 时，c 如果出现了 order by 或者 having 中时，会找不到对应的列，\n+                // 这里想要更智能，需要在整个SQL中查找别名出现的位置，暂时不考虑，直接排除\n+                return false;\n             }\n         }\n         return true;\n@@ -218,29 +219,31 @@\n     /**\n      * 处理selectBody去除Order by\n      *\n-     * @param selectBody\n+     * @param select\n      */\n-    public void processSelectBody(SelectBody selectBody) {\n-        if (selectBody != null) {\n-            if (selectBody instanceof PlainSelect) {\n-                processPlainSelect((PlainSelect) selectBody);\n-            } else if (selectBody instanceof WithItem) {\n+    public void processSelect(Select select) {\n+        if (select != null) {\n+            if (select instanceof PlainSelect) {\n+                processPlainSelect((PlainSelect) select);\n+            } else if (select instanceof ParenthesedSelect) {\n+                processSelect(((ParenthesedSelect) select).getSelect());\n+            } else if (select instanceof SetOperationList) {\n+                List<Select> selects = ((SetOperationList) select).getSelects();\n+                for (Select sel : selects) {\n+                    processSelect(sel);\n+                }\n+                if (!orderByHashParameters(select.getOrderByElements())) {\n+                    select.setOrderByElements(null);\n+                }\n+            }\n+            /*\n+            if (select instanceof WithItem) {\n                 WithItem withItem = (WithItem) selectBody;\n                 if (withItem.getSubSelect() != null && !keepSubSelectOrderBy()) {\n                     processSelectBody(withItem.getSubSelect().getSelectBody());\n                 }\n-            } else {\n-                SetOperationList operationList = (SetOperationList) selectBody;\n-                if (operationList.getSelects() != null && operationList.getSelects().size() > 0) {\n-                    List<SelectBody> plainSelects = operationList.getSelects();\n-                    for (SelectBody plainSelect : plainSelects) {\n-                        processSelectBody(plainSelect);\n-                    }\n-                }\n-                if (!orderByHashParameters(operationList.getOrderByElements())) {\n-                    operationList.setOrderByElements(null);\n-                }\n             }\n+             */\n         }\n     }\n \n@@ -272,10 +275,10 @@\n      * @param withItemsList\n      */\n     public void processWithItemsList(List<WithItem> withItemsList) {\n-        if (withItemsList != null && withItemsList.size() > 0) {\n+        if (withItemsList != null && !withItemsList.isEmpty()) {\n             for (WithItem item : withItemsList) {\n-                if (item.getSubSelect() != null && !keepSubSelectOrderBy()) {\n-                    processSelectBody(item.getSubSelect().getSelectBody());\n+                if (item.getSelect() != null && !keepSubSelectOrderBy()) {\n+                    processSelect(item.getSelect());\n                 }\n             }\n         }\n@@ -287,33 +290,16 @@\n      * @param fromItem\n      */\n     public void processFromItem(FromItem fromItem) {\n-        if (fromItem instanceof SubJoin) {\n-            SubJoin subJoin = (SubJoin) fromItem;\n-            if (subJoin.getJoinList() != null && subJoin.getJoinList().size() > 0) {\n-                for (Join join : subJoin.getJoinList()) {\n-                    if (join.getRightItem() != null) {\n-                        processFromItem(join.getRightItem());\n-                    }\n-                }\n-            }\n-            if (subJoin.getLeft() != null) {\n-                processFromItem(subJoin.getLeft());\n-            }\n-        } else if (fromItem instanceof SubSelect) {\n-            SubSelect subSelect = (SubSelect) fromItem;\n-            if (subSelect.getSelectBody() != null && !keepSubSelectOrderBy()) {\n-                processSelectBody(subSelect.getSelectBody());\n+        if (fromItem instanceof ParenthesedSelect) {\n+            ParenthesedSelect parenthesedSelect = (ParenthesedSelect) fromItem;\n+            if (parenthesedSelect.getSelect() != null && !keepSubSelectOrderBy()) {\n+                processSelect(parenthesedSelect.getSelect());\n             }\n-        } else if (fromItem instanceof ValuesList) {\n-\n-        } else if (fromItem instanceof LateralSubSelect) {\n-            LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem;\n-            if (lateralSubSelect.getSubSelect() != null) {\n-                SubSelect subSelect = lateralSubSelect.getSubSelect();\n-                if (subSelect.getSelectBody() != null && !keepSubSelectOrderBy()) {\n-                    processSelectBody(subSelect.getSelectBody());\n-                }\n-            }\n+        } else if (fromItem instanceof Select) {\n+            processSelect((Select) fromItem);\n+        } else if (fromItem instanceof ParenthesedFromItem) {\n+            ParenthesedFromItem parenthesedFromItem = (ParenthesedFromItem) fromItem;\n+            processFromItem(parenthesedFromItem.getFromItem());\n         }\n         //Table时不用处理\n     }\n"
  },
  {
    "path": "pom.xml",
    "content": "<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>com.github.pagehelper</groupId>\n    <artifactId>pagehelper</artifactId>\n    <version>6.1.1</version>\n    <packaging>jar</packaging>\n\n    <name>pagehelper 6</name>\n    <description>Mybatis Pagination Plugin</description>\n    <url>https://github.com/pagehelper/Mybatis-PageHelper</url>\n\n    <licenses>\n        <license>\n            <name>The MIT License (MIT)</name>\n            <url>https://github.com/pagehelper/Mybatis-PageHelper/blob/master/LICENSE</url>\n        </license>\n    </licenses>\n\n    <developers>\n        <developer>\n            <name>abel533</name>\n            <email>abel533@gmail.com</email>\n        </developer>\n    </developers>\n\n    <scm>\n        <connection>scm:git:git@github.com:pagehelper/Mybatis-PageHelper.git</connection>\n        <developerConnection>scm:git:git@github.com:pagehelper/Mybatis-PageHelper.git</developerConnection>\n        <url>git@github.com:pagehelper/Mybatis-PageHelper.git</url>\n    </scm>\n\n    <properties>\n        <maven.compiler.source>8</maven.compiler.source>\n        <maven.compiler.target>8</maven.compiler.target>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.github.jsqlparser</groupId>\n            <artifactId>jsqlparser</artifactId>\n            <version>4.7</version>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis</artifactId>\n            <version>3.5.19</version>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <!--\n            可选依赖:guava\n            当项目包含guava时，会使用 GuavaCache，详情看4.2.0更新日志\n        -->\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n            <version>33.4.8-jre</version>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <!-- 针对多数据源连接池的内部支持 -->\n        <dependency>\n            <groupId>com.zaxxer</groupId>\n            <!-- 这里为了能在 java6 编译选择的低版本，不影响自己选择高版本 -->\n            <artifactId>HikariCP-java6</artifactId>\n            <version>2.3.13</version>\n            <scope>compile</scope>\n            <exclusions>\n                <exclusion>\n                    <artifactId>slf4j-api</artifactId>\n                    <groupId>org.slf4j</groupId>\n                </exclusion>\n            </exclusions>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>1.2.12</version>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.tomcat</groupId>\n            <artifactId>tomcat-jdbc</artifactId>\n            <version>10.0.20</version>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>com.mchange</groupId>\n            <artifactId>c3p0</artifactId>\n            <version>0.9.5.5</version>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-dbcp2</artifactId>\n            <version>2.9.0</version>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <!-- test -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.13.2</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>ch.qos.logback</groupId>\n            <artifactId>logback-classic</artifactId>\n            <version>1.2.13</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.hsqldb</groupId>\n            <artifactId>hsqldb</artifactId>\n            <version>2.2.9</version>\n            <scope>test</scope>\n        </dependency>\n        <!--\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>8.0.33</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.oracle</groupId>\n            <artifactId>ojdbc14</artifactId>\n            <version>10.2.0.4.0</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.ibm</groupId>\n            <artifactId>db2</artifactId>\n            <version>1.0.0</version>\n            <scope>system</scope>\n            <systemPath>${basedir}/src/test/resources/db2/db2jcc4.jar</systemPath>\n        </dependency>\n        <dependency>\n            <groupId>org.postgresql</groupId>\n            <artifactId>postgresql</artifactId>\n            <version>9.3-1102-jdbc41</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n            <version>1.4.190</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.derby</groupId>\n            <artifactId>derby</artifactId>\n            <version>10.12.1.1</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>net.sourceforge.jtds</groupId>\n            <artifactId>jtds</artifactId>\n            <version>1.3.1</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.xugudb</groupId>\n            <artifactId>xugu-jdbc</artifactId>\n            <version>12.2.0</version>\n            <scope>test</scope>\n        </dependency>\n        -->\n    </dependencies>\n    <profiles>\n        <profile>\n            <id>release</id>\n            <build>\n                <plugins>\n                    <!--Compiler-->\n                    <plugin>\n                        <artifactId>maven-compiler-plugin</artifactId>\n                    </plugin>\n                    <!-- Source -->\n                    <plugin>\n                        <groupId>org.apache.maven.plugins</groupId>\n                        <artifactId>maven-source-plugin</artifactId>\n                        <executions>\n                            <execution>\n                                <phase>package</phase>\n                                <goals>\n                                    <goal>jar-no-fork</goal>\n                                </goals>\n                            </execution>\n                        </executions>\n                    </plugin>\n                    <!-- Javadoc -->\n                    <plugin>\n                        <groupId>org.apache.maven.plugins</groupId>\n                        <artifactId>maven-javadoc-plugin</artifactId>\n                        <version>3.2.0</version>\n                        <configuration>\n                            <additionalOptions>\n                                <additionalOption>-Xdoclint:none</additionalOption>\n                            </additionalOptions>\n                        </configuration>\n                        <executions>\n                            <execution>\n                                <phase>package</phase>\n                                <goals>\n                                    <goal>jar</goal>\n                                </goals>\n                            </execution>\n                        </executions>\n                    </plugin>\n                    <!-- GPG mvn clean deploy -P release -Dgpg.passphrase=YourPassphase-->\n                    <plugin>\n                        <groupId>org.apache.maven.plugins</groupId>\n                        <artifactId>maven-gpg-plugin</artifactId>\n                        <executions>\n                            <execution>\n                                <id>sign-artifacts</id>\n                                <phase>verify</phase>\n                                <goals>\n                                    <goal>sign</goal>\n                                </goals>\n                            </execution>\n                        </executions>\n                        <configuration>\n                            <gpgArguments>\n                                <argument>--pinentry-mode</argument>\n                                <argument>loopback</argument>\n                            </gpgArguments>\n                        </configuration>\n                    </plugin>\n                    <plugin>\n                        <groupId>org.sonatype.plugins</groupId>\n                        <artifactId>nexus-staging-maven-plugin</artifactId>\n                        <extensions>true</extensions>\n                        <configuration>\n                            <serverId>ossrh</serverId>\n                            <nexusUrl>https://oss.sonatype.org/</nexusUrl>\n                            <autoReleaseAfterClose>true</autoReleaseAfterClose>\n                        </configuration>\n                    </plugin>\n                </plugins>\n            </build>\n            <distributionManagement>\n                <snapshotRepository>\n                    <id>ossrh</id>\n                    <url>https://oss.sonatype.org/content/repositories/snapshots/</url>\n                </snapshotRepository>\n                <repository>\n                    <id>ossrh</id>\n                    <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>\n                </repository>\n            </distributionManagement>\n        </profile>\n    </profiles>\n    <build>\n        <pluginManagement>\n            <plugins>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-surefire-plugin</artifactId>\n                    <configuration>\n                        <argLine>-Dfile.encoding=UTF-8</argLine>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n    </build>\n</project>\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/AutoDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport org.apache.ibatis.mapping.MappedStatement;\n\nimport javax.sql.DataSource;\nimport java.util.Properties;\n\n/**\n * 自动获取方言\n *\n * @param <K> 缓存key类型\n */\npublic interface AutoDialect<K> {\n\n    /**\n     * 获取用于缓存 {@link #extractDialect } 方法返回值的 key，当返回 null 时不缓存，返回值时先判断是否已存在，不存在时调用 {@link #extractDialect } 再缓存\n     *\n     * @param ms\n     * @param dataSource\n     * @param properties\n     * @return\n     */\n    K extractDialectKey(MappedStatement ms, DataSource dataSource, Properties properties);\n\n    /**\n     * 提取 dialect\n     *\n     * @param dialectKey\n     * @param ms\n     * @param dataSource\n     * @param properties\n     * @return\n     */\n    AbstractHelperDialect extractDialect(K dialectKey, MappedStatement ms, DataSource dataSource, Properties properties);\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/BoundSqlInterceptor.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\n\n/**\n * BoundSql 处理器\n */\npublic interface BoundSqlInterceptor {\n\n    /**\n     * boundsql 处理\n     *\n     * @param type     类型\n     * @param boundSql 当前类型的 boundSql\n     * @param cacheKey 缓存 key\n     * @param chain    处理器链，通过 chain.doBoundSql 方法继续执行后续方法，也可以直接返回 boundSql 终止后续方法的执行\n     * @return 允许修改 boundSql 并返回修改后的\n     */\n    BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain);\n\n    enum Type {\n        /**\n         * 原始SQL，分页插件执行前，先执行这个类型\n         */\n        ORIGINAL,\n        /**\n         * count SQL，第二个执行这里\n         */\n        COUNT_SQL,\n        /**\n         * 分页 SQL，最后执行这里\n         */\n        PAGE_SQL\n    }\n\n    /**\n     * 处理器链，可以控制是否继续执行\n     */\n    interface Chain {\n\n        Chain DO_NOTHING = (type, boundSql, cacheKey) -> boundSql;\n\n        BoundSql doBoundSql(Type type, BoundSql boundSql, CacheKey cacheKey);\n\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/BoundSqlInterceptorChain.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\n\nimport java.util.List;\n\npublic class BoundSqlInterceptorChain implements BoundSqlInterceptor.Chain {\n    private final BoundSqlInterceptor.Chain original;\n    private final List<BoundSqlInterceptor> interceptors;\n\n    private int     index = 0;\n    private boolean executable;\n\n    public BoundSqlInterceptorChain(BoundSqlInterceptor.Chain original, List<BoundSqlInterceptor> interceptors) {\n        this(original, interceptors, false);\n    }\n\n    private BoundSqlInterceptorChain(BoundSqlInterceptor.Chain original, List<BoundSqlInterceptor> interceptors, boolean executable) {\n        this.original = original;\n        this.interceptors = interceptors;\n        this.executable = executable;\n    }\n\n    @Override\n    public BoundSql doBoundSql(BoundSqlInterceptor.Type type, BoundSql boundSql, CacheKey cacheKey) {\n        if(executable) {\n            return _doBoundSql(type, boundSql, cacheKey);\n        } else {\n            return new BoundSqlInterceptorChain(original, interceptors, true).doBoundSql(type, boundSql, cacheKey);\n        }\n    }\n\n    private BoundSql _doBoundSql(BoundSqlInterceptor.Type type, BoundSql boundSql, CacheKey cacheKey) {\n        if (this.interceptors == null || this.interceptors.size() == this.index) {\n            return this.original != null ? this.original.doBoundSql(type, boundSql, cacheKey) : boundSql;\n        } else {\n            return this.interceptors.get(this.index++).boundSql(type, boundSql, cacheKey, this);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/Constant.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\n/**\n * @author liuzh\n */\npublic interface Constant {\n    //分页的id后缀\n    String SUFFIX_PAGE = \"_PageHelper\";\n    //count查询的id后缀\n    String SUFFIX_COUNT = SUFFIX_PAGE + \"_Count\";\n    //第一个分页参数\n    String PAGEPARAMETER_FIRST = \"First\" + SUFFIX_PAGE;\n    //第二个分页参数\n    String PAGEPARAMETER_SECOND = \"Second\" + SUFFIX_PAGE;\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/CountMsIdGen.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\n\n/**\n * 构建当前查询对应的 count 方法 id\n * <p>\n * 返回的 msId 会先判断是否存在自定义的方法，存在就直接使用\n * <p>\n * 如果不存在，会根据当前的 msId 创建 MappedStatement\n *\n * @author liuzh\n */\npublic interface CountMsIdGen {\n\n    /**\n     * 默认实现\n     */\n    CountMsIdGen DEFAULT = (ms, parameter, boundSql, countSuffix) -> ms.getId() + countSuffix;\n\n    /**\n     * 构建当前查询对应的 count 方法 id\n     *\n     * @param ms          查询对应的 MappedStatement\n     * @param parameter   方法参数\n     * @param boundSql    查询SQL\n     * @param countSuffix 配置的 count 后缀\n     * @return count 查询丢的 msId\n     */\n    String genCountMsId(MappedStatement ms, Object parameter,\n                        BoundSql boundSql, String countSuffix);\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/Dialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.session.RowBounds;\n\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ForkJoinPool;\nimport java.util.concurrent.Future;\n\n/**\n * 数据库方言，针对不同数据库进行实现\n *\n * @author liuzh\n */\npublic interface Dialect {\n    /**\n     * 跳过 count 和 分页查询\n     *\n     * @param ms              MappedStatement\n     * @param parameterObject 方法参数\n     * @param rowBounds       分页参数\n     * @return true 跳过，返回默认查询结果，false 执行分页查询\n     */\n    boolean skip(MappedStatement ms, Object parameterObject, RowBounds rowBounds);\n\n    /**\n     * 是否使用异步 count 查询，使用异步后不会根据返回的 count 数来判断是否有必要进行分页查询\n     *\n     * @return true 异步，false 同步\n     */\n    default boolean isAsyncCount() {\n        return false;\n    }\n\n    /**\n     * 执行异步 count 查询\n     *\n     * @param task 异步查询任务\n     * @param <T>\n     * @return\n     */\n    default <T> Future<T> asyncCountTask(Callable<T> task) {\n        return ForkJoinPool.commonPool().submit(task);\n    }\n\n    /**\n     * 执行分页前，返回 true 会进行 count 查询，false 会继续下面的 beforePage 判断\n     *\n     * @param ms              MappedStatement\n     * @param parameterObject 方法参数\n     * @param rowBounds       分页参数\n     * @return\n     */\n    boolean beforeCount(MappedStatement ms, Object parameterObject, RowBounds rowBounds);\n\n    /**\n     * 生成 count 查询 sql\n     *\n     * @param ms              MappedStatement\n     * @param boundSql        绑定 SQL 对象\n     * @param parameterObject 方法参数\n     * @param rowBounds       分页参数\n     * @param countKey        count 缓存 key\n     * @return\n     */\n    String getCountSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey countKey);\n\n    /**\n     * 执行完 count 查询后\n     *\n     * @param count           查询结果总数\n     * @param parameterObject 接口参数\n     * @param rowBounds       分页参数\n     * @return true 继续分页查询，false 直接返回\n     */\n    boolean afterCount(long count, Object parameterObject, RowBounds rowBounds);\n\n    /**\n     * 处理查询参数对象\n     *\n     * @param ms              MappedStatement\n     * @param parameterObject\n     * @param boundSql\n     * @param pageKey\n     * @return\n     */\n    Object processParameterObject(MappedStatement ms, Object parameterObject, BoundSql boundSql, CacheKey pageKey);\n\n    /**\n     * 执行分页前，返回 true 会进行分页查询，false 会返回默认查询结果\n     *\n     * @param ms              MappedStatement\n     * @param parameterObject 方法参数\n     * @param rowBounds       分页参数\n     * @return\n     */\n    boolean beforePage(MappedStatement ms, Object parameterObject, RowBounds rowBounds);\n\n    /**\n     * 生成分页查询 sql\n     *\n     * @param ms              MappedStatement\n     * @param boundSql        绑定 SQL 对象\n     * @param parameterObject 方法参数\n     * @param rowBounds       分页参数\n     * @param pageKey         分页缓存 key\n     * @return\n     */\n    String getPageSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey pageKey);\n\n    /**\n     * 分页查询后，处理分页结果，拦截器中直接 return 该方法的返回值\n     *\n     * @param pageList        分页查询结果\n     * @param parameterObject 方法参数\n     * @param rowBounds       分页参数\n     * @return\n     */\n    Object afterPage(List pageList, Object parameterObject, RowBounds rowBounds);\n\n    /**\n     * 完成所有任务后\n     */\n    void afterAll();\n\n    /**\n     * 设置参数\n     *\n     * @param properties 插件属性\n     */\n    void setProperties(Properties properties);\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/IPage.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\n/**\n * @author liuzh\n */\npublic interface IPage {\n\n    Integer getPageNum();\n\n    Integer getPageSize();\n\n    String getOrderBy();\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/ISelect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\n/**\n * 分页查询接口\n *\n * @author liuzh_3nofxnp\n * @since 2015-12-18 18:51\n */\npublic interface ISelect {\n\n    /**\n     * 在接口中调用自己的查询方法，不要在该方法内写过多代码，只要一行查询方法最好\n     */\n    void doSelect();\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/Page.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\nimport com.github.pagehelper.util.SqlSafeUtil;\nimport com.github.pagehelper.util.StackTraceUtil;\nimport org.apache.ibatis.logging.Log;\nimport org.apache.ibatis.logging.LogFactory;\n\nimport java.io.Closeable;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Mybatis - 分页对象\n *\n * @author liuzh/abel533/isea533\n * @version 3.6.0\n * 项目地址 : http://git.oschina.net/free/Mybatis_PageHelper\n */\npublic class Page<E> extends ArrayList<E> implements Closeable {\n    private static final long serialVersionUID = 1L;\n\n    private static final Log                       log        = LogFactory.getLog(Page.class);\n    /**\n     * 记录当前堆栈,可查找到page在何处创建\n     * 需开启pagehelper.debug\n     */\n    private final        String                    stackTrace = PageInterceptor.isDebug() ? StackTraceUtil.current() : null;\n    /**\n     * 页码，从1开始\n     */\n    private              int                       pageNum;\n    /**\n     * 页面大小\n     */\n    private              int                       pageSize;\n    /**\n     * 起始行\n     */\n    private              long                      startRow;\n    /**\n     * 末行\n     */\n    private              long                      endRow;\n    /**\n     * 总数\n     */\n    private              long                      total;\n    /**\n     * 总页数\n     */\n    private              int                       pages;\n    /**\n     * 包含count查询\n     */\n    private              boolean                   count      = true;\n    /**\n     * 分页合理化\n     */\n    private              Boolean                   reasonable;\n    /**\n     * 当设置为true的时候，如果pagesize设置为0（或RowBounds的limit=0），就不执行分页，返回全部结果\n     */\n    private              Boolean                   pageSizeZero;\n    /**\n     * 进行count查询的列名\n     */\n    private              String                    countColumn;\n    /**\n     * 排序\n     */\n    private              String                    orderBy;\n    /**\n     * 只增加排序\n     */\n    private              boolean                   orderByOnly;\n    /**\n     * sql拦截处理\n     */\n    private              BoundSqlInterceptor       boundSqlInterceptor;\n    private transient    BoundSqlInterceptor.Chain chain;\n    /**\n     * 分页实现类，可以使用 {@link com.github.pagehelper.page.PageAutoDialect} 类中注册的别名，例如 \"mysql\", \"oracle\"\n     */\n    private              String                    dialectClass;\n    /**\n     * 转换count查询时保留查询的 order by 排序\n     */\n    private              Boolean                   keepOrderBy;\n    /**\n     * 转换count查询时保留子查询的 order by 排序\n     */\n    private              Boolean                   keepSubSelectOrderBy;\n    /**\n     * 异步count查询\n     */\n    private              Boolean                   asyncCount;\n\n    public Page() {\n        super();\n    }\n\n    public Page(int pageNum, int pageSize) {\n        this(pageNum, pageSize, true, null);\n    }\n\n    public Page(int pageNum, int pageSize, boolean count) {\n        this(pageNum, pageSize, count, null);\n    }\n\n    private Page(int pageNum, int pageSize, boolean count, Boolean reasonable) {\n        super(0);\n        if (pageNum == 1 && pageSize == Integer.MAX_VALUE) {\n            pageSizeZero = true;\n            pageSize = 0;\n        }\n        this.pageNum = pageNum;\n        this.pageSize = pageSize;\n        this.count = count;\n        calculateStartAndEndRow();\n        setReasonable(reasonable);\n    }\n\n    /**\n     * int[] rowBounds\n     * 0 : offset\n     * 1 : limit\n     */\n    public Page(int[] rowBounds, boolean count) {\n        super(0);\n        if (rowBounds[0] == 0 && rowBounds[1] == Integer.MAX_VALUE) {\n            pageSizeZero = true;\n            this.pageSize = 0;\n            this.pageNum = 1;\n        } else {\n            this.pageSize = rowBounds[1];\n            this.pageNum = rowBounds[1] != 0 ? (int) (Math.ceil(((double) rowBounds[0] + rowBounds[1]) / rowBounds[1])) : 0;\n        }\n        this.startRow = rowBounds[0];\n        this.count = count;\n        this.endRow = this.startRow + rowBounds[1];\n    }\n\n    public String getStackTrace() {\n        return stackTrace;\n    }\n\n    public List<E> getResult() {\n        return this;\n    }\n\n    public int getPages() {\n        return pages;\n    }\n\n    public Page<E> setPages(int pages) {\n        this.pages = pages;\n        return this;\n    }\n\n    public long getEndRow() {\n        return endRow;\n    }\n\n    public Page<E> setEndRow(long endRow) {\n        this.endRow = endRow;\n        return this;\n    }\n\n    public int getPageNum() {\n        return pageNum;\n    }\n\n    public Page<E> setPageNum(int pageNum) {\n        //分页合理化，针对不合理的页码自动处理\n        this.pageNum = ((reasonable != null && reasonable) && pageNum <= 0) ? 1 : pageNum;\n        return this;\n    }\n\n    public int getPageSize() {\n        return pageSize;\n    }\n\n    public Page<E> setPageSize(int pageSize) {\n        this.pageSize = pageSize;\n        return this;\n    }\n\n    public long getStartRow() {\n        return startRow;\n    }\n\n    public Page<E> setStartRow(long startRow) {\n        this.startRow = startRow;\n        return this;\n    }\n\n    public long getTotal() {\n        return total;\n    }\n\n    public void setTotal(long total) {\n        this.total = total;\n        if (total == -1) {\n            pages = 1;\n            return;\n        }\n        if (pageSize > 0) {\n            pages = (int) (total / pageSize + ((total % pageSize == 0) ? 0 : 1));\n        } else {\n            pages = 0;\n        }\n        //分页合理化，针对不合理的页码自动处理\n        if ((reasonable != null && reasonable) && pageNum > pages) {\n            if (pages != 0) {\n                pageNum = pages;\n            }\n            calculateStartAndEndRow();\n        }\n    }\n\n    public Boolean getReasonable() {\n        return reasonable;\n    }\n\n    public Page<E> setReasonable(Boolean reasonable) {\n        if (reasonable == null) {\n            return this;\n        }\n        this.reasonable = reasonable;\n        //分页合理化，针对不合理的页码自动处理\n        if (this.reasonable && this.pageNum <= 0) {\n            this.pageNum = 1;\n            calculateStartAndEndRow();\n        }\n        return this;\n    }\n\n    public Boolean getPageSizeZero() {\n        return pageSizeZero;\n    }\n\n    public Page<E> setPageSizeZero(Boolean pageSizeZero) {\n        if (this.pageSizeZero == null && pageSizeZero != null) {\n            this.pageSizeZero = pageSizeZero;\n        }\n        return this;\n    }\n\n    public String getOrderBy() {\n        return orderBy;\n    }\n\n    /**\n     * 设置排序字段，增加 SQL 注入校验，如果需要在 order by 使用函数，可以使用 {@link #setUnsafeOrderBy(String)} 方法\n     *\n     * @param orderBy 排序字段\n     */\n    public <E> Page<E> setOrderBy(String orderBy) {\n        if (SqlSafeUtil.check(orderBy)) {\n            throw new PageException(\"order by [\" + orderBy + \"] has a risk of SQL injection, \" +\n                    \"if you want to avoid SQL injection verification, you can call Page.setUnsafeOrderBy\");\n        }\n        this.orderBy = orderBy;\n        return (Page<E>) this;\n    }\n\n    /**\n     * 不安全的设置排序方法，如果从前端接收参数，请自行做好注入校验。\n     * <p>\n     * 请不要故意使用该方法注入然后提交漏洞!!!\n     *\n     * @param orderBy 排序字段\n     */\n    public <E> Page<E> setUnsafeOrderBy(String orderBy) {\n        this.orderBy = orderBy;\n        return (Page<E>) this;\n    }\n\n    public boolean isOrderByOnly() {\n        return orderByOnly;\n    }\n\n    public void setOrderByOnly(boolean orderByOnly) {\n        this.orderByOnly = orderByOnly;\n    }\n\n    public String getDialectClass() {\n        return dialectClass;\n    }\n\n    public void setDialectClass(String dialectClass) {\n        this.dialectClass = dialectClass;\n    }\n\n    public Boolean getKeepOrderBy() {\n        return keepOrderBy;\n    }\n\n    public Page<E> setKeepOrderBy(Boolean keepOrderBy) {\n        this.keepOrderBy = keepOrderBy;\n        return this;\n    }\n\n    public Boolean getKeepSubSelectOrderBy() {\n        return keepSubSelectOrderBy;\n    }\n\n    public void setKeepSubSelectOrderBy(Boolean keepSubSelectOrderBy) {\n        this.keepSubSelectOrderBy = keepSubSelectOrderBy;\n    }\n\n    public Boolean getAsyncCount() {\n        return asyncCount;\n    }\n\n    public void setAsyncCount(Boolean asyncCount) {\n        this.asyncCount = asyncCount;\n    }\n\n    /**\n     * 指定使用的分页实现，如果自己使用的很频繁，建议自己增加一层封装再使用\n     *\n     * @param dialect 分页实现类，可以使用 {@link com.github.pagehelper.page.PageAutoDialect} 类中注册的别名，例如 \"mysql\", \"oracle\"\n     * @return\n     */\n    public Page<E> using(String dialect) {\n        this.dialectClass = dialect;\n        return this;\n    }\n\n    /**\n     * 计算起止行号\n     */\n    private void calculateStartAndEndRow() {\n        this.startRow = this.pageNum > 0 ? (this.pageNum - 1) * this.pageSize : 0;\n        this.endRow = this.startRow + this.pageSize * (this.pageNum > 0 ? 1 : 0);\n    }\n\n    public boolean isCount() {\n        return this.count;\n    }\n\n    public Page<E> setCount(boolean count) {\n        this.count = count;\n        return this;\n    }\n\n    /**\n     * 设置页码\n     *\n     * @param pageNum\n     * @return\n     */\n    public Page<E> pageNum(int pageNum) {\n        //分页合理化，针对不合理的页码自动处理\n        this.pageNum = ((reasonable != null && reasonable) && pageNum <= 0) ? 1 : pageNum;\n        return this;\n    }\n\n    /**\n     * 设置页面大小\n     *\n     * @param pageSize\n     * @return\n     */\n    public Page<E> pageSize(int pageSize) {\n        this.pageSize = pageSize;\n        calculateStartAndEndRow();\n        return this;\n    }\n\n    /**\n     * 是否执行count查询\n     *\n     * @param count\n     * @return\n     */\n    public Page<E> count(Boolean count) {\n        this.count = count;\n        return this;\n    }\n\n    /**\n     * 设置合理化\n     *\n     * @param reasonable\n     * @return\n     */\n    public Page<E> reasonable(Boolean reasonable) {\n        setReasonable(reasonable);\n        return this;\n    }\n\n    /**\n     * 当设置为true的时候，如果pagesize设置为0（或RowBounds的limit=0），就不执行分页，返回全部结果\n     *\n     * @param pageSizeZero\n     * @return\n     */\n    public Page<E> pageSizeZero(Boolean pageSizeZero) {\n        setPageSizeZero(pageSizeZero);\n        return this;\n    }\n\n    /**\n     * 设置 BoundSql 拦截器\n     *\n     * @param boundSqlInterceptor\n     * @return\n     */\n    public Page<E> boundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor) {\n        setBoundSqlInterceptor(boundSqlInterceptor);\n        return this;\n    }\n\n    /**\n     * 指定 count 查询列\n     *\n     * @param columnName\n     * @return\n     */\n    public Page<E> countColumn(String columnName) {\n        setCountColumn(columnName);\n        return this;\n    }\n\n    /**\n     * 转换count查询时保留查询的 order by 排序\n     *\n     * @param keepOrderBy\n     * @return\n     */\n    public Page<E> keepOrderBy(boolean keepOrderBy) {\n        this.keepOrderBy = keepOrderBy;\n        return this;\n    }\n\n    public boolean keepOrderBy() {\n        return this.keepOrderBy != null && this.keepOrderBy;\n    }\n\n    /**\n     * 转换count查询时保留子查询的 order by 排序\n     *\n     * @param keepSubSelectOrderBy\n     * @return\n     */\n    public Page<E> keepSubSelectOrderBy(boolean keepSubSelectOrderBy) {\n        this.keepSubSelectOrderBy = keepSubSelectOrderBy;\n        return this;\n    }\n\n    public boolean keepSubSelectOrderBy() {\n        return this.keepSubSelectOrderBy != null && this.keepSubSelectOrderBy;\n    }\n\n    /**\n     * 异步count查询\n     *\n     * @param asyncCount\n     * @return\n     */\n    public Page<E> asyncCount(boolean asyncCount) {\n        this.asyncCount = asyncCount;\n        return this;\n    }\n\n    /**\n     * 使用异步count查询\n     *\n     * @return\n     */\n    public Page<E> enableAsyncCount() {\n        return asyncCount(true);\n    }\n\n    /**\n     * 不使用异步count查询\n     *\n     * @return\n     */\n    public Page<E> disableAsyncCount() {\n        return asyncCount(false);\n    }\n\n\n    public boolean asyncCount() {\n        return this.asyncCount != null && this.asyncCount;\n    }\n\n    public PageInfo<E> toPageInfo() {\n        return new PageInfo<E>(this);\n    }\n\n    /**\n     * 数据对象转换\n     *\n     * @param function\n     * @param <T>\n     * @return\n     */\n    public <T> PageInfo<T> toPageInfo(Function<E, T> function) {\n        List<T> list = new ArrayList<T>(this.size());\n        for (E e : this) {\n            list.add(function.apply(e));\n        }\n        PageInfo<T> pageInfo = new PageInfo<T>(list);\n        pageInfo.setTotal(this.getTotal());\n        pageInfo.setPageNum(this.getPageNum());\n        pageInfo.setPageSize(this.getPageSize());\n        pageInfo.setPages(this.getPages());\n        pageInfo.setStartRow(this.getStartRow());\n        pageInfo.setEndRow(this.getEndRow());\n        pageInfo.calcByNavigatePages(PageInfo.DEFAULT_NAVIGATE_PAGES);\n        return pageInfo;\n    }\n\n    public PageSerializable<E> toPageSerializable() {\n        return new PageSerializable<E>(this);\n    }\n\n    /**\n     * 数据对象转换\n     *\n     * @param function\n     * @param <T>\n     * @return\n     */\n    public <T> PageSerializable<T> toPageSerializable(Function<E, T> function) {\n        List<T> list = new ArrayList<T>(this.size());\n        for (E e : this) {\n            list.add(function.apply(e));\n        }\n        PageSerializable<T> pageSerializable = new PageSerializable<T>(list);\n        pageSerializable.setTotal(this.getTotal());\n        return pageSerializable;\n    }\n\n    public <E> Page<E> doSelectPage(ISelect select) {\n        select.doSelect();\n        return (Page<E>) this;\n    }\n\n    public <E> PageInfo<E> doSelectPageInfo(ISelect select) {\n        select.doSelect();\n        return (PageInfo<E>) this.toPageInfo();\n    }\n\n    public <E> PageSerializable<E> doSelectPageSerializable(ISelect select) {\n        select.doSelect();\n        return (PageSerializable<E>) this.toPageSerializable();\n    }\n\n    public long doCount(ISelect select) {\n        this.pageSizeZero = true;\n        this.pageSize = 0;\n        select.doSelect();\n        return this.total;\n    }\n\n    public String getCountColumn() {\n        return countColumn;\n    }\n\n    public void setCountColumn(String countColumn) {\n        if (!\"0\".equals(countColumn) && !\"*\".equals(countColumn) && SqlSafeUtil.check(countColumn)) {\n            throw new PageException(\"count(\" + countColumn + \") has a risk of SQL injection\");\n        }\n        this.countColumn = countColumn;\n    }\n\n    public BoundSqlInterceptor getBoundSqlInterceptor() {\n        return boundSqlInterceptor;\n    }\n\n    public void setBoundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor) {\n        this.boundSqlInterceptor = boundSqlInterceptor;\n    }\n\n    BoundSqlInterceptor.Chain getChain() {\n        return chain;\n    }\n\n    void setChain(BoundSqlInterceptor.Chain chain) {\n        this.chain = chain;\n    }\n\n    @Override\n    public String toString() {\n        return \"Page{\" +\n                \"count=\" + count +\n                \", pageNum=\" + pageNum +\n                \", pageSize=\" + pageSize +\n                \", startRow=\" + startRow +\n                \", endRow=\" + endRow +\n                \", total=\" + total +\n                \", pages=\" + pages +\n                \", reasonable=\" + reasonable +\n                \", pageSizeZero=\" + pageSizeZero +\n                '}' + super.toString();\n    }\n\n    @Override\n    public void close() {\n        PageHelper.clearPage();\n    }\n\n    /**\n     * 兼容低版本 Java 7-\n     */\n    public interface Function<E, T> {\n\n        /**\n         * Applies this function to the given argument.\n         *\n         * @param t the function argument\n         * @return the function result\n         */\n        T apply(E t);\n\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/PageException.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\n/**\n * 分页插件异常\n */\npublic class PageException extends RuntimeException {\n    public PageException() {\n        super();\n    }\n\n    public PageException(String message) {\n        super(message);\n    }\n\n    public PageException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public PageException(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/PageHelper.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport com.github.pagehelper.page.PageAutoDialect;\nimport com.github.pagehelper.page.PageBoundSqlInterceptors;\nimport com.github.pagehelper.page.PageMethod;\nimport com.github.pagehelper.page.PageParams;\nimport com.github.pagehelper.parser.CountSqlParser;\nimport com.github.pagehelper.util.StringUtil;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.session.RowBounds;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.UUID;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ForkJoinPool;\nimport java.util.concurrent.ForkJoinWorkerThread;\nimport java.util.concurrent.Future;\n\n/**\n * Mybatis - 通用分页拦截器<br/>\n * 项目地址 : http://git.oschina.net/free/Mybatis_PageHelper\n *\n * @author liuzh/abel533/isea533\n * @version 5.0.0\n */\npublic class PageHelper extends PageMethod implements Dialect, BoundSqlInterceptor.Chain {\n    private PageParams               pageParams;\n    private PageAutoDialect          autoDialect;\n    private PageBoundSqlInterceptors pageBoundSqlInterceptors;\n    private ForkJoinPool             asyncCountService;\n\n    @Override\n    public boolean skip(MappedStatement ms, Object parameterObject, RowBounds rowBounds) {\n        Page page = pageParams.getPage(parameterObject, rowBounds);\n        if (page == null) {\n            return true;\n        } else {\n            //设置默认的 count 列\n            if (StringUtil.isEmpty(page.getCountColumn())) {\n                page.setCountColumn(pageParams.getCountColumn());\n            }\n            //设置默认的异步 count 设置\n            if (page.getAsyncCount() == null) {\n                page.setAsyncCount(pageParams.isAsyncCount());\n            }\n            autoDialect.initDelegateDialect(ms, page.getDialectClass());\n            return false;\n        }\n    }\n\n    @Override\n    public boolean isAsyncCount() {\n        return getLocalPage().asyncCount();\n    }\n\n    @Override\n    public <T> Future<T> asyncCountTask(Callable<T> task) {\n        //异步执行时需要将ThreadLocal值传递，否则会找不到\n        AbstractHelperDialect dialectThreadLocal = autoDialect.getDialectThreadLocal();\n        Page<Object> localPage = getLocalPage();\n        String countId = UUID.randomUUID().toString();\n        return asyncCountService.submit(() -> {\n            try {\n                //设置 ThreadLocal\n                autoDialect.setDialectThreadLocal(dialectThreadLocal);\n                setLocalPage(localPage);\n                return task.call();\n            } finally {\n                autoDialect.clearDelegate();\n                clearPage();\n            }\n        });\n    }\n\n    @Override\n    public boolean beforeCount(MappedStatement ms, Object parameterObject, RowBounds rowBounds) {\n        return autoDialect.getDelegate().beforeCount(ms, parameterObject, rowBounds);\n    }\n\n    @Override\n    public String getCountSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey countKey) {\n        return autoDialect.getDelegate().getCountSql(ms, boundSql, parameterObject, rowBounds, countKey);\n    }\n\n    @Override\n    public boolean afterCount(long count, Object parameterObject, RowBounds rowBounds) {\n        return autoDialect.getDelegate().afterCount(count, parameterObject, rowBounds);\n    }\n\n    @Override\n    public Object processParameterObject(MappedStatement ms, Object parameterObject, BoundSql boundSql, CacheKey pageKey) {\n        return autoDialect.getDelegate().processParameterObject(ms, parameterObject, boundSql, pageKey);\n    }\n\n    @Override\n    public boolean beforePage(MappedStatement ms, Object parameterObject, RowBounds rowBounds) {\n        return autoDialect.getDelegate().beforePage(ms, parameterObject, rowBounds);\n    }\n\n    @Override\n    public String getPageSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey pageKey) {\n        return autoDialect.getDelegate().getPageSql(ms, boundSql, parameterObject, rowBounds, pageKey);\n    }\n\n    public String getPageSql(String sql, Page page, RowBounds rowBounds, CacheKey pageKey) {\n        return autoDialect.getDelegate().getPageSql(sql, page, pageKey);\n    }\n\n    @Override\n    public Object afterPage(List pageList, Object parameterObject, RowBounds rowBounds) {\n        //这个方法即使不分页也会被执行，所以要判断 null\n        AbstractHelperDialect delegate = autoDialect.getDelegate();\n        if (delegate != null) {\n            return delegate.afterPage(pageList, parameterObject, rowBounds);\n        }\n        return pageList;\n    }\n\n    @Override\n    public void afterAll() {\n        //这个方法即使不分页也会被执行，所以要判断 null\n        AbstractHelperDialect delegate = autoDialect.getDelegate();\n        if (delegate != null) {\n            delegate.afterAll();\n            autoDialect.clearDelegate();\n        }\n        clearPage();\n    }\n\n    @Override\n    public BoundSql doBoundSql(BoundSqlInterceptor.Type type, BoundSql boundSql, CacheKey cacheKey) {\n        Page<Object> localPage = getLocalPage();\n        BoundSqlInterceptor.Chain chain = localPage != null ? localPage.getChain() : null;\n        if (chain == null) {\n            BoundSqlInterceptor boundSqlInterceptor = localPage != null ? localPage.getBoundSqlInterceptor() : null;\n            BoundSqlInterceptor.Chain defaultChain = pageBoundSqlInterceptors != null ? pageBoundSqlInterceptors.getChain() : null;\n            if (boundSqlInterceptor != null) {\n                chain = new BoundSqlInterceptorChain(defaultChain, Arrays.asList(boundSqlInterceptor));\n            } else if (defaultChain != null) {\n                chain = defaultChain;\n            }\n            if (chain == null) {\n                chain = DO_NOTHING;\n            }\n            if (localPage != null) {\n                localPage.setChain(chain);\n            }\n        }\n        return chain.doBoundSql(type, boundSql, cacheKey);\n    }\n\n    @Override\n    public void setProperties(Properties properties) {\n        setStaticProperties(properties);\n        pageParams = new PageParams();\n        autoDialect = new PageAutoDialect();\n        pageBoundSqlInterceptors = new PageBoundSqlInterceptors();\n        pageParams.setProperties(properties);\n        autoDialect.setProperties(properties);\n        pageBoundSqlInterceptors.setProperties(properties);\n        //20180902新增 aggregateFunctions, 允许手动添加聚合函数（影响行数）\n        CountSqlParser.addAggregateFunctions(properties.getProperty(\"aggregateFunctions\"));\n        // 异步 asyncCountService 并发度设置，这里默认为应用可用的处理器核心数 * 2，更合理的值应该综合考虑数据库服务器的处理能力\n        int asyncCountParallelism = Integer.parseInt(properties.getProperty(\"asyncCountParallelism\",\n                \"\" + (Runtime.getRuntime().availableProcessors() * 2)));\n        asyncCountService = new ForkJoinPool(asyncCountParallelism,\n                pool -> {\n                    final ForkJoinWorkerThread worker = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool);\n                    worker.setName(\"pagehelper-async-count-\" + worker.getPoolIndex());\n                    return worker;\n                }, null, true);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/PageInfo.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * 对Page<E>结果进行包装\n * <p/>\n * 新增分页的多项属性，主要参考:http://bbs.csdn.net/topics/360010907\n *\n * @author liuzh/abel533/isea533\n * @version 3.3.0\n * @since 3.2.2\n * 项目地址 : http://git.oschina.net/free/Mybatis_PageHelper\n */\n@SuppressWarnings({\"rawtypes\", \"unchecked\"})\npublic class PageInfo<T> extends PageSerializable<T> {\n    public static final int DEFAULT_NAVIGATE_PAGES = 8;\n    //private PageInfo EMPTY = new PageInfo(Collections.emptyList(), 0);\n    /**\n     * 当前页\n     */\n    private int pageNum;\n    /**\n     * 每页的数量\n     */\n    private              int      pageSize;\n    /**\n     * 当前页的数量\n     */\n    private              int      size;\n\n    /**\n     * 由于startRow和endRow不常用，这里说个具体的用法\n     * 可以在页面中\"显示startRow到endRow 共size条数据\"\n     * 当前页面第一个元素在数据库中的行号\n     */\n    private long startRow;\n    /**\n     * 当前页面最后一个元素在数据库中的行号\n     */\n    private long endRow;\n    /**\n     * 总页数\n     */\n    private int pages;\n    /**\n     * 前一页\n     */\n    private int prePage;\n    /**\n     * 下一页\n     */\n    private int nextPage;\n\n    /**\n     * 是否为第一页\n     */\n    private boolean isFirstPage = false;\n    /**\n     * 是否为最后一页\n     */\n    private boolean isLastPage = false;\n    /**\n     * 是否有前一页\n     */\n    private boolean hasPreviousPage = false;\n    /**\n     * 是否有下一页\n     */\n    private boolean hasNextPage = false;\n\n    /**\n     * 导航页码数\n     */\n    private int navigatePages;\n    /**\n     * 所有导航页号\n     */\n    private int[] navigatepageNums;\n    /**\n     * 导航条上的第一页\n     */\n    private int navigateFirstPage;\n    /**\n     * 导航条上的最后一页\n     */\n    private int navigateLastPage;\n\n    public PageInfo() {\n    }\n\n    /**\n     * 包装Page对象\n     *\n     * @param list\n     */\n    public PageInfo(List<? extends T> list) {\n        this(list, DEFAULT_NAVIGATE_PAGES);\n    }\n\n    /**\n     * 包装Page对象\n     *\n     * @param list          page结果\n     * @param navigatePages 页码数量\n     */\n    public PageInfo(List<? extends T> list, int navigatePages) {\n        super(list);\n        if (list instanceof Page) {\n            Page page = (Page) list;\n            this.pageNum = page.getPageNum();\n            this.pageSize = page.getPageSize();\n\n            this.pages = page.getPages();\n            this.size = page.size();\n            //由于结果是>startRow的，所以实际的需要+1\n            if (this.size == 0) {\n                this.startRow = 0;\n                this.endRow = 0;\n            } else {\n                this.startRow = page.getStartRow() + 1;\n                //计算实际的endRow（最后一页的时候特殊）\n                this.endRow = this.startRow - 1 + this.size;\n            }\n        } else if (list instanceof Collection) {\n            this.pageNum = 1;\n            this.pageSize = list.size();\n\n            this.pages = this.pageSize > 0 ? 1 : 0;\n            this.size = list.size();\n            this.startRow = 0;\n            this.endRow = list.size() > 0 ? list.size() - 1 : 0;\n        }\n        if (list instanceof Collection) {\n            calcByNavigatePages(navigatePages);\n        }\n    }\n\n    public static <T> PageInfo<T> of(List<? extends T> list) {\n        return new PageInfo<T>(list);\n    }\n\n\n    /**\n     * 手动指定总记录数获取分页信息\n     *\n     * @param total 总记录数\n     * @param list  page结果\n     */\n    public static <T> PageInfo<T> of(long total, List<? extends T> list) {\n        if (list instanceof Page) {\n            Page page = (Page) list;\n            page.setTotal(total);\n        }\n        return new PageInfo<T>(list);\n    }\n\n    public static <T> PageInfo<T> of(List<? extends T> list, int navigatePages) {\n        return new PageInfo<T>(list, navigatePages);\n    }\n\n    /**\n     * 返回一个空的 Pageinfo 对象\n     *\n     * @return\n     */\n    public static <T> PageInfo<T> emptyPageInfo() {\n        return new PageInfo(Collections.emptyList(), 0);\n    }\n\n    public void calcByNavigatePages(int navigatePages) {\n        setNavigatePages(navigatePages);\n        //计算导航页\n        calcNavigatepageNums();\n        //计算前后页，第一页，最后一页\n        calcPage();\n        //判断页面边界\n        judgePageBoudary();\n    }\n\n    /**\n     * 计算导航页\n     */\n    private void calcNavigatepageNums() {\n        //当总页数小于或等于导航页码数时\n        if (pages <= navigatePages) {\n            navigatepageNums = new int[pages];\n            for (int i = 0; i < pages; i++) {\n                navigatepageNums[i] = i + 1;\n            }\n        } else { //当总页数大于导航页码数时\n            navigatepageNums = new int[navigatePages];\n            int startNum = pageNum - navigatePages / 2;\n            int endNum = pageNum + navigatePages / 2;\n\n            if (startNum < 1) {\n                startNum = 1;\n                //(最前navigatePages页\n                for (int i = 0; i < navigatePages; i++) {\n                    navigatepageNums[i] = startNum++;\n                }\n            } else if (endNum > pages) {\n                endNum = pages;\n                //最后navigatePages页\n                for (int i = navigatePages - 1; i >= 0; i--) {\n                    navigatepageNums[i] = endNum--;\n                }\n            } else {\n                //所有中间页\n                for (int i = 0; i < navigatePages; i++) {\n                    navigatepageNums[i] = startNum++;\n                }\n            }\n        }\n    }\n\n    /**\n     * 计算前后页，第一页，最后一页\n     */\n    private void calcPage() {\n        if (navigatepageNums != null && navigatepageNums.length > 0) {\n            navigateFirstPage = navigatepageNums[0];\n            navigateLastPage = navigatepageNums[navigatepageNums.length - 1];\n            if (pageNum > 1) {\n                prePage = pageNum - 1;\n            }\n            if (pageNum < pages) {\n                nextPage = pageNum + 1;\n            }\n        }\n    }\n\n    /**\n     * 判定页面边界\n     */\n    private void judgePageBoudary() {\n        isFirstPage = pageNum == 1;\n        isLastPage = pageNum == pages || pages == 0;\n        hasPreviousPage = pageNum > 1;\n        hasNextPage = pageNum < pages;\n    }\n\n    /**\n     * 数据对象转换\n     *\n     * @param function 用以转换数据对象的函数\n     * @param <E>      目标类型\n     * @return 转换了对象类型的包装结果\n     */\n    public <E> PageInfo<E> convert(Page.Function<T, E> function) {\n        List<E> list = new ArrayList<E>(this.list.size());\n        for (T t : this.list) {\n            list.add(function.apply(t));\n        }\n        PageInfo<E> newPageInfo = new PageInfo<>(list);\n        newPageInfo.setPageNum(this.pageNum);\n        newPageInfo.setPageSize(this.pageSize);\n        newPageInfo.setSize(this.size);\n        newPageInfo.setStartRow(this.startRow);\n        newPageInfo.setEndRow(this.endRow);\n        newPageInfo.setTotal(this.total);\n        newPageInfo.setPages(this.pages);\n        newPageInfo.setPrePage(this.prePage);\n        newPageInfo.setNextPage(this.nextPage);\n        newPageInfo.setIsFirstPage(this.isFirstPage);\n        newPageInfo.setIsLastPage(this.isLastPage);\n        newPageInfo.setHasPreviousPage(this.hasPreviousPage);\n        newPageInfo.setHasNextPage(this.hasNextPage);\n        newPageInfo.setNavigatePages(this.navigatePages);\n        newPageInfo.setNavigateFirstPage(this.navigateFirstPage);\n        newPageInfo.setNavigateLastPage(this.navigateLastPage);\n        newPageInfo.setNavigatepageNums(this.navigatepageNums);\n        return newPageInfo;\n    }\n\n    /**\n     * 是否包含内容\n     */\n    public boolean hasContent() {\n        return this.size > 0;\n    }\n\n    public int getPageNum() {\n        return pageNum;\n    }\n\n    public void setPageNum(int pageNum) {\n        this.pageNum = pageNum;\n    }\n\n    public int getPageSize() {\n        return pageSize;\n    }\n\n    public void setPageSize(int pageSize) {\n        this.pageSize = pageSize;\n    }\n\n    public int getSize() {\n        return size;\n    }\n\n    public void setSize(int size) {\n        this.size = size;\n    }\n\n    public long getStartRow() {\n        return startRow;\n    }\n\n    public void setStartRow(long startRow) {\n        this.startRow = startRow;\n    }\n\n    public long getEndRow() {\n        return endRow;\n    }\n\n    public void setEndRow(long endRow) {\n        this.endRow = endRow;\n    }\n\n    public int getPages() {\n        return pages;\n    }\n\n    public void setPages(int pages) {\n        this.pages = pages;\n    }\n\n    public int getPrePage() {\n        return prePage;\n    }\n\n    public void setPrePage(int prePage) {\n        this.prePage = prePage;\n    }\n\n    public int getNextPage() {\n        return nextPage;\n    }\n\n    public void setNextPage(int nextPage) {\n        this.nextPage = nextPage;\n    }\n\n    public boolean isIsFirstPage() {\n        return isFirstPage;\n    }\n\n    public void setIsFirstPage(boolean isFirstPage) {\n        this.isFirstPage = isFirstPage;\n    }\n\n    public boolean isIsLastPage() {\n        return isLastPage;\n    }\n\n    public void setIsLastPage(boolean isLastPage) {\n        this.isLastPage = isLastPage;\n    }\n\n    public boolean isHasPreviousPage() {\n        return hasPreviousPage;\n    }\n\n    public void setHasPreviousPage(boolean hasPreviousPage) {\n        this.hasPreviousPage = hasPreviousPage;\n    }\n\n    public boolean isHasNextPage() {\n        return hasNextPage;\n    }\n\n    public void setHasNextPage(boolean hasNextPage) {\n        this.hasNextPage = hasNextPage;\n    }\n\n    public int getNavigatePages() {\n        return navigatePages;\n    }\n\n    public void setNavigatePages(int navigatePages) {\n        this.navigatePages = navigatePages;\n    }\n\n    public int[] getNavigatepageNums() {\n        return navigatepageNums;\n    }\n\n    public void setNavigatepageNums(int[] navigatepageNums) {\n        this.navigatepageNums = navigatepageNums;\n    }\n\n    public int getNavigateFirstPage() {\n        return navigateFirstPage;\n    }\n\n    public int getNavigateLastPage() {\n        return navigateLastPage;\n    }\n\n    public void setNavigateFirstPage(int navigateFirstPage) {\n        this.navigateFirstPage = navigateFirstPage;\n    }\n\n    public void setNavigateLastPage(int navigateLastPage) {\n        this.navigateLastPage = navigateLastPage;\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"PageInfo{\");\n        sb.append(\"pageNum=\").append(pageNum);\n        sb.append(\", pageSize=\").append(pageSize);\n        sb.append(\", size=\").append(size);\n        sb.append(\", startRow=\").append(startRow);\n        sb.append(\", endRow=\").append(endRow);\n        sb.append(\", total=\").append(total);\n        sb.append(\", pages=\").append(pages);\n        sb.append(\", list=\").append(list);\n        sb.append(\", prePage=\").append(prePage);\n        sb.append(\", nextPage=\").append(nextPage);\n        sb.append(\", isFirstPage=\").append(isFirstPage);\n        sb.append(\", isLastPage=\").append(isLastPage);\n        sb.append(\", hasPreviousPage=\").append(hasPreviousPage);\n        sb.append(\", hasNextPage=\").append(hasNextPage);\n        sb.append(\", navigatePages=\").append(navigatePages);\n        sb.append(\", navigateFirstPage=\").append(navigateFirstPage);\n        sb.append(\", navigateLastPage=\").append(navigateLastPage);\n        sb.append(\", navigatepageNums=\");\n        if (navigatepageNums == null) {\n            sb.append(\"null\");\n        } else {\n            sb.append('[');\n            for (int i = 0; i < navigatepageNums.length; ++i) {\n                sb.append(i == 0 ? \"\" : \", \").append(navigatepageNums[i]);\n            }\n            sb.append(']');\n        }\n        sb.append('}');\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/PageInterceptor.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\nimport com.github.pagehelper.cache.Cache;\nimport com.github.pagehelper.cache.CacheFactory;\nimport com.github.pagehelper.page.PageMethod;\nimport com.github.pagehelper.util.ClassUtil;\nimport com.github.pagehelper.util.ExecutorUtil;\nimport com.github.pagehelper.util.MSUtils;\nimport com.github.pagehelper.util.StringUtil;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.executor.CachingExecutor;\nimport org.apache.ibatis.executor.Executor;\nimport org.apache.ibatis.executor.SimpleExecutor;\nimport org.apache.ibatis.logging.Log;\nimport org.apache.ibatis.logging.LogFactory;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.Environment;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.plugin.*;\nimport org.apache.ibatis.session.Configuration;\nimport org.apache.ibatis.session.ResultHandler;\nimport org.apache.ibatis.session.RowBounds;\nimport org.apache.ibatis.transaction.Transaction;\nimport org.apache.ibatis.transaction.TransactionFactory;\nimport org.apache.ibatis.transaction.managed.ManagedTransactionFactory;\n\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.concurrent.Future;\n\n/**\n * Mybatis - 通用分页拦截器\n * <p>\n * GitHub: https://github.com/pagehelper/Mybatis-PageHelper\n * <p>\n * Gitee : https://gitee.com/free/Mybatis_PageHelper\n *\n * @author liuzh/abel533/isea533\n * @version 5.0.0\n */\n@SuppressWarnings({\"rawtypes\", \"unchecked\"})\n@Intercepts(\n        {\n                @Signature(type = Executor.class, method = \"query\", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),\n                @Signature(type = Executor.class, method = \"query\", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),\n        }\n)\npublic class PageInterceptor implements Interceptor {\n    private static final Log                            log                   = LogFactory.getLog(PageInterceptor.class);\n    private static       boolean                        debug                 = false;\n    protected            Cache<String, MappedStatement> msCountMap            = null;\n    protected            CountMsIdGen                   countMsIdGen          = CountMsIdGen.DEFAULT;\n    private volatile     Dialect                        dialect;\n    private              String                         countSuffix           = \"_COUNT\";\n    private              String                         default_dialect_class = \"com.github.pagehelper.PageHelper\";\n\n    public PageInterceptor() {\n        String bannerEnabled = System.getProperty(\"pagehelper.banner\");\n        if (StringUtil.isEmpty(bannerEnabled)) {\n            bannerEnabled = System.getenv(\"PAGEHELPER_BANNER\");\n        }\n        //默认 TRUE\n        if (StringUtil.isEmpty(bannerEnabled) || Boolean.parseBoolean(bannerEnabled)) {\n            log.debug(\"\\n\\n\" +\n                    \",------.                           ,--.  ,--.         ,--.                         \\n\" +\n                    \"|  .--. '  ,--,--.  ,---.   ,---.  |  '--'  |  ,---.  |  |  ,---.   ,---.  ,--.--. \\n\" +\n                    \"|  '--' | ' ,-.  | | .-. | | .-. : |  .--.  | | .-. : |  | | .-. | | .-. : |  .--' \\n\" +\n                    \"|  | --'  \\\\ '-'  | ' '-' ' \\\\   --. |  |  |  | \\\\   --. |  | | '-' ' \\\\   --. |  |    \\n\" +\n                    \"`--'       `--`--' .`-  /   `----' `--'  `--'  `----' `--' |  |-'   `----' `--'    \\n\" +\n                    \"                   `---'                                   `--'                        is intercepting.\\n\");\n        }\n    }\n\n    public static boolean isDebug() {\n        return debug;\n    }\n\n    /**\n     * 输出启用分页方法时的调用堆栈信息\n     */\n    protected void debugStackTraceLog() {\n        if (isDebug()) {\n            Page<Object> page = PageMethod.getLocalPage();\n            log.debug(page.getStackTrace());\n        }\n    }\n\n    @Override\n    public Object intercept(Invocation invocation) throws Throwable {\n        try {\n            Object[] args = invocation.getArgs();\n            MappedStatement ms = (MappedStatement) args[0];\n            Object parameter = args[1];\n            RowBounds rowBounds = (RowBounds) args[2];\n            ResultHandler resultHandler = (ResultHandler) args[3];\n            Executor executor = (Executor) invocation.getTarget();\n            CacheKey cacheKey;\n            BoundSql boundSql;\n            //由于逻辑关系，只会进入一次\n            if (args.length == 4) {\n                //4 个参数时\n                boundSql = ms.getBoundSql(parameter);\n                cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);\n            } else {\n                //6 个参数时\n                cacheKey = (CacheKey) args[4];\n                boundSql = (BoundSql) args[5];\n            }\n            checkDialectExists();\n            //对 boundSql 的拦截处理\n            if (dialect instanceof BoundSqlInterceptor.Chain) {\n                boundSql = ((BoundSqlInterceptor.Chain) dialect).doBoundSql(BoundSqlInterceptor.Type.ORIGINAL, boundSql, cacheKey);\n            }\n            List resultList;\n            //调用方法判断是否需要进行分页，如果不需要，直接返回结果\n            if (!dialect.skip(ms, parameter, rowBounds)) {\n                //开启debug时，输出触发当前分页执行时的PageHelper调用堆栈\n                // 如果和当前调用堆栈不一致，说明在启用分页后没有消费，当前线程再次执行时消费，调用堆栈显示的方法使用不安全\n                debugStackTraceLog();\n                Future<Long> countFuture = null;\n                //判断是否需要进行 count 查询\n                if (dialect.beforeCount(ms, parameter, rowBounds)) {\n                    if (dialect.isAsyncCount()) {\n                        countFuture = asyncCount(ms, boundSql, parameter, rowBounds);\n                    } else {\n                        //查询总数\n                        Long count = count(executor, ms, parameter, rowBounds, null, boundSql);\n                        //处理查询总数，返回 true 时继续分页查询，false 时直接返回\n                        if (!dialect.afterCount(count, parameter, rowBounds)) {\n                            //当查询总数为 0 时，直接返回空的结果\n                            return dialect.afterPage(new ArrayList(), parameter, rowBounds);\n                        }\n                    }\n                }\n                resultList = ExecutorUtil.pageQuery(dialect, executor,\n                        ms, parameter, rowBounds, resultHandler, boundSql, cacheKey);\n                if (countFuture != null) {\n                    Long count = countFuture.get();\n                    dialect.afterCount(count, parameter, rowBounds);\n                }\n            } else {\n                //rowBounds用参数值，不使用分页插件处理时，仍然支持默认的内存分页\n                resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);\n            }\n            return dialect.afterPage(resultList, parameter, rowBounds);\n        } finally {\n            if (dialect != null) {\n                dialect.afterAll();\n            }\n        }\n    }\n\n    /**\n     * 异步查询总数\n     */\n    private Future<Long> asyncCount(MappedStatement ms, BoundSql boundSql, Object parameter, RowBounds rowBounds) {\n        Configuration configuration = ms.getConfiguration();\n        //异步不能复用 BoundSql，因为分页使用时会添加分页参数，这里需要复制一个新的\n        BoundSql countBoundSql = new BoundSql(configuration, boundSql.getSql(), new ArrayList<>(boundSql.getParameterMappings()), parameter);\n        Map<String, Object> additionalParameter = ExecutorUtil.getAdditionalParameter(boundSql);\n        if (additionalParameter != null){\n            for (String key : additionalParameter.keySet()) {\n                countBoundSql.setAdditionalParameter(key, additionalParameter.get(key));\n            }\n        }\n        //异步想要起作用需要新的数据库连接，需要独立的事务，创建新的Executor，因此异步查询只适合在独立查询中使用，如果混合增删改操作，不能开启异步\n        Environment environment = configuration.getEnvironment();\n        TransactionFactory transactionFactory = null;\n        if (environment == null || environment.getTransactionFactory() == null) {\n            transactionFactory = new ManagedTransactionFactory();\n        } else {\n            transactionFactory = environment.getTransactionFactory();\n        }\n        //创建新的事务\n        Transaction tx = transactionFactory.newTransaction(environment.getDataSource(), null, false);\n        //使用新的 Executor 执行 count 查询，这里没有加载拦截器，避免递归死循环\n        Executor countExecutor = new CachingExecutor(new SimpleExecutor(configuration, tx));\n\n        return dialect.asyncCountTask(() -> {\n            try {\n                return count(countExecutor, ms, parameter, rowBounds, null, countBoundSql);\n            } finally {\n                tx.close();\n            }\n        });\n    }\n\n    /**\n     * Spring bean 方式配置时，如果没有配置属性就不会执行下面的 setProperties 方法，就不会初始化\n     * <p>\n     * 因此这里会出现 null 的情况 fixed #26\n     */\n    private void checkDialectExists() {\n        if (dialect == null) {\n            synchronized (default_dialect_class) {\n                if (dialect == null) {\n                    setProperties(new Properties());\n                }\n            }\n        }\n    }\n\n    private Long count(Executor executor, MappedStatement ms, Object parameter,\n                       RowBounds rowBounds, ResultHandler resultHandler,\n                       BoundSql boundSql) throws SQLException {\n        String countMsId = countMsIdGen.genCountMsId(ms, parameter, boundSql, countSuffix);\n        Long count;\n        //先判断是否存在手写的 count 查询\n        MappedStatement countMs = ExecutorUtil.getExistedMappedStatement(ms.getConfiguration(), countMsId);\n        if (countMs != null) {\n            count = ExecutorUtil.executeManualCount(executor, countMs, parameter, boundSql, resultHandler);\n        } else {\n            if (msCountMap != null) {\n                countMs = msCountMap.get(countMsId);\n            }\n            //自动创建\n            if (countMs == null) {\n                //根据当前的 ms 创建一个返回值为 Long 类型的 ms\n                countMs = MSUtils.newCountMappedStatement(ms, countMsId);\n                if (msCountMap != null) {\n                    msCountMap.put(countMsId, countMs);\n                }\n            }\n            count = ExecutorUtil.executeAutoCount(this.dialect, executor, countMs, parameter, boundSql, rowBounds, resultHandler);\n        }\n        return count;\n    }\n\n    @Override\n    public Object plugin(Object target) {\n        return Plugin.wrap(target, this);\n    }\n\n    @Override\n    public void setProperties(Properties properties) {\n        //缓存 count ms\n        msCountMap = CacheFactory.createCache(properties.getProperty(\"msCountCache\"), \"ms\", properties);\n        String dialectClass = properties.getProperty(\"dialect\");\n        if (StringUtil.isEmpty(dialectClass)) {\n            dialectClass = default_dialect_class;\n        }\n        Dialect tempDialect = ClassUtil.newInstance(dialectClass, properties);\n        tempDialect.setProperties(properties);\n\n        String countSuffix = properties.getProperty(\"countSuffix\");\n        if (StringUtil.isNotEmpty(countSuffix)) {\n            this.countSuffix = countSuffix;\n        }\n\n        // debug模式，用于排查不安全分页调用\n        debug = Boolean.parseBoolean(properties.getProperty(\"debug\"));\n\n        // 通过 countMsId 配置自定义类\n        String countMsIdGenClass = properties.getProperty(\"countMsIdGen\");\n        if (StringUtil.isNotEmpty(countMsIdGenClass)) {\n            countMsIdGen = ClassUtil.newInstance(countMsIdGenClass, properties);\n        }\n        // 初始化完成后再设置值，保证 dialect 完成初始化\n        dialect = tempDialect;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/PageParam.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\n/**\n * 抽象类，自己的查询类可以继承该类，可以更直接的控制分页参数\n */\npublic class PageParam implements IPage {\n    private Integer pageNum;\n    private Integer pageSize;\n    private String  orderBy;\n\n    public PageParam() {\n    }\n\n    public PageParam(Integer pageNum, Integer pageSize) {\n        this.pageNum = pageNum;\n        this.pageSize = pageSize;\n    }\n\n    public PageParam(Integer pageNum, Integer pageSize, String orderBy) {\n        this.pageNum = pageNum;\n        this.pageSize = pageSize;\n        this.orderBy = orderBy;\n    }\n\n    public void setPageNum(Integer pageNum) {\n        this.pageNum = pageNum;\n    }\n\n    public void setPageSize(Integer pageSize) {\n        this.pageSize = pageSize;\n    }\n\n    public void setOrderBy(String orderBy) {\n        this.orderBy = orderBy;\n    }\n\n    @Override\n    public Integer getPageNum() {\n        return pageNum;\n    }\n\n    @Override\n    public Integer getPageSize() {\n        return pageSize;\n    }\n\n    @Override\n    public String getOrderBy() {\n        return orderBy;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/PageProperties.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\nimport java.util.Properties;\n\n/**\n * 分页配置，实现该接口的类在初始化后会调用 {@link #setProperties(Properties)} 方法\n *\n * @author liuzh\n */\npublic interface PageProperties {\n\n    /**\n     * 设置参数\n     *\n     * @param properties 插件属性\n     */\n    void setProperties(Properties properties);\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/PageRowBounds.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\nimport org.apache.ibatis.session.RowBounds;\n\n/**\n * @author liuzenghui\n */\npublic class PageRowBounds extends RowBounds {\n    private Long total;\n    private Boolean count;\n\n    public PageRowBounds(int offset, int limit) {\n        super(offset, limit);\n    }\n\n    public Long getTotal() {\n        return total;\n    }\n\n    public void setTotal(Long total) {\n        this.total = total;\n    }\n\n    public Boolean getCount() {\n        return count;\n    }\n\n    public void setCount(Boolean count) {\n        this.count = count;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/PageSerializable.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * @author liuzh\n */\npublic class PageSerializable<T> implements Serializable {\n    private static final long serialVersionUID = 1L;\n    //总记录数\n    protected long    total;\n    //结果集\n    protected List<T> list;\n\n    public PageSerializable() {\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public PageSerializable(List<? extends T> list) {\n        this.list = (List<T>) list;\n        if(list instanceof Page){\n            this.total = ((Page<?>)list).getTotal();\n        } else {\n            this.total = list.size();\n        }\n    }\n\n    public static <T> PageSerializable<T> of(List<? extends T> list){\n        return new PageSerializable<T>(list);\n    }\n\n    public long getTotal() {\n        return total;\n    }\n\n    public void setTotal(long total) {\n        this.total = total;\n    }\n\n    public List<T> getList() {\n        return list;\n    }\n\n    public void setList(List<T> list) {\n        this.list = list;\n    }\n\n    @Override\n    public String toString() {\n        return \"PageSerializable{\" +\n                \"total=\" + total +\n                \", list=\" + list +\n                '}';\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/QueryInterceptor.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper;\n\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.executor.Executor;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.plugin.*;\nimport org.apache.ibatis.session.ResultHandler;\nimport org.apache.ibatis.session.RowBounds;\n\nimport java.util.Properties;\n\n/**\n * QueryInterceptor 规范\n *\n * 详细说明见文档：https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Interceptor.md\n *\n * @author liuzh/abel533/isea533\n * @version 1.0.0\n */\n@Intercepts(\n    {\n        @Signature(type = Executor.class, method = \"query\", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),\n        @Signature(type = Executor.class, method = \"query\", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),\n    }\n)\npublic class QueryInterceptor implements Interceptor {\n\n    @Override\n    public Object intercept(Invocation invocation) throws Throwable {\n        Object[] args = invocation.getArgs();\n        MappedStatement ms = (MappedStatement) args[0];\n        Object parameter = args[1];\n        RowBounds rowBounds = (RowBounds) args[2];\n        ResultHandler resultHandler = (ResultHandler) args[3];\n        Executor executor = (Executor) invocation.getTarget();\n        CacheKey cacheKey;\n        BoundSql boundSql;\n        //由于逻辑关系，只会进入一次\n        if(args.length == 4){\n            //4 个参数时\n            boundSql = ms.getBoundSql(parameter);\n            cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);\n        } else {\n            //6 个参数时\n            cacheKey = (CacheKey) args[4];\n            boundSql = (BoundSql) args[5];\n        }\n        //TODO 自己要进行的各种处理\n        //注：下面的方法可以根据自己的逻辑调用多次，在分页插件中，count 和 page 各调用了一次\n        return executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);\n    }\n\n    @Override\n    public Object plugin(Object target) {\n        return Plugin.wrap(target, this);\n    }\n\n    @Override\n    public void setProperties(Properties properties) {\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/cache/Cache.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.cache;\n\n/**\n * Simple cache interface\n *\n * @author liuzh\n */\npublic interface Cache<K, V> {\n\n    V get(K key);\n\n    void put(K key, V value);\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/cache/CacheFactory.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.cache;\n\nimport com.github.pagehelper.PageException;\nimport com.github.pagehelper.PageProperties;\nimport com.github.pagehelper.util.StringUtil;\n\nimport java.lang.reflect.Constructor;\nimport java.util.Properties;\n\n/**\n * CacheFactory\n *\n * @author liuzh\n */\npublic abstract class CacheFactory {\n\n    /**\n     * 创建 SQL 缓存\n     *\n     * @param sqlCacheClass\n     * @return\n     */\n    public static <K, V> Cache<K, V> createCache(String sqlCacheClass, String prefix, Properties properties) {\n        if (StringUtil.isEmpty(sqlCacheClass)) {\n            try {\n                Class.forName(\"com.google.common.cache.Cache\");\n                return new GuavaCache<K, V>(properties, prefix);\n            } catch (Throwable t) {\n                return new SimpleCache<K, V>(properties, prefix);\n            }\n        } else {\n            try {\n                Class<? extends Cache> clazz = (Class<? extends Cache>) Class.forName(sqlCacheClass);\n                try {\n                    Constructor<? extends Cache> constructor = clazz.getConstructor(Properties.class, String.class);\n                    return constructor.newInstance(properties, prefix);\n                } catch (Exception e) {\n                    Cache cache = clazz.newInstance();\n                    if (cache instanceof PageProperties) {\n                        ((PageProperties) cache).setProperties(properties);\n                    }\n                    return cache;\n                }\n            } catch (Throwable t) {\n                throw new PageException(\"Created Sql Cache [\" + sqlCacheClass + \"] Error\", t);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/cache/GuavaCache.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.cache;\n\nimport com.github.pagehelper.util.StringUtil;\nimport com.google.common.cache.CacheBuilder;\n\nimport java.util.Properties;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Simple Guava Cache\n *\n * @author liuzh\n */\npublic class GuavaCache<K, V> implements Cache<K, V> {\n\n    private final com.google.common.cache.Cache<K, V> CACHE;\n\n    public GuavaCache(Properties properties, String prefix) {\n        CacheBuilder cacheBuilder = CacheBuilder.newBuilder();\n        String maximumSize = properties.getProperty(prefix + \".maximumSize\");\n        if (StringUtil.isNotEmpty(maximumSize)) {\n            cacheBuilder.maximumSize(Long.parseLong(maximumSize));\n        } else {\n            cacheBuilder.maximumSize(1000);\n        }\n        String expireAfterAccess = properties.getProperty(prefix + \".expireAfterAccess\");\n        if (StringUtil.isNotEmpty(expireAfterAccess)) {\n            cacheBuilder.expireAfterAccess(Long.parseLong(expireAfterAccess), TimeUnit.MILLISECONDS);\n        }\n        String expireAfterWrite = properties.getProperty(prefix + \".expireAfterWrite\");\n        if (StringUtil.isNotEmpty(expireAfterWrite)) {\n            cacheBuilder.expireAfterWrite(Long.parseLong(expireAfterWrite), TimeUnit.MILLISECONDS);\n        }\n        String initialCapacity = properties.getProperty(prefix + \".initialCapacity\");\n        if (StringUtil.isNotEmpty(initialCapacity)) {\n            cacheBuilder.initialCapacity(Integer.parseInt(initialCapacity));\n        }\n        CACHE = cacheBuilder.build();\n    }\n\n    @Override\n    public V get(K key) {\n        return CACHE.getIfPresent(key);\n    }\n\n    @Override\n    public void put(K key, V value) {\n        CACHE.put(key, value);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/cache/SimpleCache.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.cache;\n\nimport com.github.pagehelper.util.StringUtil;\nimport org.apache.ibatis.cache.decorators.FifoCache;\nimport org.apache.ibatis.cache.impl.PerpetualCache;\nimport org.apache.ibatis.mapping.CacheBuilder;\n\nimport java.util.Properties;\n\n/**\n * Simple MyBatis Cache\n *\n * @author liuzh\n */\npublic class SimpleCache<K, V> implements Cache<K, V> {\n\n    private final org.apache.ibatis.cache.Cache CACHE;\n\n    public SimpleCache(Properties properties, String prefix) {\n        CacheBuilder cacheBuilder = new CacheBuilder(\"SQL_CACHE\");\n        String typeClass = properties.getProperty(prefix + \".typeClass\");\n        if (StringUtil.isNotEmpty(typeClass)) {\n            try {\n                cacheBuilder.implementation((Class<? extends org.apache.ibatis.cache.Cache>) Class.forName(typeClass));\n            } catch (ClassNotFoundException e) {\n                cacheBuilder.implementation(PerpetualCache.class);\n            }\n        } else {\n            cacheBuilder.implementation(PerpetualCache.class);\n        }\n        String evictionClass = properties.getProperty(prefix + \".evictionClass\");\n        if (StringUtil.isNotEmpty(evictionClass)) {\n            try {\n                cacheBuilder.addDecorator((Class<? extends org.apache.ibatis.cache.Cache>) Class.forName(evictionClass));\n            } catch (ClassNotFoundException e) {\n                cacheBuilder.addDecorator(FifoCache.class);\n            }\n        } else {\n            cacheBuilder.addDecorator(FifoCache.class);\n        }\n        String flushInterval = properties.getProperty(prefix + \".flushInterval\");\n        if (StringUtil.isNotEmpty(flushInterval)) {\n            cacheBuilder.clearInterval(Long.parseLong(flushInterval));\n        }\n        String size = properties.getProperty(prefix + \".size\");\n        if (StringUtil.isNotEmpty(size)) {\n            cacheBuilder.size(Integer.parseInt(size));\n        }\n        cacheBuilder.properties(properties);\n        CACHE = cacheBuilder.build();\n    }\n\n    @Override\n    public V get(K key) {\n        Object value = CACHE.getObject(key);\n        if (value != null) {\n            return (V) value;\n        }\n        return null;\n    }\n\n    @Override\n    public void put(K key, V value) {\n        CACHE.putObject(key, value);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/AbstractDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect;\n\nimport com.github.pagehelper.Dialect;\nimport com.github.pagehelper.parser.CountSqlParser;\nimport com.github.pagehelper.parser.OrderBySqlParser;\nimport com.github.pagehelper.parser.defaults.DefaultCountSqlParser;\nimport com.github.pagehelper.parser.defaults.DefaultOrderBySqlParser;\nimport com.github.pagehelper.util.ClassUtil;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.session.RowBounds;\n\nimport java.util.Properties;\n\n/**\n * 基于 CountSqlParser 的智能 Count 查询\n *\n * @author liuzh\n */\npublic abstract class AbstractDialect implements Dialect {\n    //处理SQL\n    protected CountSqlParser   countSqlParser;\n    protected OrderBySqlParser orderBySqlParser;\n\n    @Override\n    public String getCountSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey countKey) {\n        return countSqlParser.getSmartCountSql(boundSql.getSql());\n    }\n\n    @Override\n    public void setProperties(Properties properties) {\n        this.countSqlParser = ClassUtil.newInstance(properties.getProperty(\"countSqlParser\"), CountSqlParser.class, properties, DefaultCountSqlParser::new);\n        this.orderBySqlParser = ClassUtil.newInstance(properties.getProperty(\"orderBySqlParser\"), OrderBySqlParser.class, properties, DefaultOrderBySqlParser::new);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/AbstractHelperDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect;\n\nimport com.github.pagehelper.Constant;\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageRowBounds;\nimport com.github.pagehelper.util.ExecutorUtil;\nimport com.github.pagehelper.util.MetaObjectUtil;\nimport com.github.pagehelper.util.StringUtil;\nimport org.apache.ibatis.builder.annotation.ProviderSqlSource;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.mapping.ParameterMapping;\nimport org.apache.ibatis.reflection.MetaObject;\nimport org.apache.ibatis.session.RowBounds;\n\nimport java.util.*;\n\n/**\n * 针对 PageHelper 的实现\n *\n * @author liuzh\n * @since 2016-12-04 14:32\n */\npublic abstract class AbstractHelperDialect extends AbstractDialect implements Constant {\n\n    /**\n     * 获取分页参数\n     *\n     * @param <T>\n     * @return\n     */\n    public <T> Page<T> getLocalPage() {\n        return PageHelper.getLocalPage();\n    }\n\n    @Override\n    public final boolean skip(MappedStatement ms, Object parameterObject, RowBounds rowBounds) {\n        //该方法不会被调用\n        return true;\n    }\n\n    @Override\n    public boolean beforeCount(MappedStatement ms, Object parameterObject, RowBounds rowBounds) {\n        Page page = getLocalPage();\n        return !page.isOrderByOnly() && page.isCount();\n    }\n\n    @Override\n    public String getCountSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey countKey) {\n        Page<Object> page = getLocalPage();\n        String countColumn = page.getCountColumn();\n        if (StringUtil.isNotEmpty(countColumn)) {\n            return countSqlParser.getSmartCountSql(boundSql.getSql(), countColumn);\n        }\n        return countSqlParser.getSmartCountSql(boundSql.getSql());\n    }\n\n    @Override\n    public boolean afterCount(long count, Object parameterObject, RowBounds rowBounds) {\n        Page page = getLocalPage();\n        page.setTotal(count);\n        if (rowBounds instanceof PageRowBounds) {\n            ((PageRowBounds) rowBounds).setTotal(count);\n        }\n        //pageSize < 0 的时候，不执行分页查询\n        //pageSize = 0 的时候，还需要执行后续查询，但是不会分页\n        if (page.getPageSizeZero() != null) {\n            //PageSizeZero=false&&pageSize<=0\n            if (!page.getPageSizeZero() && page.getPageSize() <= 0) {\n                return false;\n            }\n            //PageSizeZero=true&&pageSize<0 返回 false，只有>=0才需要执行后续的\n            else if (page.getPageSizeZero() && page.getPageSize() < 0) {\n                return false;\n            }\n        }\n        //页码>0 && 开始行数<总行数即可，不需要考虑 pageSize（上面的 if 已经处理不符合要求的值了）\n        return page.getPageNum() > 0 && count > page.getStartRow();\n    }\n\n    @Override\n    public Object processParameterObject(MappedStatement ms, Object parameterObject, BoundSql boundSql, CacheKey pageKey) {\n        //处理参数\n        Page page = getLocalPage();\n        //如果只是 order by 就不必处理参数\n        if (page.isOrderByOnly()) {\n            return parameterObject;\n        }\n        Map<String, Object> paramMap = null;\n        if (parameterObject == null) {\n            paramMap = new HashMap<String, Object>();\n        } else if (parameterObject instanceof Map) {\n            //解决不可变Map的情况\n            paramMap = new HashMap<String, Object>();\n            paramMap.putAll((Map) parameterObject);\n        } else {\n            paramMap = new HashMap<String, Object>();\n            // sqlSource为ProviderSqlSource时，处理只有1个参数的情况\n            if (ms.getSqlSource() instanceof ProviderSqlSource) {\n                String[] providerMethodArgumentNames = ExecutorUtil.getProviderMethodArgumentNames((ProviderSqlSource) ms.getSqlSource());\n                if (providerMethodArgumentNames != null && providerMethodArgumentNames.length == 1) {\n                    paramMap.put(providerMethodArgumentNames[0], parameterObject);\n                    paramMap.put(\"param1\", parameterObject);\n                }\n            }\n            //动态sql时的判断条件不会出现在ParameterMapping中，但是必须有，所以这里需要收集所有的getter属性\n            //TypeHandlerRegistry可以直接处理的会作为一个直接使用的对象进行处理\n            boolean hasTypeHandler = ms.getConfiguration().getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass());\n            MetaObject metaObject = MetaObjectUtil.forObject(parameterObject);\n            //需要针对注解形式的MyProviderSqlSource保存原值\n            if (!hasTypeHandler) {\n                for (String name : metaObject.getGetterNames()) {\n                    paramMap.put(name, metaObject.getValue(name));\n                }\n            }\n            //下面这段方法，主要解决一个常见类型的参数时的问题\n            if (boundSql.getParameterMappings() != null && boundSql.getParameterMappings().size() > 0) {\n                for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {\n                    String name = parameterMapping.getProperty();\n                    if (!name.equals(PAGEPARAMETER_FIRST)\n                            && !name.equals(PAGEPARAMETER_SECOND)\n                            && paramMap.get(name) == null) {\n                        if (hasTypeHandler\n                                || parameterMapping.getJavaType().equals(parameterObject.getClass())) {\n                            paramMap.put(name, parameterObject);\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n        return processPageParameter(ms, paramMap, page, boundSql, pageKey);\n    }\n\n    /**\n     * 处理分页参数\n     *\n     * @param ms\n     * @param paramMap\n     * @param page\n     * @param boundSql\n     * @param pageKey\n     * @return\n     */\n    public abstract Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey);\n\n    @Override\n    public boolean beforePage(MappedStatement ms, Object parameterObject, RowBounds rowBounds) {\n        Page page = getLocalPage();\n        if (page.isOrderByOnly() || page.getPageSize() > 0) {\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public String getPageSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey pageKey) {\n        String sql = boundSql.getSql();\n        Page page = getLocalPage();\n        //支持 order by\n        String orderBy = page.getOrderBy();\n        if (StringUtil.isNotEmpty(orderBy)) {\n            pageKey.update(orderBy);\n            sql = orderBySqlParser.converToOrderBySql(sql, orderBy);\n        }\n        if (page.isOrderByOnly()) {\n            return sql;\n        }\n        return getPageSql(sql, page, pageKey);\n    }\n\n    /**\n     * 单独处理分页部分\n     *\n     * @param sql\n     * @param page\n     * @param pageKey\n     * @return\n     */\n    public abstract String getPageSql(String sql, Page page, CacheKey pageKey);\n\n    @Override\n    public Object afterPage(List pageList, Object parameterObject, RowBounds rowBounds) {\n        Page page = getLocalPage();\n        if (page == null) {\n            return pageList;\n        }\n        page.addAll(pageList);\n        //调整判断顺序，如果查全部，total就是size，如果只排序，也是全部，其他情况下如果不查询count就是-1\n        if ((page.getPageSizeZero() != null && page.getPageSizeZero()) && page.getPageSize() == 0) {\n            page.setTotal(pageList.size());\n        } else if (page.isOrderByOnly()) {\n            page.setTotal(pageList.size());\n        } else if (!page.isCount()) {\n            page.setTotal(-1);\n        }\n        return page;\n    }\n\n    @Override\n    public void afterAll() {\n\n    }\n\n    @Override\n    public void setProperties(Properties properties) {\n        super.setProperties(properties);\n    }\n\n    /**\n     * @param boundSql\n     * @param ms\n     * @deprecated use {@code handleParameter(BoundSql boundSql, MappedStatement ms, Class<?> firstClass, Class<?> secondClass)}\n     */\n    @Deprecated\n    protected void handleParameter(BoundSql boundSql, MappedStatement ms) {\n        if (boundSql.getParameterMappings() != null) {\n            handleParameter(boundSql, ms, long.class, long.class);\n        }\n    }\n\n    protected void handleParameter(BoundSql boundSql, MappedStatement ms, Class<?> firstClass, Class<?> secondClass) {\n        if (boundSql.getParameterMappings() != null) {\n            List<ParameterMapping> newParameterMappings = new ArrayList<ParameterMapping>(boundSql.getParameterMappings());\n            newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, firstClass).build());\n            newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, secondClass).build());\n            MetaObject metaObject = MetaObjectUtil.forObject(boundSql);\n            metaObject.setValue(\"parameterMappings\", newParameterMappings);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/AbstractRowBoundsDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect;\n\nimport com.github.pagehelper.PageRowBounds;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.session.RowBounds;\n\nimport java.util.List;\nimport java.util.Properties;\n\n/**\n * 基于 RowBounds 的分页\n *\n * @author liuzh\n */\npublic abstract class AbstractRowBoundsDialect extends AbstractDialect {\n\n    @Override\n    public boolean skip(MappedStatement ms, Object parameterObject, RowBounds rowBounds) {\n        return rowBounds == RowBounds.DEFAULT;\n    }\n\n    @Override\n    public boolean beforeCount(MappedStatement ms, Object parameterObject, RowBounds rowBounds) {\n        if(rowBounds instanceof PageRowBounds){\n            PageRowBounds pageRowBounds = (PageRowBounds)rowBounds;\n            return pageRowBounds.getCount() == null || pageRowBounds.getCount();\n        }\n        return false;\n    }\n\n    @Override\n    public boolean afterCount(long count, Object parameterObject, RowBounds rowBounds) {\n        //由于 beforeCount 校验，这里一定是 PageRowBounds\n        ((PageRowBounds) rowBounds).setTotal(count);\n        return count > 0;\n    }\n\n    @Override\n    public Object processParameterObject(MappedStatement ms, Object parameterObject, BoundSql boundSql, CacheKey pageKey) {\n        return parameterObject;\n    }\n\n    @Override\n    public boolean beforePage(MappedStatement ms, Object parameterObject, RowBounds rowBounds) {\n        return true;\n    }\n\n    @Override\n    public String getPageSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey pageKey) {\n        String sql = boundSql.getSql();\n        return getPageSql(sql, rowBounds, pageKey);\n    }\n\n    public abstract String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey);\n\n    @Override\n    public Object afterPage(List pageList, Object parameterObject, RowBounds rowBounds) {\n        return pageList;\n    }\n\n    @Override\n    public void afterAll() {\n\n    }\n\n    @Override\n    public void setProperties(Properties properties) {\n        super.setProperties(properties);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/ReplaceSql.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect;\n\n/**\n * 替换和还原 SQL\n *\n * @author liuzh\n * @since 2017/8/23.\n */\npublic interface ReplaceSql {\n\n    /**\n     * 临时替换后用于 jsqlparser 解析\n     *\n     * @param sql\n     * @return\n     */\n    String replace(String sql);\n\n    /**\n     * 还原经过解析后的 sql\n     *\n     * @param sql\n     * @return\n     */\n    String restore(String sql);\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/auto/C3P0AutoDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.auto;\n\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\n\n/**\n * c3p0\n *\n * @author liuzh\n */\npublic class C3P0AutoDialect extends DataSourceAutoDialect<ComboPooledDataSource> {\n\n    @Override\n    public String getJdbcUrl(ComboPooledDataSource comboPooledDataSource) {\n        return comboPooledDataSource.getJdbcUrl();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/auto/DataSourceAutoDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.auto;\n\nimport com.github.pagehelper.AutoDialect;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport com.github.pagehelper.page.PageAutoDialect;\nimport org.apache.ibatis.mapping.MappedStatement;\n\nimport javax.sql.DataSource;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.util.Properties;\n\n/**\n * 使用 Hikari 连接池时，简单获取 jdbcUrl\n *\n * @author liuzh\n */\npublic abstract class DataSourceAutoDialect<Ds extends DataSource> implements AutoDialect<String> {\n    protected Class dataSourceClass;\n\n    public DataSourceAutoDialect() {\n        Type genericSuperclass = getClass().getGenericSuperclass();\n        dataSourceClass = (Class) ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];\n    }\n\n    public abstract String getJdbcUrl(Ds ds);\n\n    @Override\n    public String extractDialectKey(MappedStatement ms, DataSource dataSource, Properties properties) {\n        if (dataSourceClass.isInstance(dataSource)) {\n            return getJdbcUrl((Ds) dataSource);\n        }\n        return null;\n    }\n\n    @Override\n    public AbstractHelperDialect extractDialect(String dialectKey, MappedStatement ms, DataSource dataSource, Properties properties) {\n        String dialect = PageAutoDialect.fromJdbcUrl(dialectKey);\n        return PageAutoDialect.instanceDialect(dialect, properties);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/auto/DataSourceNegotiationAutoDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.auto;\n\nimport com.github.pagehelper.AutoDialect;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport org.apache.ibatis.mapping.MappedStatement;\n\nimport javax.sql.DataSource;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * 遍历所有实现，找到匹配的实现\n *\n * @author liuzh\n */\npublic class DataSourceNegotiationAutoDialect implements AutoDialect<String> {\n    private static final List<DataSourceAutoDialect>        AUTO_DIALECTS = new ArrayList<DataSourceAutoDialect>();\n    private              Map<String, DataSourceAutoDialect> urlMap        = new ConcurrentHashMap<String, DataSourceAutoDialect>();\n\n    static {\n        //创建时，初始化所有实现，当依赖的连接池不存在时，这里不会添加成功，所以理论上这里包含的内容不会多，执行时不会迭代多次\n        try {\n            AUTO_DIALECTS.add(new HikariAutoDialect());\n        } catch (Exception ignore) {\n        }\n        try {\n            AUTO_DIALECTS.add(new DruidAutoDialect());\n        } catch (Exception ignore) {\n        }\n        try {\n            AUTO_DIALECTS.add(new TomcatAutoDialect());\n        } catch (Exception ignore) {\n        }\n        try {\n            AUTO_DIALECTS.add(new C3P0AutoDialect());\n        } catch (Exception ignore) {\n        }\n        try {\n            AUTO_DIALECTS.add(new DbcpAutoDialect());\n        } catch (Exception ignore) {\n        }\n    }\n\n    /**\n     * 允许手工添加额外的实现，实际上没有必要\n     *\n     * @param autoDialect\n     */\n    public static void registerAutoDialect(DataSourceAutoDialect autoDialect) {\n        AUTO_DIALECTS.add(autoDialect);\n    }\n\n    @Override\n    public String extractDialectKey(MappedStatement ms, DataSource dataSource, Properties properties) {\n        for (DataSourceAutoDialect autoDialect : AUTO_DIALECTS) {\n            String dialectKey = autoDialect.extractDialectKey(ms, dataSource, properties);\n            if (dialectKey != null) {\n                if (!urlMap.containsKey(dialectKey)) {\n                    urlMap.put(dialectKey, autoDialect);\n                }\n                return dialectKey;\n            }\n        }\n        //都不匹配的时候使用默认方式\n        return DefaultAutoDialect.DEFAULT.extractDialectKey(ms, dataSource, properties);\n    }\n\n    @Override\n    public AbstractHelperDialect extractDialect(String dialectKey, MappedStatement ms, DataSource dataSource, Properties properties) {\n        if (dialectKey != null && urlMap.containsKey(dialectKey)) {\n            return urlMap.get(dialectKey).extractDialect(dialectKey, ms, dataSource, properties);\n        }\n        //都不匹配的时候使用默认方式\n        return DefaultAutoDialect.DEFAULT.extractDialect(dialectKey, ms, dataSource, properties);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/auto/DbcpAutoDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.auto;\n\nimport org.apache.commons.dbcp2.BasicDataSource;\n\n/**\n * commons-dbcp\n *\n * @author liuzh\n */\npublic class DbcpAutoDialect extends DataSourceAutoDialect<BasicDataSource> {\n\n    @Override\n    public String getJdbcUrl(BasicDataSource basicDataSource) {\n        return basicDataSource.getUrl();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/auto/DefaultAutoDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.auto;\n\nimport com.github.pagehelper.AutoDialect;\nimport com.github.pagehelper.PageException;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport com.github.pagehelper.page.PageAutoDialect;\nimport com.github.pagehelper.util.StringUtil;\nimport org.apache.ibatis.mapping.MappedStatement;\n\nimport javax.sql.DataSource;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.Properties;\n\n/**\n * 最初的默认实现，获取连接再获取 url，这种方式通用性强，但是性能低，处理不好关闭连接时容易出问题\n *\n * @author liuzh\n */\npublic class DefaultAutoDialect implements AutoDialect<String> {\n\n    public static final AutoDialect<String> DEFAULT = new DefaultAutoDialect();\n\n    @Override\n    public String extractDialectKey(MappedStatement ms, DataSource dataSource, Properties properties) {\n        Connection conn = null;\n        try {\n            conn = dataSource.getConnection();\n            return conn.getMetaData().getURL();\n        } catch (SQLException e) {\n            throw new PageException(e);\n        } finally {\n            if (conn != null) {\n                try {\n                    String closeConn = properties.getProperty(\"closeConn\");\n                    if (StringUtil.isEmpty(closeConn) || Boolean.parseBoolean(closeConn)) {\n                        conn.close();\n                    }\n                } catch (SQLException e) {\n                    //ignore\n                }\n            }\n        }\n    }\n\n    @Override\n    public AbstractHelperDialect extractDialect(String dialectKey, MappedStatement ms, DataSource dataSource, Properties properties) {\n        String dialectStr = PageAutoDialect.fromJdbcUrl(dialectKey);\n        if (dialectStr == null) {\n            throw new PageException(\"The database type cannot be obtained automatically, please specify it via the helperDialect parameter!\");\n        }\n        return PageAutoDialect.instanceDialect(dialectStr, properties);\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/auto/DruidAutoDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.auto;\n\nimport com.alibaba.druid.pool.DruidDataSource;\n\n/**\n * Druid\n *\n * @author liuzh\n */\npublic class DruidAutoDialect extends DataSourceAutoDialect<DruidDataSource> {\n\n    @Override\n    public String getJdbcUrl(DruidDataSource druidDataSource) {\n        return druidDataSource.getUrl();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/auto/HikariAutoDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.auto;\n\nimport com.zaxxer.hikari.HikariDataSource;\n\n/**\n * Hikari\n *\n * @author liuzh\n */\npublic class HikariAutoDialect extends DataSourceAutoDialect<HikariDataSource> {\n\n    @Override\n    public String getJdbcUrl(HikariDataSource hikariDataSource) {\n        return hikariDataSource.getJdbcUrl();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/auto/TomcatAutoDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.auto;\n\nimport org.apache.tomcat.jdbc.pool.DataSource;\n\n/**\n * tomcat-jdbc\n *\n * @author liuzh\n */\npublic class TomcatAutoDialect extends DataSourceAutoDialect<DataSource> {\n\n    @Override\n    public String getJdbcUrl(DataSource dataSource) {\n        return dataSource.getUrl();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/helper/AS400Dialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.helper;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\n\nimport java.util.Map;\n\n/**\n * @author bluezealot\n */\n@SuppressWarnings(\"rawtypes\")\npublic class AS400Dialect extends AbstractHelperDialect {\n\n\t@Override\n\tpublic Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap,\n\t\t\tPage page, BoundSql boundSql, CacheKey pageKey) {\n\t\tparamMap.put(PAGEPARAMETER_FIRST, page.getStartRow());\n\t\tparamMap.put(PAGEPARAMETER_SECOND, page.getPageSize());\n\t\tpageKey.update(page.getStartRow());\n\t\tpageKey.update(page.getPageSize());\n\t\thandleParameter(boundSql, ms, long.class, int.class);\n\t\treturn paramMap;\n\t}\n\n\t@Override\n\tpublic String getPageSql(String sql, Page page, CacheKey pageKey) {\n\t\treturn sql + \" OFFSET ? ROWS FETCH FIRST ? ROWS ONLY\";\n\t}\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/helper/CirroDataDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.helper;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\n\nimport java.util.Map;\n\n/**\n * @author sxh\n */\npublic class CirroDataDialect extends AbstractHelperDialect {\n    @Override\n    public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {\n        paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow() + 1);\n        paramMap.put(PAGEPARAMETER_SECOND, page.getEndRow());\n        //处理pageKey\n        pageKey.update(page.getStartRow() + 1);\n        pageKey.update(page.getEndRow());\n        //处理参数配置\n        handleParameter(boundSql, ms, long.class, long.class);\n        return paramMap;\n    }\n\n    @Override\n    public String getPageSql(String sql, Page page, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 16);\n        sqlBuilder.append(sql);\n        sqlBuilder.append(\"\\n LIMIT ( ?, ? )\");\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/helper/Db2Dialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.helper;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\n\nimport java.util.Map;\n\n/**\n * @author liuzh\n */\npublic class Db2Dialect extends AbstractHelperDialect {\n\n    @Override\n    public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {\n        paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow() + 1);\n        paramMap.put(PAGEPARAMETER_SECOND, page.getEndRow());\n        //处理pageKey\n        pageKey.update(page.getStartRow() + 1);\n        pageKey.update(page.getEndRow());\n        //处理参数配置\n        handleParameter(boundSql, ms, long.class, long.class);\n        return paramMap;\n    }\n\n    @Override\n    public String getPageSql(String sql, Page page, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 140);\n        sqlBuilder.append(\"SELECT * FROM (SELECT TMP_PAGE.*,ROWNUMBER() OVER() AS PAGEHELPER_ROW_ID FROM ( \\n\");\n        sqlBuilder.append(sql);\n        sqlBuilder.append(\"\\n ) AS TMP_PAGE) TMP_PAGE WHERE PAGEHELPER_ROW_ID BETWEEN ? AND ?\");\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/helper/FirebirdDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.helper;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\n\nimport java.util.Map;\n\n/**\n * firebirdsql数据库\n * <ul>\n * <li>https://firebirdsql.github.io/jaybird-manual/jaybird_manual.html</li>\n * <li>https://firebirdsql.org/file/documentation/chunk/en/refdocs/fblangref40/fblangref40-dml.html#fblangref40-dml-select-offsetfetch</li>\n * </ul>\n *\n * @author liuzh\n */\npublic class FirebirdDialect extends AbstractHelperDialect {\n\n    @Override\n    public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {\n        paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow());\n        paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize());\n        //处理pageKey\n        pageKey.update(page.getStartRow());\n        pageKey.update(page.getPageSize());\n        //处理参数配置\n        handleParameter(boundSql, ms, long.class, int.class);\n        return paramMap;\n    }\n\n    @Override\n    public String getPageSql(String sql, Page page, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 64);\n        sqlBuilder.append(sql);\n        sqlBuilder.append(\"\\n OFFSET ? ROWS FETCH NEXT ? ROWS ONLY \");\n        pageKey.update(page.getPageSize());\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/helper/GaussDBDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.helper;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport com.github.pagehelper.util.MetaObjectUtil;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.mapping.ParameterMapping;\nimport org.apache.ibatis.reflection.MetaObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * GaussDB 方言\n *\n * @author nieqiurong\n * @since 6.1.2\n */\npublic class GaussDBDialect extends AbstractHelperDialect {\n\n    @Override\n    public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {\n        paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow());\n        paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize());\n        pageKey.update(page.getStartRow());\n        pageKey.update(page.getPageSize());\n        if (boundSql.getParameterMappings() != null) {\n            List<ParameterMapping> newParameterMappings = new ArrayList<ParameterMapping>(boundSql.getParameterMappings());\n            if (page.getStartRow() == 0) {\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build());\n            } else {\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, long.class).build());\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build());\n            }\n            MetaObject metaObject = MetaObjectUtil.forObject(boundSql);\n            metaObject.setValue(\"parameterMappings\", newParameterMappings);\n        }\n        return paramMap;\n    }\n\n    /**\n     * 构建 <a href=\"https://support.huaweicloud.com/centralized-devg-v8-gaussdb/gaussdb-42-1702.html\">GaussDB</a>分页查询语句\n     */\n    @Override\n    public String getPageSql(String sql, Page page, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);\n        sqlBuilder.append(sql);\n        if (page.getStartRow() == 0) {\n            sqlBuilder.append(\" LIMIT ? \");\n        } else {\n            sqlBuilder.append(\" LIMIT ?, ? \");\n        }\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/helper/HerdDBDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.helper;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport com.github.pagehelper.util.MetaObjectUtil;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.mapping.ParameterMapping;\nimport org.apache.ibatis.reflection.MetaObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Support for HerdDB https://github.com/diennea/herddb. It is mostly the same as MySQL\n * @author Enrico Olivelli\n */\npublic class HerdDBDialect extends AbstractHelperDialect {\n\n    @Override\n    public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {\n        paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow());\n        paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize());\n        pageKey.update(page.getStartRow());\n        pageKey.update(page.getPageSize());\n        if (boundSql.getParameterMappings() != null) {\n            List<ParameterMapping> newParameterMappings = new ArrayList<ParameterMapping>(boundSql.getParameterMappings());\n            if (page.getStartRow() == 0) {\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build());\n            } else {\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, long.class).build());\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build());\n            }\n            MetaObject metaObject = MetaObjectUtil.forObject(boundSql);\n            metaObject.setValue(\"parameterMappings\", newParameterMappings);\n        }\n        return paramMap;\n    }\n\n    @Override\n    public String getPageSql(String sql, Page page, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);\n        sqlBuilder.append(sql);\n        if (page.getStartRow() == 0) {\n            sqlBuilder.append(\"\\n LIMIT ? \");\n        } else {\n            sqlBuilder.append(\"\\n LIMIT ?, ? \");\n        }\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/helper/HsqldbDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.helper;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport com.github.pagehelper.util.MetaObjectUtil;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.mapping.ParameterMapping;\nimport org.apache.ibatis.reflection.MetaObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @author liuzh\n */\npublic class HsqldbDialect extends AbstractHelperDialect {\n\n    @Override\n    public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {\n        paramMap.put(PAGEPARAMETER_FIRST, page.getPageSize());\n        paramMap.put(PAGEPARAMETER_SECOND, page.getStartRow());\n        //处理pageKey\n        pageKey.update(page.getPageSize());\n        pageKey.update(page.getStartRow());\n        //处理参数配置\n        if (boundSql.getParameterMappings() != null) {\n            List<ParameterMapping> newParameterMappings = new ArrayList<ParameterMapping>(boundSql.getParameterMappings());\n            if (page.getPageSize() > 0) {\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, int.class).build());\n            }\n            if (page.getStartRow() > 0) {\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, long.class).build());\n            }\n            MetaObject metaObject = MetaObjectUtil.forObject(boundSql);\n            metaObject.setValue(\"parameterMappings\", newParameterMappings);\n        }\n        return paramMap;\n    }\n\n    @Override\n    public String getPageSql(String sql, Page page, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 20);\n        sqlBuilder.append(sql);\n        if (page.getPageSize() > 0) {\n            sqlBuilder.append(\"\\n LIMIT ? \");\n        }\n        if (page.getStartRow() > 0) {\n            sqlBuilder.append(\"\\n OFFSET ? \");\n        }\n        return sqlBuilder.toString();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/helper/InformixDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.helper;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport com.github.pagehelper.util.MetaObjectUtil;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.mapping.ParameterMapping;\nimport org.apache.ibatis.reflection.MetaObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @author liuzh\n */\npublic class InformixDialect extends AbstractHelperDialect {\n\n    @Override\n    public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {\n        paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow());\n        paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize());\n        //处理pageKey\n        pageKey.update(page.getStartRow());\n        pageKey.update(page.getPageSize());\n        //处理参数配置\n        if (boundSql.getParameterMappings() != null) {\n            List<ParameterMapping> newParameterMappings = new ArrayList<ParameterMapping>();\n            if (page.getStartRow() > 0) {\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, long.class).build());\n            }\n            if (page.getPageSize() > 0) {\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build());\n            }\n            newParameterMappings.addAll(boundSql.getParameterMappings());\n            MetaObject metaObject = MetaObjectUtil.forObject(boundSql);\n            metaObject.setValue(\"parameterMappings\", newParameterMappings);\n        }\n        return paramMap;\n    }\n\n    @Override\n    public String getPageSql(String sql, Page page, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 40);\n        sqlBuilder.append(\"SELECT \");\n        if (page.getStartRow() > 0) {\n            sqlBuilder.append(\" SKIP ? \");\n        }\n        if (page.getPageSize() > 0) {\n            sqlBuilder.append(\" FIRST ? \");\n        }\n        sqlBuilder.append(\" * FROM ( \\n\");\n        sqlBuilder.append(sql);\n        sqlBuilder.append(\"\\n ) TEMP_T \");\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/helper/MySqlDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.helper;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport com.github.pagehelper.util.MetaObjectUtil;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.mapping.ParameterMapping;\nimport org.apache.ibatis.reflection.MetaObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @author liuzh\n */\npublic class MySqlDialect extends AbstractHelperDialect {\n\n    @Override\n    public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {\n        paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow());\n        paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize());\n        //处理pageKey\n        pageKey.update(page.getStartRow());\n        pageKey.update(page.getPageSize());\n        //处理参数配置\n        if (boundSql.getParameterMappings() != null) {\n            List<ParameterMapping> newParameterMappings = new ArrayList<ParameterMapping>(boundSql.getParameterMappings());\n            if (page.getStartRow() == 0) {\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build());\n            } else {\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, long.class).build());\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build());\n            }\n            MetaObject metaObject = MetaObjectUtil.forObject(boundSql);\n            metaObject.setValue(\"parameterMappings\", newParameterMappings);\n        }\n        return paramMap;\n    }\n\n    @Override\n    public String getPageSql(String sql, Page page, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);\n        sqlBuilder.append(sql);\n        if (page.getStartRow() == 0) {\n            sqlBuilder.append(\"\\n LIMIT ? \");\n        } else {\n            sqlBuilder.append(\"\\n LIMIT ?, ? \");\n        }\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/helper/Oracle9iDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.helper;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\n\nimport java.util.Map;\n\n/**\n * 参考\n * <ul>\n *     <li>https://github.com/pagehelper/Mybatis-PageHelper/pull/476</li>\n *     <li>https://github.com/hibernate/hibernate-orm/search?utf8=%E2%9C%93&q=rownum&type=</li>\n * </ul>\n * @author liuzh\n */\npublic class Oracle9iDialect extends AbstractHelperDialect {\n\n    @Override\n    public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {\n        paramMap.put(PAGEPARAMETER_FIRST, page.getEndRow());\n        paramMap.put(PAGEPARAMETER_SECOND, page.getStartRow());\n        //处理pageKey\n        pageKey.update(page.getEndRow());\n        pageKey.update(page.getStartRow());\n        //处理参数配置\n        handleParameter(boundSql, ms, long.class, long.class);\n        return paramMap;\n    }\n\n    @Override\n    public String getPageSql(String sql, Page page, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 120);\n        sqlBuilder.append(\"SELECT * FROM ( \");\n        sqlBuilder.append(\" SELECT TMP_PAGE.*, ROWNUM PAGEHELPER_ROW_ID FROM ( \\n\");\n        sqlBuilder.append(sql);\n        sqlBuilder.append(\"\\n ) TMP_PAGE WHERE ROWNUM <= ? \");\n        sqlBuilder.append(\" ) WHERE PAGEHELPER_ROW_ID > ? \");\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/helper/OracleDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.helper;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\n\nimport java.util.Map;\n\n/**\n * @author liuzh\n */\npublic class OracleDialect extends AbstractHelperDialect {\n\n    @Override\n    public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {\n        paramMap.put(PAGEPARAMETER_FIRST, page.getEndRow());\n        paramMap.put(PAGEPARAMETER_SECOND, page.getStartRow());\n        //处理pageKey\n        pageKey.update(page.getEndRow());\n        pageKey.update(page.getStartRow());\n        //处理参数配置\n        handleParameter(boundSql, ms, long.class, long.class);\n        return paramMap;\n    }\n\n    @Override\n    public String getPageSql(String sql, Page page, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 120);\n        sqlBuilder.append(\"SELECT * FROM ( \");\n        sqlBuilder.append(\" SELECT TMP_PAGE.*, ROWNUM PAGEHELPER_ROW_ID FROM ( \\n\");\n        sqlBuilder.append(sql);\n        sqlBuilder.append(\"\\n ) TMP_PAGE)\");\n        sqlBuilder.append(\" WHERE PAGEHELPER_ROW_ID <= ? AND PAGEHELPER_ROW_ID > ?\");\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/helper/OscarDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.helper;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport com.github.pagehelper.util.MetaObjectUtil;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.mapping.ParameterMapping;\nimport org.apache.ibatis.reflection.MetaObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n *\n */\npublic class OscarDialect extends AbstractHelperDialect {\n\n    @Override\n    public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {\n        paramMap.put(PAGEPARAMETER_FIRST, page.getPageSize() );\n        paramMap.put(PAGEPARAMETER_SECOND, (int) page.getStartRow() );\n        //处理pageKey\n        pageKey.update(page.getStartRow());\n        pageKey.update(page.getPageSize());\n        //处理参数配置\n        if (boundSql.getParameterMappings() != null) {\n            List<ParameterMapping> newParameterMappings = new ArrayList<ParameterMapping>(boundSql.getParameterMappings());\n            if (page.getStartRow() == 0) {\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, int.class).build());\n            } else {\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, int.class).build());\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build());\n            }\n            MetaObject metaObject = MetaObjectUtil.forObject(boundSql);\n            metaObject.setValue(\"parameterMappings\", newParameterMappings);\n        }\n        return paramMap;\n    }\n\n    @Override\n    public String getPageSql(String sql, Page page, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);\n        sqlBuilder.append(sql);\n        if (page.getStartRow() == 0) {\n            sqlBuilder.append(\"\\n LIMIT ? \");\n        } else {\n            sqlBuilder.append(\"\\n LIMIT ? OFFSET ? \");\n        }\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/helper/PostgreSqlDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.helper;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport com.github.pagehelper.util.MetaObjectUtil;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.mapping.ParameterMapping;\nimport org.apache.ibatis.reflection.MetaObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * PostgreSQL 方言.\n *\n * @author liym\n * @since 2021-02-06\n */\npublic class PostgreSqlDialect extends AbstractHelperDialect {\n\n    @Override\n    public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {\n        paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize());\n        paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow());\n        //处理pageKey\n        pageKey.update(page.getPageSize());\n        pageKey.update(page.getStartRow());\n        //处理参数配置\n        if (boundSql.getParameterMappings() != null) {\n            List<ParameterMapping> newParameterMappings = new ArrayList<ParameterMapping>(boundSql.getParameterMappings());\n            if (page.getStartRow() == 0) {\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build());\n            } else {\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build());\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, long.class).build());\n            }\n            MetaObject metaObject = MetaObjectUtil.forObject(boundSql);\n            metaObject.setValue(\"parameterMappings\", newParameterMappings);\n        }\n        return paramMap;\n    }\n\n    /**\n     * 构建 <a href=\"https://www.postgresql.org/docs/current/queries-limit.html\">PostgreSQL</a>分页查询语句\n     */\n    @Override\n    public String getPageSql(String sql, Page page, CacheKey pageKey) {\n        StringBuilder sqlStr = new StringBuilder(sql.length() + 17);\n        sqlStr.append(sql);\n        if (page.getStartRow() == 0) {\n            sqlStr.append(\" LIMIT ?\");\n        } else {\n            sqlStr.append(\" LIMIT ? OFFSET ?\");\n        }\n        return sqlStr.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/helper/SqlServer2012Dialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.helper;\n\nimport com.github.pagehelper.Page;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\n\nimport java.util.Map;\n\n/**\n * @author liuzh\n */\npublic class SqlServer2012Dialect extends SqlServerDialect {\n\n    @Override\n    public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {\n        paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow());\n        paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize());\n        //处理pageKey\n        pageKey.update(page.getStartRow());\n        pageKey.update(page.getPageSize());\n        //处理参数配置\n        handleParameter(boundSql, ms, long.class, int.class);\n        return paramMap;\n    }\n\n    @Override\n    public String getPageSql(String sql, Page page, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 64);\n        sqlBuilder.append(sql);\n        sqlBuilder.append(\"\\n OFFSET ? ROWS FETCH NEXT ? ROWS ONLY \");\n        pageKey.update(page.getPageSize());\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/helper/SqlServerDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.helper;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.cache.Cache;\nimport com.github.pagehelper.cache.CacheFactory;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport com.github.pagehelper.dialect.ReplaceSql;\nimport com.github.pagehelper.dialect.replace.RegexWithNolockReplaceSql;\nimport com.github.pagehelper.dialect.replace.SimpleWithNolockReplaceSql;\nimport com.github.pagehelper.parser.SqlServerSqlParser;\nimport com.github.pagehelper.parser.defaults.DefaultSqlServerSqlParser;\nimport com.github.pagehelper.util.ClassUtil;\nimport com.github.pagehelper.util.StringUtil;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.session.RowBounds;\n\nimport java.util.Map;\nimport java.util.Properties;\n\n/**\n * @author liuzh\n */\npublic class SqlServerDialect extends AbstractHelperDialect {\n    protected SqlServerSqlParser sqlServerSqlParser;\n    protected Cache<String, String> CACHE_COUNTSQL;\n    protected Cache<String, String> CACHE_PAGESQL;\n    protected ReplaceSql            replaceSql;\n\n    @Override\n    public String getCountSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey countKey) {\n        String sql = boundSql.getSql();\n        String cacheSql = CACHE_COUNTSQL.get(sql);\n        if (cacheSql != null) {\n            return cacheSql;\n        } else {\n            cacheSql = sql;\n        }\n        cacheSql = replaceSql.replace(cacheSql);\n        cacheSql = countSqlParser.getSmartCountSql(cacheSql);\n        cacheSql = replaceSql.restore(cacheSql);\n        CACHE_COUNTSQL.put(sql, cacheSql);\n        return cacheSql;\n    }\n\n    @Override\n    public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {\n        return paramMap;\n    }\n\n    @Override\n    public String getPageSql(String sql, Page page, CacheKey pageKey) {\n        //处理pageKey\n        pageKey.update(page.getStartRow());\n        pageKey.update(page.getPageSize());\n        String cacheSql = CACHE_PAGESQL.get(sql);\n        if (cacheSql == null) {\n            cacheSql = sql;\n            cacheSql = replaceSql.replace(cacheSql);\n            cacheSql = sqlServerSqlParser.convertToPageSql(cacheSql, null, null);\n            cacheSql = replaceSql.restore(cacheSql);\n            CACHE_PAGESQL.put(sql, cacheSql);\n        }\n        cacheSql = cacheSql.replace(String.valueOf(Long.MIN_VALUE), String.valueOf(page.getStartRow()));\n        cacheSql = cacheSql.replace(String.valueOf(Long.MAX_VALUE), String.valueOf(page.getPageSize()));\n        return cacheSql;\n    }\n\n    /**\n     * 分页查询，pageHelper转换SQL时报错with(nolock)不识别的问题，\n     * 重写父类AbstractHelperDialect.getPageSql转换出错的方法。\n     * 1. this.replaceSql.replace(sql);先转换成假的表名\n     * 2. 然后进行SQL转换\n     * 3. this.replaceSql.restore(sql);最后再恢复成真的with(nolock)\n     */\n    @Override\n    public String getPageSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey pageKey) {\n        String sql = boundSql.getSql();\n        Page page = this.getLocalPage();\n        String orderBy = page.getOrderBy();\n        if (StringUtil.isNotEmpty(orderBy)) {\n            pageKey.update(orderBy);\n            sql = this.replaceSql.replace(sql);\n            sql = orderBySqlParser.converToOrderBySql(sql, orderBy);\n            sql = this.replaceSql.restore(sql);\n        }\n\n        return page.isOrderByOnly() ? sql : this.getPageSql(sql, page, pageKey);\n    }\n\n    @Override\n    public void setProperties(Properties properties) {\n        super.setProperties(properties);\n        this.sqlServerSqlParser = ClassUtil.newInstance(properties.getProperty(\"sqlServerSqlParser\"), SqlServerSqlParser.class, properties, DefaultSqlServerSqlParser::new);\n        String replaceSql = properties.getProperty(\"replaceSql\");\n        if (StringUtil.isEmpty(replaceSql) || \"regex\".equalsIgnoreCase(replaceSql)) {\n            this.replaceSql = new RegexWithNolockReplaceSql();\n        } else if (\"simple\".equalsIgnoreCase(replaceSql)) {\n            this.replaceSql = new SimpleWithNolockReplaceSql();\n        } else {\n            this.replaceSql = ClassUtil.newInstance(replaceSql, properties);\n        }\n        String sqlCacheClass = properties.getProperty(\"sqlCacheClass\");\n        if (StringUtil.isNotEmpty(sqlCacheClass) && !sqlCacheClass.equalsIgnoreCase(\"false\")) {\n            CACHE_COUNTSQL = CacheFactory.createCache(sqlCacheClass, \"count\", properties);\n            CACHE_PAGESQL = CacheFactory.createCache(sqlCacheClass, \"page\", properties);\n        } else {\n            CACHE_COUNTSQL = CacheFactory.createCache(null, \"count\", properties);\n            CACHE_PAGESQL = CacheFactory.createCache(null, \"page\", properties);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/helper/XuguDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2017 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.helper;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport com.github.pagehelper.util.MetaObjectUtil;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.mapping.ParameterMapping;\nimport org.apache.ibatis.reflection.MetaObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @author liuzh\n */\npublic class XuguDialect extends AbstractHelperDialect {\n\n    @Override\n    public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {\n        paramMap.put(PAGEPARAMETER_FIRST, page.getStartRow());\n        paramMap.put(PAGEPARAMETER_SECOND, page.getPageSize());\n        //处理pageKey\n        pageKey.update(page.getStartRow());\n        pageKey.update(page.getPageSize());\n        //处理参数配置\n        if (boundSql.getParameterMappings() != null) {\n            List<ParameterMapping> newParameterMappings = new ArrayList<ParameterMapping>(boundSql.getParameterMappings());\n            if (page.getStartRow() == 0) {\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build());\n            } else {\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_FIRST, long.class).build());\n                newParameterMappings.add(new ParameterMapping.Builder(ms.getConfiguration(), PAGEPARAMETER_SECOND, int.class).build());\n            }\n            MetaObject metaObject = MetaObjectUtil.forObject(boundSql);\n            metaObject.setValue(\"parameterMappings\", newParameterMappings);\n        }\n        return paramMap;\n    }\n\n    @Override\n    public String getPageSql(String sql, Page page, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);\n        sqlBuilder.append(sql);\n        if (page.getStartRow() == 0) {\n            sqlBuilder.append(\"\\n LIMIT ? \");\n        } else {\n            sqlBuilder.append(\"\\n LIMIT ?, ? \");\n        }\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/replace/RegexWithNolockReplaceSql.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.replace;\n\nimport com.github.pagehelper.dialect.ReplaceSql;\n\n/**\n * 正则处理 with(nolock)，转换为一个 table_PAGEWITHNOLOCK\n *\n * @author liuzh\n * @since 2017/8/23.\n */\npublic class RegexWithNolockReplaceSql implements ReplaceSql {\n\n    //with(nolock)\n    protected String WITHNOLOCK = \", PAGEWITHNOLOCK\";\n\n    @Override\n    public String replace(String sql) {\n        return sql.replaceAll(\"((?i)\\\\s*(\\\\w+)\\\\s*with\\\\s*\\\\(\\\\s*nolock\\\\s*\\\\))\", \" $2_PAGEWITHNOLOCK\");\n    }\n\n    @Override\n    public String restore(String sql) {\n        return sql.replaceAll(\"\\\\s*(\\\\w*?)_PAGEWITHNOLOCK\", \" $1 WITH(NOLOCK)\");\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/replace/SimpleWithNolockReplaceSql.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.replace;\n\nimport com.github.pagehelper.dialect.ReplaceSql;\n\n/**\n * 简单处理 with(nolock)\n *\n * @author liuzh\n * @since 2017/8/23.\n */\npublic class SimpleWithNolockReplaceSql implements ReplaceSql {\n\n    //with(nolock)\n    protected String WITHNOLOCK = \", PAGEWITHNOLOCK\";\n\n    @Override\n    public String replace(String sql) {\n        return sql.replaceAll(\"((?i)with\\\\s*\\\\(nolock\\\\))\", WITHNOLOCK);\n    }\n\n    @Override\n    public String restore(String sql) {\n        return sql.replaceAll(WITHNOLOCK, \" with(nolock)\");\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/rowbounds/Db2RowBoundsDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.rowbounds;\n\nimport com.github.pagehelper.dialect.AbstractRowBoundsDialect;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.session.RowBounds;\n\n/**\n * db2 基于 RowBounds 的分页\n *\n * @author liuzh\n */\npublic class Db2RowBoundsDialect extends AbstractRowBoundsDialect {\n\n    @Override\n    public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) {\n        int startRow = rowBounds.getOffset() + 1;\n        int endRow = rowBounds.getOffset() + rowBounds.getLimit();\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 120);\n        sqlBuilder.append(\"SELECT * FROM (SELECT TMP_PAGE.*,ROWNUMBER() OVER() AS PAGEHELPER_ROW_ID FROM ( \\n\");\n        sqlBuilder.append(sql);\n        sqlBuilder.append(\"\\n ) AS TMP_PAGE) TMP_PAGE WHERE PAGEHELPER_ROW_ID BETWEEN \");\n        sqlBuilder.append(startRow);\n        sqlBuilder.append(\" AND \");\n        sqlBuilder.append(endRow);\n        pageKey.update(startRow);\n        pageKey.update(endRow);\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/rowbounds/GaussDBRowBoundsDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.rowbounds;\n\nimport com.github.pagehelper.dialect.AbstractRowBoundsDialect;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.session.RowBounds;\n\n/**\n * GaussDB 基于 RowBounds 的分页.\n *\n * @author nieqiurong\n * @since 6.1.2\n */\npublic class GaussDBRowBoundsDialect extends AbstractRowBoundsDialect {\n\n    /**\n     * 构建 <a href=\"https://support.huaweicloud.com/centralized-devg-v8-gaussdb/gaussdb-42-1702.html\">GaussDB</a>分页查询语句\n     */\n    @Override\n    public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);\n        sqlBuilder.append(sql);\n        if (rowBounds.getOffset() == 0) {\n            sqlBuilder.append(\" LIMIT \");\n            sqlBuilder.append(rowBounds.getLimit());\n        } else {\n            sqlBuilder.append(\" LIMIT \");\n            sqlBuilder.append(rowBounds.getOffset());\n            sqlBuilder.append(\",\");\n            sqlBuilder.append(rowBounds.getLimit());\n            pageKey.update(rowBounds.getOffset());\n        }\n        pageKey.update(rowBounds.getLimit());\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/rowbounds/HerdDBRowBoundsDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.rowbounds;\n\nimport com.github.pagehelper.dialect.AbstractRowBoundsDialect;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.session.RowBounds;\n\n/**\n * HerdDB 基于 RowBounds 的分页\n *\n * @author Enrico Olivelli\n */\npublic class HerdDBRowBoundsDialect extends AbstractRowBoundsDialect {\n\n    @Override\n    public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);\n        sqlBuilder.append(sql);\n        if (rowBounds.getOffset() == 0) {\n            sqlBuilder.append(\"\\n LIMIT \");\n            sqlBuilder.append(rowBounds.getLimit());\n        } else {\n            sqlBuilder.append(\"\\n LIMIT \");\n            sqlBuilder.append(rowBounds.getOffset());\n            sqlBuilder.append(\",\");\n            sqlBuilder.append(rowBounds.getLimit());\n            pageKey.update(rowBounds.getOffset());\n        }\n        pageKey.update(rowBounds.getLimit());\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/rowbounds/HsqldbRowBoundsDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.rowbounds;\n\nimport com.github.pagehelper.dialect.AbstractRowBoundsDialect;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.session.RowBounds;\n\n/**\n * hsqldb 基于 RowBounds 的分页\n *\n * @author liuzh\n */\npublic class HsqldbRowBoundsDialect extends AbstractRowBoundsDialect {\n\n    @Override\n    public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 20);\n        sqlBuilder.append(sql);\n        if (rowBounds.getLimit() > 0) {\n            sqlBuilder.append(\"\\n LIMIT \");\n            sqlBuilder.append(rowBounds.getLimit());\n            pageKey.update(rowBounds.getLimit());\n        }\n        if (rowBounds.getOffset() > 0) {\n            sqlBuilder.append(\"\\n OFFSET \");\n            sqlBuilder.append(rowBounds.getOffset());\n            pageKey.update(rowBounds.getOffset());\n        }\n        return sqlBuilder.toString();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/rowbounds/InformixRowBoundsDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.rowbounds;\n\nimport com.github.pagehelper.dialect.AbstractRowBoundsDialect;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.session.RowBounds;\n\n/**\n * informix 基于 RowBounds 的分页\n *\n * @author liuzh\n */\npublic class InformixRowBoundsDialect extends AbstractRowBoundsDialect {\n\n    @Override\n    public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 40);\n        sqlBuilder.append(\"SELECT \");\n        if (rowBounds.getOffset() > 0) {\n            sqlBuilder.append(\" SKIP \");\n            sqlBuilder.append(rowBounds.getOffset());\n            pageKey.update(rowBounds.getOffset());\n        }\n        if (rowBounds.getLimit() > 0) {\n            sqlBuilder.append(\" FIRST \");\n            sqlBuilder.append(rowBounds.getLimit());\n            pageKey.update(rowBounds.getLimit());\n        }\n        sqlBuilder.append(\" * FROM ( \\n\");\n        sqlBuilder.append(sql);\n        sqlBuilder.append(\"\\n ) TEMP_T\");\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/rowbounds/MySqlRowBoundsDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.rowbounds;\n\nimport com.github.pagehelper.dialect.AbstractRowBoundsDialect;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.session.RowBounds;\n\n/**\n * mysql 基于 RowBounds 的分页\n *\n * @author liuzh\n */\npublic class MySqlRowBoundsDialect extends AbstractRowBoundsDialect {\n\n    @Override\n    public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);\n        sqlBuilder.append(sql);\n        if (rowBounds.getOffset() == 0) {\n            sqlBuilder.append(\"\\n LIMIT \");\n            sqlBuilder.append(rowBounds.getLimit());\n        } else {\n            sqlBuilder.append(\"\\n LIMIT \");\n            sqlBuilder.append(rowBounds.getOffset());\n            sqlBuilder.append(\",\");\n            sqlBuilder.append(rowBounds.getLimit());\n            pageKey.update(rowBounds.getOffset());\n        }\n        pageKey.update(rowBounds.getLimit());\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/rowbounds/OracleRowBoundsDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.rowbounds;\n\nimport com.github.pagehelper.dialect.AbstractRowBoundsDialect;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.session.RowBounds;\n\n/**\n * oracle 基于 RowBounds 的分页\n *\n * @author liuzh\n */\npublic class OracleRowBoundsDialect extends AbstractRowBoundsDialect {\n\n    @Override\n    public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) {\n        int startRow = rowBounds.getOffset();\n        int endRow = rowBounds.getOffset() + rowBounds.getLimit();\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 120);\n        if (startRow > 0) {\n            sqlBuilder.append(\"SELECT * FROM ( \");\n        }\n        if (endRow > 0) {\n            sqlBuilder.append(\" SELECT TMP_PAGE.*, ROWNUM PAGEHELPER_ROW_ID FROM ( \");\n        }\n        sqlBuilder.append(\"\\n\");\n        sqlBuilder.append(sql);\n        sqlBuilder.append(\"\\n\");\n        if (endRow > 0) {\n            sqlBuilder.append(\" ) TMP_PAGE WHERE ROWNUM <= \");\n            sqlBuilder.append(endRow);\n            pageKey.update(endRow);\n        }\n        if (startRow > 0) {\n            sqlBuilder.append(\" ) WHERE PAGEHELPER_ROW_ID > \");\n            sqlBuilder.append(startRow);\n            pageKey.update(startRow);\n        }\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/rowbounds/PostgreSqlRowBoundsDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.rowbounds;\n\nimport com.github.pagehelper.dialect.AbstractRowBoundsDialect;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.session.RowBounds;\n\n/**\n * PostgreSQL 基于 RowBounds 的分页.\n *\n * @author liym\n * @since 2021-02-06 19:31 新建\n */\npublic class PostgreSqlRowBoundsDialect extends AbstractRowBoundsDialect {\n\n    /**\n     * 构建 <a href=\"https://www.postgresql.org/docs/current/queries-limit.html\">PostgreSQL</a>分页查询语句\n     */\n    @Override\n    public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) {\n        StringBuilder sqlStr = new StringBuilder(sql.length() + 17);\n        sqlStr.append(sql);\n        if (rowBounds.getOffset() == 0) {\n            sqlStr.append(\" LIMIT \");\n            sqlStr.append(rowBounds.getLimit());\n        } else {\n            sqlStr.append(\" LIMIT \");\n            sqlStr.append(rowBounds.getLimit());\n            sqlStr.append(\" OFFSET \");\n            sqlStr.append(rowBounds.getOffset());\n            pageKey.update(rowBounds.getOffset());\n        }\n        pageKey.update(rowBounds.getLimit());\n        return sqlStr.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/rowbounds/SqlServer2012RowBoundsDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.rowbounds;\n\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.session.RowBounds;\n\n/**\n * sqlserver2012 基于 RowBounds 的分页\n *\n * @author liuzh\n */\npublic class SqlServer2012RowBoundsDialect extends SqlServerRowBoundsDialect {\n\n    @Override\n    public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);\n        sqlBuilder.append(sql);\n        sqlBuilder.append(\"\\n OFFSET \");\n        sqlBuilder.append(rowBounds.getOffset());\n        sqlBuilder.append(\" ROWS \");\n        pageKey.update(rowBounds.getOffset());\n        sqlBuilder.append(\" FETCH NEXT \");\n        sqlBuilder.append(rowBounds.getLimit());\n        sqlBuilder.append(\" ROWS ONLY\");\n        pageKey.update(rowBounds.getLimit());\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/rowbounds/SqlServerRowBoundsDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.rowbounds;\n\nimport com.github.pagehelper.dialect.AbstractRowBoundsDialect;\nimport com.github.pagehelper.dialect.ReplaceSql;\nimport com.github.pagehelper.dialect.replace.RegexWithNolockReplaceSql;\nimport com.github.pagehelper.dialect.replace.SimpleWithNolockReplaceSql;\nimport com.github.pagehelper.parser.SqlServerSqlParser;\nimport com.github.pagehelper.parser.defaults.DefaultSqlServerSqlParser;\nimport com.github.pagehelper.util.ClassUtil;\nimport com.github.pagehelper.util.StringUtil;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.session.RowBounds;\n\nimport java.util.Properties;\n\n/**\n * sqlserver 基于 RowBounds 的分页\n *\n * @author liuzh\n */\npublic class SqlServerRowBoundsDialect extends AbstractRowBoundsDialect {\n    protected SqlServerSqlParser sqlServerSqlParser;\n    protected ReplaceSql         replaceSql;\n\n    @Override\n    public String getCountSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey countKey) {\n        String sql = boundSql.getSql();\n        sql = replaceSql.replace(sql);\n        sql = countSqlParser.getSmartCountSql(sql);\n        sql = replaceSql.restore(sql);\n        return sql;\n    }\n\n    @Override\n    public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) {\n        //处理pageKey\n        pageKey.update(rowBounds.getOffset());\n        pageKey.update(rowBounds.getLimit());\n        sql = replaceSql.replace(sql);\n        sql = sqlServerSqlParser.convertToPageSql(sql, null, null);\n        sql = replaceSql.restore(sql);\n        sql = sql.replace(String.valueOf(Long.MIN_VALUE), String.valueOf(rowBounds.getOffset()));\n        sql = sql.replace(String.valueOf(Long.MAX_VALUE), String.valueOf(rowBounds.getLimit()));\n        return sql;\n    }\n\n    @Override\n    public void setProperties(Properties properties) {\n        super.setProperties(properties);\n        this.sqlServerSqlParser = ClassUtil.newInstance(properties.getProperty(\"sqlServerSqlParser\"), SqlServerSqlParser.class, properties, DefaultSqlServerSqlParser::new);\n        String replaceSql = properties.getProperty(\"replaceSql\");\n        if (StringUtil.isEmpty(replaceSql) || \"simple\".equalsIgnoreCase(replaceSql)) {\n            this.replaceSql = new SimpleWithNolockReplaceSql();\n        } else if (\"regex\".equalsIgnoreCase(replaceSql)) {\n            this.replaceSql = new RegexWithNolockReplaceSql();\n        } else {\n            this.replaceSql = ClassUtil.newInstance(replaceSql, properties);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/rowbounds/XuguRowBoundsDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2017 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.dialect.rowbounds;\n\nimport com.github.pagehelper.dialect.AbstractRowBoundsDialect;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.session.RowBounds;\n\n/**\n * mysql 基于 RowBounds 的分页\n *\n * @author liuzh\n */\npublic class XuguRowBoundsDialect extends AbstractRowBoundsDialect {\n\n    @Override\n    public String getPageSql(String sql, RowBounds rowBounds, CacheKey pageKey) {\n        StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);\n        sqlBuilder.append(sql);\n        if (rowBounds.getOffset() == 0) {\n            sqlBuilder.append(\"\\n LIMIT \");\n            sqlBuilder.append(rowBounds.getLimit());\n        } else {\n            sqlBuilder.append(\"\\n LIMIT \");\n            sqlBuilder.append(rowBounds.getOffset());\n            sqlBuilder.append(\",\");\n            sqlBuilder.append(rowBounds.getLimit());\n            pageKey.update(rowBounds.getOffset());\n        }\n        pageKey.update(rowBounds.getLimit());\n        return sqlBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/dialect/rowbounds/package-info.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n/**\n * 当前包中的实现属于示例，也可以使用，但是以后不会再支持更多数据库\n */\npackage com.github.pagehelper.dialect.rowbounds;\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/page/PageAutoDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.page;\n\nimport com.github.pagehelper.AutoDialect;\nimport com.github.pagehelper.Dialect;\nimport com.github.pagehelper.PageException;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport com.github.pagehelper.dialect.auto.*;\nimport com.github.pagehelper.dialect.helper.*;\nimport com.github.pagehelper.util.ClassUtil;\nimport com.github.pagehelper.util.StringUtil;\nimport org.apache.ibatis.mapping.MappedStatement;\n\nimport javax.sql.DataSource;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * 基础方言信息\n *\n * @author liuzh\n */\npublic class PageAutoDialect {\n\n    private static Map<String, Class<? extends Dialect>>     dialectAliasMap = new LinkedHashMap<>();\n    private static Map<String, Class<? extends AutoDialect>> autoDialectMap  = new LinkedHashMap<>();\n\n    public static void registerDialectAlias(String alias, Class<? extends Dialect> dialectClass) {\n        dialectAliasMap.put(alias, dialectClass);\n    }\n\n    static {\n        //注册别名\n        registerDialectAlias(\"hsqldb\", HsqldbDialect.class);\n        registerDialectAlias(\"h2\", HsqldbDialect.class);\n        registerDialectAlias(\"phoenix\", HsqldbDialect.class);\n\n        registerDialectAlias(\"postgresql\", PostgreSqlDialect.class);\n\n        registerDialectAlias(\"mysql\", MySqlDialect.class);\n        registerDialectAlias(\"mariadb\", MySqlDialect.class);\n        registerDialectAlias(\"sqlite\", MySqlDialect.class);\n\n        registerDialectAlias(\"herddb\", HerdDBDialect.class);\n\n        registerDialectAlias(\"oracle\", OracleDialect.class);\n        registerDialectAlias(\"oracle9i\", Oracle9iDialect.class);\n        registerDialectAlias(\"db2\", Db2Dialect.class);\n        registerDialectAlias(\"as400\", AS400Dialect.class);\n        registerDialectAlias(\"informix\", InformixDialect.class);\n        //解决 informix-sqli #129，仍然保留上面的\n        registerDialectAlias(\"informix-sqli\", InformixDialect.class);\n\n        registerDialectAlias(\"sqlserver\", SqlServerDialect.class);\n        registerDialectAlias(\"sqlserver2012\", SqlServer2012Dialect.class);\n\n        registerDialectAlias(\"derby\", SqlServer2012Dialect.class);\n        //达梦数据库,https://github.com/mybatis-book/book/issues/43\n        registerDialectAlias(\"dm\", OracleDialect.class);\n        //阿里云PPAS数据库,https://github.com/pagehelper/Mybatis-PageHelper/issues/281\n        registerDialectAlias(\"edb\", OracleDialect.class);\n        //神通数据库\n        registerDialectAlias(\"oscar\", OscarDialect.class);\n        registerDialectAlias(\"clickhouse\", MySqlDialect.class);\n        //瀚高数据库\n        registerDialectAlias(\"highgo\", HsqldbDialect.class);\n        //虚谷数据库\n        registerDialectAlias(\"xugu\", HsqldbDialect.class);\n        registerDialectAlias(\"impala\", HsqldbDialect.class);\n        registerDialectAlias(\"firebirdsql\", FirebirdDialect.class);\n        //人大金仓数据库\n        registerDialectAlias(\"kingbase\", PostgreSqlDialect.class);\n        // 人大金仓新版本kingbase8\n        registerDialectAlias(\"kingbase8\", PostgreSqlDialect.class);\n        //行云数据库\n        registerDialectAlias(\"xcloud\", CirroDataDialect.class);\n\n        //openGauss数据库\n        registerDialectAlias(\"opengauss\", PostgreSqlDialect.class);\n        registerDialectAlias(\"gaussdb\", GaussDBDialect.class);\n        registerDialectAlias(\"sundb\", OracleDialect.class);\n\n        //注册 AutoDialect\n        //想要实现和以前版本相同的效果时，可以配置 autoDialectClass=old\n        registerAutoDialectAlias(\"old\", DefaultAutoDialect.class);\n        registerAutoDialectAlias(\"hikari\", HikariAutoDialect.class);\n        registerAutoDialectAlias(\"druid\", DruidAutoDialect.class);\n        registerAutoDialectAlias(\"tomcat-jdbc\", TomcatAutoDialect.class);\n        registerAutoDialectAlias(\"dbcp\", DbcpAutoDialect.class);\n        registerAutoDialectAlias(\"c3p0\", C3P0AutoDialect.class);\n\n        //不配置时，默认使用 DataSourceNegotiationAutoDialect\n        registerAutoDialectAlias(\"default\", DataSourceNegotiationAutoDialect.class);\n    }\n\n    public static void registerAutoDialectAlias(String alias, Class<? extends AutoDialect> autoDialectClass) {\n        autoDialectMap.put(alias, autoDialectClass);\n    }\n\n    /**\n     * 自动获取dialect,如果没有setProperties或setSqlUtilConfig，也可以正常进行\n     */\n    private boolean                            autoDialect        = true;\n    /**\n     * 属性配置\n     */\n    private Properties                         properties;\n    /**\n     * 缓存 dialect 实现，key 有两种，分别为 jdbcurl 和 dialectClassName\n     */\n    private Map<Object, AbstractHelperDialect> urlDialectMap      = new ConcurrentHashMap<Object, AbstractHelperDialect>();\n    private ReentrantLock                      lock               = new ReentrantLock();\n    private AbstractHelperDialect              delegate;\n    private ThreadLocal<AbstractHelperDialect> dialectThreadLocal = new ThreadLocal<AbstractHelperDialect>();\n    private AutoDialect                        autoDialectDelegate;\n\n    public static String fromJdbcUrl(String jdbcUrl) {\n        final String url = jdbcUrl.toLowerCase();\n        for (String dialect : dialectAliasMap.keySet()) {\n            if (url.contains(\":\" + dialect.toLowerCase() + \":\")) {\n                return dialect;\n            }\n        }\n        return null;\n    }\n\n    //获取当前的代理对象\n    public AbstractHelperDialect getDelegate() {\n        if (delegate != null) {\n            return delegate;\n        }\n        return dialectThreadLocal.get();\n    }\n\n    //移除代理对象\n    public void clearDelegate() {\n        dialectThreadLocal.remove();\n    }\n\n    public AbstractHelperDialect getDialectThreadLocal() {\n        return dialectThreadLocal.get();\n    }\n\n    public void setDialectThreadLocal(AbstractHelperDialect delegate) {\n        this.dialectThreadLocal.set(delegate);\n    }\n\n    /**\n     * 反射类\n     *\n     * @param className\n     * @return\n     * @throws Exception\n     */\n    public static Class resloveDialectClass(String className) throws Exception {\n        if (dialectAliasMap.containsKey(className.toLowerCase())) {\n            return dialectAliasMap.get(className.toLowerCase());\n        } else {\n            return Class.forName(className);\n        }\n    }\n\n    /**\n     * 初始化 helper\n     *\n     * @param dialectClass\n     * @param properties\n     */\n    public static AbstractHelperDialect instanceDialect(String dialectClass, Properties properties) {\n        AbstractHelperDialect dialect;\n        if (StringUtil.isEmpty(dialectClass)) {\n            throw new PageException(\"When you use the PageHelper pagination plugin, you must set the helper property\");\n        }\n        try {\n            Class sqlDialectClass = resloveDialectClass(dialectClass);\n            if (AbstractHelperDialect.class.isAssignableFrom(sqlDialectClass)) {\n                dialect = (AbstractHelperDialect) sqlDialectClass.newInstance();\n            } else {\n                throw new PageException(\"When using PageHelper, the dialect must be an implementation class that implements the \" + AbstractHelperDialect.class.getCanonicalName() + \" interface!\");\n            }\n        } catch (Exception e) {\n            throw new PageException(\"error initializing helper dialectclass[\" + dialectClass + \"]\" + e.getMessage(), e);\n        }\n        dialect.setProperties(properties);\n        return dialect;\n    }\n\n    /**\n     * 多数据动态获取时，每次需要初始化，还可以运行时指定具体的实现\n     *\n     * @param ms\n     * @param dialectClass 分页实现，必须是 {@link AbstractHelperDialect} 实现类，可以使用当前类中注册的别名，例如 \"mysql\", \"oracle\"\n     */\n    public void initDelegateDialect(MappedStatement ms, String dialectClass) {\n        if (StringUtil.isNotEmpty(dialectClass)) {\n            AbstractHelperDialect dialect = urlDialectMap.get(dialectClass);\n            if (dialect == null) {\n                lock.lock();\n                try {\n                    if ((dialect = urlDialectMap.get(dialectClass)) == null) {\n                        dialect = instanceDialect(dialectClass, properties);\n                        urlDialectMap.put(dialectClass, dialect);\n                    }\n                } finally {\n                    lock.unlock();\n                }\n            }\n            dialectThreadLocal.set(dialect);\n        } else if (delegate == null) {\n            if (autoDialect) {\n                this.delegate = autoGetDialect(ms);\n            } else {\n                dialectThreadLocal.set(autoGetDialect(ms));\n            }\n        }\n    }\n\n    /**\n     * 自动获取分页方言实现\n     *\n     * @param ms\n     * @return\n     */\n    public AbstractHelperDialect autoGetDialect(MappedStatement ms) {\n        DataSource dataSource = ms.getConfiguration().getEnvironment().getDataSource();\n        Object dialectKey = autoDialectDelegate.extractDialectKey(ms, dataSource, properties);\n        if (dialectKey == null) {\n            return autoDialectDelegate.extractDialect(dialectKey, ms, dataSource, properties);\n        } else if (!urlDialectMap.containsKey(dialectKey)) {\n            lock.lock();\n            try {\n                if (!urlDialectMap.containsKey(dialectKey)) {\n                    urlDialectMap.put(dialectKey, autoDialectDelegate.extractDialect(dialectKey, ms, dataSource, properties));\n                }\n            } finally {\n                lock.unlock();\n            }\n        }\n        return urlDialectMap.get(dialectKey);\n    }\n\n    /**\n     * 初始化自定义 AutoDialect\n     *\n     * @param properties\n     */\n    private void initAutoDialectClass(Properties properties) {\n        String autoDialectClassStr = properties.getProperty(\"autoDialectClass\");\n        if (StringUtil.isNotEmpty(autoDialectClassStr)) {\n            try {\n                Class<? extends AutoDialect> autoDialectClass;\n                if (autoDialectMap.containsKey(autoDialectClassStr)) {\n                    autoDialectClass = autoDialectMap.get(autoDialectClassStr);\n                } else {\n                    autoDialectClass = (Class<AutoDialect>) Class.forName(autoDialectClassStr);\n                }\n                this.autoDialectDelegate = ClassUtil.newInstance(autoDialectClass, properties);\n            } catch (ClassNotFoundException e) {\n                throw new IllegalArgumentException(\"Make sure that the AutoDialect implementation class (\"\n                        + autoDialectClassStr + \") for the autoDialectClass configuration exists!\", e);\n            } catch (Exception e) {\n                throw new RuntimeException(autoDialectClassStr + \"Class must provide a constructor without parameters\", e);\n            }\n        } else {\n            this.autoDialectDelegate = new DataSourceNegotiationAutoDialect();\n        }\n    }\n\n    /**\n     * 初始化方言别名\n     *\n     * @param properties\n     */\n    private void initDialectAlias(Properties properties) {\n        String dialectAlias = properties.getProperty(\"dialectAlias\");\n        if (StringUtil.isNotEmpty(dialectAlias)) {\n            String[] alias = dialectAlias.split(\";\");\n            for (int i = 0; i < alias.length; i++) {\n                String[] kv = alias[i].split(\"=\");\n                if (kv.length != 2) {\n                    throw new IllegalArgumentException(\"dialectAlias parameter misconfigured,\" +\n                            \"Please follow alias1=xx.dialectClass; alias2=dialectClass2!\");\n                }\n                for (int j = 0; j < kv.length; j++) {\n                    try {\n                        //允许配置如 dm=oracle, 直接引用oracle实现\n                        if (dialectAliasMap.containsKey(kv[1])) {\n                            registerDialectAlias(kv[0], dialectAliasMap.get(kv[1]));\n                        } else {\n                            Class<? extends Dialect> diallectClass = (Class<? extends Dialect>) Class.forName(kv[1]);\n                            //允许覆盖已有的实现\n                            registerDialectAlias(kv[0], diallectClass);\n                        }\n                    } catch (ClassNotFoundException e) {\n                        throw new IllegalArgumentException(\"Make sure the Dialect implementation class configured by dialectAlias exists!\", e);\n                    }\n                }\n            }\n        }\n    }\n\n    public void setProperties(Properties properties) {\n\n        this.properties = properties;\n        //初始化自定义AutoDialect\n        initAutoDialectClass(properties);\n        //使用 sqlserver2012 作为默认分页方式，这种情况在动态数据源时方便使用\n        String useSqlserver2012 = properties.getProperty(\"useSqlserver2012\");\n        if (StringUtil.isNotEmpty(useSqlserver2012) && Boolean.parseBoolean(useSqlserver2012)) {\n            registerDialectAlias(\"sqlserver\", SqlServer2012Dialect.class);\n            registerDialectAlias(\"sqlserver2008\", SqlServerDialect.class);\n        }\n        initDialectAlias(properties);\n        //指定的 Helper 数据库方言，和  不同\n        String dialect = properties.getProperty(\"helperDialect\");\n        //运行时获取数据源\n        String runtimeDialect = properties.getProperty(\"autoRuntimeDialect\");\n        //1.动态多数据源\n        if (StringUtil.isNotEmpty(runtimeDialect) && \"TRUE\".equalsIgnoreCase(runtimeDialect)) {\n            this.autoDialect = false;\n        }\n        //2.动态获取方言\n        else if (StringUtil.isEmpty(dialect)) {\n            autoDialect = true;\n        }\n        //3.指定方言\n        else {\n            autoDialect = false;\n            this.delegate = instanceDialect(dialect, properties);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/page/PageBoundSqlInterceptors.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.page;\n\nimport com.github.pagehelper.BoundSqlInterceptor;\nimport com.github.pagehelper.BoundSqlInterceptorChain;\nimport com.github.pagehelper.util.ClassUtil;\nimport com.github.pagehelper.util.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Properties;\n\npublic class PageBoundSqlInterceptors {\n\n    private BoundSqlInterceptor.Chain chain;\n\n    public void setProperties(Properties properties) {\n        //初始化 boundSqlInterceptorChain\n        String boundSqlInterceptorStr = properties.getProperty(\"boundSqlInterceptors\");\n        if (StringUtil.isNotEmpty(boundSqlInterceptorStr)) {\n            String[] boundSqlInterceptors = boundSqlInterceptorStr.split(\"[;|,]\");\n            List<BoundSqlInterceptor> list = new ArrayList<BoundSqlInterceptor>();\n            for (int i = 0; i < boundSqlInterceptors.length; i++) {\n                list.add(ClassUtil.newInstance(boundSqlInterceptors[i], properties));\n            }\n            if (list.size() > 0) {\n                chain = new BoundSqlInterceptorChain(null, list);\n            }\n        }\n    }\n\n    public BoundSqlInterceptor.Chain getChain() {\n        return chain;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/page/PageMethod.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.page;\n\nimport com.github.pagehelper.ISelect;\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.util.PageObjectUtil;\n\nimport java.util.Properties;\n\n/**\n * 基础分页方法\n *\n * @author liuzh\n */\npublic abstract class PageMethod {\n    protected static final ThreadLocal<Page> LOCAL_PAGE    = new ThreadLocal<Page>();\n    protected static       boolean           DEFAULT_COUNT = true;\n\n    /**\n     * 设置 Page 参数\n     *\n     * @param page\n     */\n    public static void setLocalPage(Page page) {\n        LOCAL_PAGE.set(page);\n    }\n\n    /**\n     * 获取 Page 参数\n     *\n     * @return\n     */\n    public static <T> Page<T> getLocalPage() {\n        return LOCAL_PAGE.get();\n    }\n\n    /**\n     * 移除本地变量\n     */\n    public static void clearPage() {\n        LOCAL_PAGE.remove();\n    }\n\n    /**\n     * 获取任意查询方法的count总数\n     *\n     * @param select\n     * @return\n     */\n    public static long count(ISelect select) {\n        //单纯count查询时禁用异步count\n        Page<?> page = startPage(1, -1, true).disableAsyncCount();\n        select.doSelect();\n        return page.getTotal();\n    }\n\n    /**\n     * 开始分页\n     *\n     * @param params\n     */\n    public static <E> Page<E> startPage(Object params) {\n        Page<E> page = PageObjectUtil.getPageFromObject(params, true);\n        //当已经执行过orderBy的时候\n        Page<E> oldPage = getLocalPage();\n        if (oldPage != null && oldPage.isOrderByOnly()) {\n            page.setOrderBy(oldPage.getOrderBy());\n        }\n        setLocalPage(page);\n        return page;\n    }\n\n    /**\n     * 开始分页\n     *\n     * @param pageNum  页码\n     * @param pageSize 每页显示数量\n     */\n    public static <E> Page<E> startPage(int pageNum, int pageSize) {\n        return startPage(pageNum, pageSize, DEFAULT_COUNT);\n    }\n\n    /**\n     * 开始分页\n     *\n     * @param pageNum  页码\n     * @param pageSize 每页显示数量\n     * @param count    是否进行count查询\n     */\n    public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count) {\n        return startPage(pageNum, pageSize, count, null, null);\n    }\n\n    /**\n     * 开始分页\n     *\n     * @param pageNum  页码\n     * @param pageSize 每页显示数量\n     * @param orderBy  排序\n     */\n    public static <E> Page<E> startPage(int pageNum, int pageSize, String orderBy) {\n        Page<E> page = startPage(pageNum, pageSize);\n        page.setOrderBy(orderBy);\n        return page;\n    }\n\n    /**\n     * 开始分页\n     *\n     * @param pageNum      页码\n     * @param pageSize     每页显示数量\n     * @param count        是否进行count查询\n     * @param reasonable   分页合理化,null时用默认配置\n     * @param pageSizeZero true且pageSize=0时返回全部结果，false时分页,null时用默认配置\n     */\n    public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {\n        Page<E> page = new Page<E>(pageNum, pageSize, count);\n        page.setReasonable(reasonable);\n        page.setPageSizeZero(pageSizeZero);\n        //当已经执行过orderBy的时候\n        Page<E> oldPage = getLocalPage();\n        if (oldPage != null && oldPage.isOrderByOnly()) {\n            page.setOrderBy(oldPage.getOrderBy());\n        }\n        setLocalPage(page);\n        return page;\n    }\n\n    /**\n     * 开始分页\n     *\n     * @param offset 起始位置，偏移位置\n     * @param limit  每页显示数量\n     */\n    public static <E> Page<E> offsetPage(int offset, int limit) {\n        return offsetPage(offset, limit, DEFAULT_COUNT);\n    }\n\n    /**\n     * 开始分页\n     *\n     * @param offset 起始位置，偏移位置\n     * @param limit  每页显示数量\n     * @param count  是否进行count查询\n     */\n    public static <E> Page<E> offsetPage(int offset, int limit, boolean count) {\n        Page<E> page = new Page<E>(new int[]{offset, limit}, count);\n        //当已经执行过orderBy的时候\n        Page<E> oldPage = getLocalPage();\n        if (oldPage != null && oldPage.isOrderByOnly()) {\n            page.setOrderBy(oldPage.getOrderBy());\n        }\n        setLocalPage(page);\n        return page;\n    }\n\n    /**\n     * 排序\n     *\n     * @param orderBy\n     */\n    public static void orderBy(String orderBy) {\n        Page<?> page = getLocalPage();\n        if (page != null) {\n            page.setOrderBy(orderBy);\n            if (page.getPageSizeZero() != null && page.getPageSizeZero() && page.getPageSize() == 0) {\n                page.setOrderByOnly(true);\n            }\n        } else {\n            page = new Page();\n            page.setOrderBy(orderBy);\n            page.setOrderByOnly(true);\n            setLocalPage(page);\n        }\n    }\n\n    /**\n     * 设置参数\n     *\n     * @param properties 插件属性\n     */\n    protected static void setStaticProperties(Properties properties) {\n        //defaultCount，这是一个全局生效的参数，多数据源时也是统一的行为\n        if (properties != null) {\n            DEFAULT_COUNT = Boolean.valueOf(properties.getProperty(\"defaultCount\", \"true\"));\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/page/PageParams.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.page;\n\nimport com.github.pagehelper.IPage;\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageRowBounds;\nimport com.github.pagehelper.util.PageObjectUtil;\nimport com.github.pagehelper.util.StringUtil;\nimport org.apache.ibatis.session.RowBounds;\n\nimport java.util.Properties;\n\n/**\n * Page 参数信息\n *\n * @author liuzh\n */\npublic class PageParams {\n    /**\n     * RowBounds参数offset作为PageNum使用 - 默认不使用\n     */\n    protected boolean offsetAsPageNum         = false;\n    /**\n     * RowBounds是否进行count查询 - 默认不查询\n     */\n    protected boolean rowBoundsWithCount      = false;\n    /**\n     * 当设置为true的时候，如果pagesize设置为0（或RowBounds的limit=0），就不执行分页，返回全部结果\n     */\n    protected boolean pageSizeZero            = false;\n    /**\n     * 分页合理化\n     */\n    protected boolean reasonable              = false;\n    /**\n     * 是否支持接口参数来传递分页参数，默认false\n     */\n    protected boolean supportMethodsArguments = false;\n    /**\n     * 默认count(0)\n     */\n    protected String  countColumn             = \"0\";\n    /**\n     * 转换count查询时保留 order by 排序\n     */\n    private   boolean keepOrderBy             = false;\n    /**\n     * 转换count查询时保留子查询的 order by 排序\n     */\n    private   boolean keepSubSelectOrderBy    = false;\n    /**\n     * 异步count查询\n     */\n    private   boolean asyncCount              = false;\n\n    /**\n     * 获取分页参数\n     *\n     * @param parameterObject\n     * @param rowBounds\n     * @return\n     */\n    public Page getPage(Object parameterObject, RowBounds rowBounds) {\n        Page page = PageHelper.getLocalPage();\n        if (page == null) {\n            if (rowBounds != RowBounds.DEFAULT) {\n                if (offsetAsPageNum) {\n                    page = new Page(rowBounds.getOffset(), rowBounds.getLimit(), rowBoundsWithCount);\n                } else {\n                    page = new Page(new int[]{rowBounds.getOffset(), rowBounds.getLimit()}, rowBoundsWithCount);\n                    //offsetAsPageNum=false的时候，由于PageNum问题，不能使用reasonable，这里会强制为false\n                    page.setReasonable(false);\n                }\n                if (rowBounds instanceof PageRowBounds) {\n                    PageRowBounds pageRowBounds = (PageRowBounds) rowBounds;\n                    page.setCount(pageRowBounds.getCount() == null || pageRowBounds.getCount());\n                }\n            } else if (parameterObject instanceof IPage || supportMethodsArguments) {\n                try {\n                    page = PageObjectUtil.getPageFromObject(parameterObject, false);\n                } catch (Exception e) {\n                    return null;\n                }\n            }\n            if (page == null) {\n                return null;\n            }\n            PageHelper.setLocalPage(page);\n        }\n        //分页合理化\n        if (page.getReasonable() == null) {\n            page.setReasonable(reasonable);\n        }\n        //当设置为true的时候，如果pagesize设置为0（或RowBounds的limit=0），就不执行分页，返回全部结果\n        if (page.getPageSizeZero() == null) {\n            page.setPageSizeZero(pageSizeZero);\n        }\n        if (page.getKeepOrderBy() == null) {\n            page.setKeepOrderBy(keepOrderBy);\n        }\n        if (page.getKeepSubSelectOrderBy() == null) {\n            page.setKeepSubSelectOrderBy(keepSubSelectOrderBy);\n        }\n        return page;\n    }\n\n    public void setProperties(Properties properties) {\n        //offset作为PageNum使用\n        String offsetAsPageNum = properties.getProperty(\"offsetAsPageNum\");\n        this.offsetAsPageNum = Boolean.parseBoolean(offsetAsPageNum);\n        //RowBounds方式是否做count查询\n        String rowBoundsWithCount = properties.getProperty(\"rowBoundsWithCount\");\n        this.rowBoundsWithCount = Boolean.parseBoolean(rowBoundsWithCount);\n        //当设置为true的时候，如果pagesize设置为0（或RowBounds的limit=0），就不执行分页\n        String pageSizeZero = properties.getProperty(\"pageSizeZero\");\n        this.pageSizeZero = Boolean.parseBoolean(pageSizeZero);\n        //分页合理化，true开启，如果分页参数不合理会自动修正。默认false不启用\n        String reasonable = properties.getProperty(\"reasonable\");\n        this.reasonable = Boolean.parseBoolean(reasonable);\n        //是否支持接口参数来传递分页参数，默认false\n        String supportMethodsArguments = properties.getProperty(\"supportMethodsArguments\");\n        this.supportMethodsArguments = Boolean.parseBoolean(supportMethodsArguments);\n        //默认count列\n        String countColumn = properties.getProperty(\"countColumn\");\n        if (StringUtil.isNotEmpty(countColumn)) {\n            this.countColumn = countColumn;\n        }\n        //当offsetAsPageNum=false的时候，不能\n        //参数映射\n        PageObjectUtil.setParams(properties.getProperty(\"params\"));\n        // count查询时，是否保留查询中的 order by\n        keepOrderBy = Boolean.parseBoolean(properties.getProperty(\"keepOrderBy\"));\n        // count查询时，是否保留子查询中的 order by\n        keepSubSelectOrderBy = Boolean.parseBoolean(properties.getProperty(\"keepSubSelectOrderBy\"));\n        // 异步count查询\n        asyncCount = Boolean.parseBoolean(properties.getProperty(\"asyncCount\"));\n    }\n\n    public boolean isOffsetAsPageNum() {\n        return offsetAsPageNum;\n    }\n\n    public boolean isRowBoundsWithCount() {\n        return rowBoundsWithCount;\n    }\n\n    public boolean isPageSizeZero() {\n        return pageSizeZero;\n    }\n\n    public boolean isReasonable() {\n        return reasonable;\n    }\n\n    public boolean isSupportMethodsArguments() {\n        return supportMethodsArguments;\n    }\n\n    public String getCountColumn() {\n        return countColumn;\n    }\n\n    public boolean isAsyncCount() {\n        return asyncCount;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/parser/CountSqlParser.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.parser;\n\nimport com.github.pagehelper.util.StringUtil;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\n\npublic interface CountSqlParser {\n    /**\n     * 聚合函数，以下列函数开头的都认为是聚合函数\n     */\n    Set<String> AGGREGATE_FUNCTIONS = new HashSet<String>(Arrays.asList(\n            (\"APPROX_COUNT_DISTINCT,\" +\n                    \"ARRAY_AGG,\" +\n                    \"AVG,\" +\n                    \"BIT_,\" +\n                    //\"BIT_AND,\" +\n                    //\"BIT_OR,\" +\n                    //\"BIT_XOR,\" +\n                    \"BOOL_,\" +\n                    //\"BOOL_AND,\" +\n                    //\"BOOL_OR,\" +\n                    \"CHECKSUM_AGG,\" +\n                    \"COLLECT,\" +\n                    \"CORR,\" +\n                    //\"CORR_,\" +\n                    //\"CORRELATION,\" +\n                    \"COUNT,\" +\n                    //\"COUNT_BIG,\" +\n                    \"COVAR,\" +\n                    //\"COVAR_POP,\" +\n                    //\"COVAR_SAMP,\" +\n                    //\"COVARIANCE,\" +\n                    //\"COVARIANCE_SAMP,\" +\n                    \"CUME_DIST,\" +\n                    \"DENSE_RANK,\" +\n                    \"EVERY,\" +\n                    \"FIRST,\" +\n                    \"GROUP,\" +\n                    //\"GROUP_CONCAT,\" +\n                    //\"GROUP_ID,\" +\n                    //\"GROUPING,\" +\n                    //\"GROUPING,\" +\n                    //\"GROUPING_ID,\" +\n                    \"JSON_,\" +\n                    //\"JSON_AGG,\" +\n                    //\"JSON_ARRAYAGG,\" +\n                    //\"JSON_OBJECT_AGG,\" +\n                    //\"JSON_OBJECTAGG,\" +\n                    //\"JSONB_AGG,\" +\n                    //\"JSONB_OBJECT_AGG,\" +\n                    \"LAST,\" +\n                    \"LISTAGG,\" +\n                    \"MAX,\" +\n                    \"MEDIAN,\" +\n                    \"MIN,\" +\n                    \"PERCENT_,\" +\n                    //\"PERCENT_RANK,\" +\n                    //\"PERCENTILE_CONT,\" +\n                    //\"PERCENTILE_DISC,\" +\n                    \"RANK,\" +\n                    \"REGR_,\" +\n                    \"SELECTIVITY,\" +\n                    \"STATS_,\" +\n                    //\"STATS_BINOMIAL_TEST,\" +\n                    //\"STATS_CROSSTAB,\" +\n                    //\"STATS_F_TEST,\" +\n                    //\"STATS_KS_TEST,\" +\n                    //\"STATS_MODE,\" +\n                    //\"STATS_MW_TEST,\" +\n                    //\"STATS_ONE_WAY_ANOVA,\" +\n                    //\"STATS_T_TEST_*,\" +\n                    //\"STATS_WSR_TEST,\" +\n                    \"STD,\" +\n                    //\"STDDEV,\" +\n                    //\"STDDEV_POP,\" +\n                    //\"STDDEV_SAMP,\" +\n                    //\"STDDEV_SAMP,\" +\n                    //\"STDEV,\" +\n                    //\"STDEVP,\" +\n                    \"STRING_AGG,\" +\n                    \"SUM,\" +\n                    \"SYS_OP_ZONE_ID,\" +\n                    \"SYS_XMLAGG,\" +\n                    \"VAR,\" +\n                    //\"VAR_POP,\" +\n                    //\"VAR_SAMP,\" +\n                    //\"VARIANCE,\" +\n                    //\"VARIANCE_SAMP,\" +\n                    //\"VARP,\" +\n                    \"XMLAGG\").split(\",\")));\n\n    /**\n     * 添加到聚合函数，可以是逗号隔开的多个函数前缀\n     *\n     * @param functions\n     */\n    static void addAggregateFunctions(String functions) {\n        if (StringUtil.isNotEmpty(functions)) {\n            String[] funs = functions.split(\",\");\n            for (int i = 0; i < funs.length; i++) {\n                AGGREGATE_FUNCTIONS.add(funs[i].toUpperCase());\n            }\n        }\n    }\n\n    /**\n     * 获取智能的countSql\n     *\n     * @param sql\n     */\n    default String getSmartCountSql(String sql) {\n        return getSmartCountSql(sql, \"0\");\n    }\n\n\n    /**\n     * 获取智能的countSql\n     *\n     * @param sql\n     * @param countColumn 列名，默认 0\n     */\n    String getSmartCountSql(String sql, String countColumn);\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/parser/OrderBySqlParser.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.parser;\n\npublic interface OrderBySqlParser {\n    String converToOrderBySql(String sql, String orderBy);\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/parser/SqlParser.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.parser;\n\nimport net.sf.jsqlparser.JSQLParserException;\nimport net.sf.jsqlparser.parser.CCJSqlParser;\nimport net.sf.jsqlparser.parser.CCJSqlParserUtil;\nimport net.sf.jsqlparser.parser.ParseException;\nimport net.sf.jsqlparser.statement.Statement;\n\n/**\n * 为了能自己控制是否使用单线程池，是否支持超时控制，所以自己实现了一个\n *\n * @author liuzh\n */\npublic interface SqlParser {\n    /**\n     * 不使用单线程池，不支持超时控制\n     */\n    SqlParser DEFAULT = statementReader -> {\n        CCJSqlParser parser = CCJSqlParserUtil.newParser(statementReader);\n        parser.withSquareBracketQuotation(true);\n        return parser.Statement();\n    };\n\n    /**\n     * 解析 SQL\n     *\n     * @param statementReader SQL\n     * @return\n     * @throws JSQLParserException\n     */\n    Statement parse(String statementReader) throws JSQLParserException, ParseException;\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/parser/SqlParserUtil.java",
    "content": "package com.github.pagehelper.parser;\n\nimport net.sf.jsqlparser.JSQLParserException;\nimport net.sf.jsqlparser.parser.ParseException;\nimport net.sf.jsqlparser.statement.Statement;\n\nimport java.util.ServiceLoader;\n\npublic class SqlParserUtil {\n\n    private static final SqlParser SQL_PARSER;\n\n    static {\n        SqlParser temp = null;\n        ServiceLoader<SqlParser> loader = ServiceLoader.load(SqlParser.class);\n        for (SqlParser sqlParser : loader) {\n            temp = sqlParser;\n            break;\n        }\n        if (temp == null) {\n            temp = SqlParser.DEFAULT;\n        }\n        SQL_PARSER = temp;\n    }\n\n    public static Statement parse(String statementReader) {\n        try {\n            return SQL_PARSER.parse(statementReader);\n        } catch (JSQLParserException | ParseException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/parser/SqlServerSqlParser.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.parser;\n\n/**\n * 针对 sqlserver 的分页解析\n */\npublic interface SqlServerSqlParser {\n\n    String convertToPageSql(String sql, Integer offset, Integer limit);\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/parser/defaults/DefaultCountSqlParser.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.parser.defaults;\n\nimport com.github.pagehelper.page.PageMethod;\nimport com.github.pagehelper.parser.CountSqlParser;\nimport com.github.pagehelper.parser.SqlParserUtil;\nimport net.sf.jsqlparser.expression.Alias;\nimport net.sf.jsqlparser.expression.Expression;\nimport net.sf.jsqlparser.expression.Function;\nimport net.sf.jsqlparser.expression.Parenthesis;\nimport net.sf.jsqlparser.parser.Token;\nimport net.sf.jsqlparser.schema.Column;\nimport net.sf.jsqlparser.statement.Statement;\nimport net.sf.jsqlparser.statement.select.*;\n\nimport java.util.*;\n\n/**\n * sql解析类，提供更智能的count查询sql\n *\n * @author liuzh\n */\npublic class DefaultCountSqlParser implements CountSqlParser {\n    public static final String KEEP_ORDERBY = \"/*keep orderby*/\";\n    protected static final Alias TABLE_ALIAS;\n\n    protected final Set<String> skipFunctions = Collections.synchronizedSet(new HashSet<>());\n    protected final Set<String> falseFunctions = Collections.synchronizedSet(new HashSet<>());\n\n    static {\n        TABLE_ALIAS = new Alias(\"table_count\");\n        TABLE_ALIAS.setUseAs(false);\n    }\n\n    /**\n     * 获取智能的countSql\n     *\n     * @param sql\n     * @param countColumn 列名，默认 0\n     * @return\n     */\n    @Override\n    public String getSmartCountSql(String sql, String countColumn) {\n        // 解析SQL\n        Statement stmt = null;\n        // 特殊sql不需要去掉order by时，使用注释前缀\n        if (sql.indexOf(KEEP_ORDERBY) >= 0 || keepOrderBy()) {\n            return getSimpleCountSql(sql, countColumn);\n        }\n        try {\n            stmt = SqlParserUtil.parse(sql);\n        } catch (Throwable e) {\n            // 无法解析的用一般方法返回count语句\n            return getSimpleCountSql(sql, countColumn);\n        }\n        Select select = (Select) stmt;\n        try {\n            // 处理body-去order by\n            processSelect(select);\n        } catch (Exception e) {\n            // 当 sql 包含 group by 时，不去除 order by\n            return getSimpleCountSql(sql, countColumn);\n        }\n        // 处理with-去order by\n        processWithItemsList(select.getWithItemsList());\n        // 处理为count查询\n        Select countSelect = sqlToCount(select, countColumn);\n        String result = countSelect.toString();\n        if (select instanceof PlainSelect) {\n            Token token = select.getASTNode().jjtGetFirstToken().specialToken;\n            if (token != null) {\n                String hints = token.toString().trim();\n                // 这里判断是否存在hint, 且result是不包含hint的\n                if (hints.startsWith(\"/*\") && hints.endsWith(\"*/\") && !result.startsWith(\"/*\")) {\n                    result = hints + result;\n                }\n            }\n        }\n        return result;\n    }\n\n    /**\n     * 获取普通的Count-sql\n     *\n     * @param sql 原查询sql\n     * @return 返回count查询sql\n     */\n    public String getSimpleCountSql(final String sql) {\n        return getSimpleCountSql(sql, \"0\");\n    }\n\n    /**\n     * 获取普通的Count-sql\n     *\n     * @param sql 原查询sql\n     * @return 返回count查询sql\n     */\n    public String getSimpleCountSql(final String sql, String name) {\n        StringBuilder stringBuilder = new StringBuilder(sql.length() + 40);\n        stringBuilder.append(\"select count(\");\n        stringBuilder.append(name);\n        stringBuilder.append(\") from ( \\n\");\n        stringBuilder.append(sql);\n        stringBuilder.append(\"\\n ) tmp_count\");\n        return stringBuilder.toString();\n    }\n\n    /**\n     * 将sql转换为count查询\n     *\n     * @param select\n     */\n    public Select sqlToCount(Select select, String name) {\n        // 是否能简化count查询\n        List<SelectItem<?>> COUNT_ITEM = new ArrayList<>();\n        COUNT_ITEM.add(new SelectItem(new Column(\"count(\" + name + \")\")));\n        if (select instanceof PlainSelect && isSimpleCount((PlainSelect) select)) {\n            ((PlainSelect) select).setSelectItems(COUNT_ITEM);\n            return select;\n        } else {\n            PlainSelect plainSelect = new PlainSelect();\n            ParenthesedSelect subSelect = new ParenthesedSelect();\n            subSelect.setSelect(select);\n            subSelect.setAlias(TABLE_ALIAS);\n            plainSelect.setFromItem(subSelect);\n            plainSelect.setSelectItems(COUNT_ITEM);\n            if (select.getWithItemsList() != null) {\n                plainSelect.setWithItemsList(select.getWithItemsList());\n                select.setWithItemsList(null);\n            }\n            return plainSelect;\n        }\n    }\n\n    /**\n     * 是否可以用简单的count查询方式\n     *\n     * @param select\n     * @return\n     */\n    public boolean isSimpleCount(PlainSelect select) {\n        // #868 Cannot use simple count when ORDER BY contains parameters\n        // If ORDER BY contains parameters, removing it will cause JDBC parameter\n        // mismatch\n        // Fixed by @pwdLight -\n        // https://github.com/pagehelper/Mybatis-PageHelper/pull/869\n        if (orderByHashParameters(select.getOrderByElements())) {\n            return false;\n        }\n        // 包含group by的时候不可以\n        if (select.getGroupBy() != null) {\n            return false;\n        }\n        // 包含distinct的时候不可以\n        if (select.getDistinct() != null) {\n            return false;\n        }\n        // #606,包含having时不可以\n        if (select.getHaving() != null) {\n            return false;\n        }\n        for (SelectItem<?> item : select.getSelectItems()) {\n            // select列中包含参数的时候不可以，否则会引起参数个数错误\n            if (item.toString().contains(\"?\")) {\n                return false;\n            }\n            // 如果查询列中包含函数，也不可以，函数可能会聚合列\n            Expression expression = item.getExpression();\n            if (expression instanceof Function) {\n                String name = ((Function) expression).getName();\n                if (name != null) {\n                    String NAME = name.toUpperCase();\n                    if (skipFunctions.contains(NAME)) {\n                        // go on\n                    } else if (falseFunctions.contains(NAME)) {\n                        return false;\n                    } else {\n                        for (String aggregateFunction : AGGREGATE_FUNCTIONS) {\n                            if (NAME.startsWith(aggregateFunction)) {\n                                falseFunctions.add(NAME);\n                                return false;\n                            }\n                        }\n                        skipFunctions.add(NAME);\n                    }\n                }\n            } else if (expression instanceof Parenthesis && item.getAlias() != null) {\n                // #555，当存在 (a+b) as c 时，c 如果出现了 order by 或者 having 中时，会找不到对应的列，\n                // 这里想要更智能，需要在整个SQL中查找别名出现的位置，暂时不考虑，直接排除\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * 处理selectBody去除Order by\n     *\n     * @param select\n     */\n    public void processSelect(Select select) {\n        if (select != null) {\n            if (select instanceof PlainSelect) {\n                processPlainSelect((PlainSelect) select);\n            } else if (select instanceof ParenthesedSelect) {\n                processSelect(((ParenthesedSelect) select).getSelect());\n            } else if (select instanceof SetOperationList) {\n                List<Select> selects = ((SetOperationList) select).getSelects();\n                for (Select sel : selects) {\n                    processSelect(sel);\n                }\n                if (!orderByHashParameters(select.getOrderByElements())) {\n                    select.setOrderByElements(null);\n                }\n            }\n            /*\n             * if (select instanceof WithItem) {\n             * WithItem withItem = (WithItem) selectBody;\n             * if (withItem.getSubSelect() != null && !keepSubSelectOrderBy()) {\n             * processSelectBody(withItem.getSubSelect().getSelectBody());\n             * }\n             * }\n             */\n        }\n    }\n\n    /**\n     * 处理PlainSelect类型的selectBody\n     *\n     * @param plainSelect\n     */\n    public void processPlainSelect(PlainSelect plainSelect) {\n        if (!orderByHashParameters(plainSelect.getOrderByElements())) {\n            plainSelect.setOrderByElements(null);\n        }\n        if (plainSelect.getFromItem() != null) {\n            processFromItem(plainSelect.getFromItem());\n        }\n        if (plainSelect.getJoins() != null && plainSelect.getJoins().size() > 0) {\n            List<Join> joins = plainSelect.getJoins();\n            for (Join join : joins) {\n                if (join.getRightItem() != null) {\n                    processFromItem(join.getRightItem());\n                }\n            }\n        }\n    }\n\n    /**\n     * 处理WithItem\n     *\n     * @param withItemsList\n     */\n    public void processWithItemsList(List<WithItem> withItemsList) {\n        if (withItemsList != null && !withItemsList.isEmpty()) {\n            for (WithItem item : withItemsList) {\n                if (item.getSelect() != null && !keepSubSelectOrderBy()) {\n                    processSelect(item.getSelect());\n                }\n            }\n        }\n    }\n\n    /**\n     * 处理子查询\n     *\n     * @param fromItem\n     */\n    public void processFromItem(FromItem fromItem) {\n        if (fromItem instanceof ParenthesedSelect) {\n            ParenthesedSelect parenthesedSelect = (ParenthesedSelect) fromItem;\n            if (parenthesedSelect.getSelect() != null && !keepSubSelectOrderBy()) {\n                processSelect(parenthesedSelect.getSelect());\n            }\n        } else if (fromItem instanceof Select) {\n            processSelect((Select) fromItem);\n        } else if (fromItem instanceof ParenthesedFromItem) {\n            ParenthesedFromItem parenthesedFromItem = (ParenthesedFromItem) fromItem;\n            processFromItem(parenthesedFromItem.getFromItem());\n        }\n        // Table时不用处理\n    }\n\n    /**\n     * 保留 order by\n     */\n    protected boolean keepOrderBy() {\n        return PageMethod.getLocalPage() != null && PageMethod.getLocalPage().keepOrderBy();\n    }\n\n    /**\n     * 保留子查询 order by\n     */\n    protected boolean keepSubSelectOrderBy() {\n        return PageMethod.getLocalPage() != null && PageMethod.getLocalPage().keepSubSelectOrderBy();\n    }\n\n    /**\n     * 判断Orderby是否包含参数，有参数的不能去\n     *\n     * @param orderByElements\n     * @return\n     */\n    public boolean orderByHashParameters(List<OrderByElement> orderByElements) {\n        if (orderByElements == null) {\n            return false;\n        }\n        for (OrderByElement orderByElement : orderByElements) {\n            if (orderByElement.toString().contains(\"?\")) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/parser/defaults/DefaultOrderBySqlParser.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.parser.defaults;\n\nimport com.github.pagehelper.PageException;\nimport com.github.pagehelper.parser.OrderBySqlParser;\nimport com.github.pagehelper.parser.SqlParserUtil;\nimport net.sf.jsqlparser.statement.Statement;\nimport net.sf.jsqlparser.statement.select.*;\nimport org.apache.ibatis.logging.Log;\nimport org.apache.ibatis.logging.LogFactory;\n\nimport java.util.List;\n\n/**\n * 处理 Order by\n *\n * @author liuzh\n * @since 2015-06-27\n */\npublic class DefaultOrderBySqlParser implements OrderBySqlParser {\n    private static final Log log = LogFactory.getLog(DefaultOrderBySqlParser.class);\n\n    /**\n     * convert to order by sql\n     *\n     * @param sql\n     * @param orderBy\n     * @return\n     */\n    @Override\n    public String converToOrderBySql(String sql, String orderBy) {\n        //解析SQL\n        Statement stmt = null;\n        try {\n            stmt = SqlParserUtil.parse(sql);\n            Select select = (Select) stmt;\n            //处理body-去最外层order by\n            List<OrderByElement> orderByElements = extraOrderBy(select);\n            String defaultOrderBy = PlainSelect.orderByToString(orderByElements);\n            if (defaultOrderBy.indexOf('?') != -1) {\n                throw new PageException(\"The order by in the original SQL[\" + sql + \"] contains parameters, so it cannot be modified using the OrderBy plugin!\");\n            }\n            //新的sql\n            sql = select.toString();\n        } catch (Throwable e) {\n            log.warn(\"Failed to handle sorting: \" + e + \", downgraded to a direct splice of the order by parameter\");\n        }\n        return sql + \" order by \" + orderBy;\n    }\n\n    /**\n     * extra order by and set default orderby to null\n     *\n     * @param select\n     */\n    public static List<OrderByElement> extraOrderBy(Select select) {\n        if (select != null) {\n            if (select instanceof PlainSelect || select instanceof SetOperationList) {\n                List<OrderByElement> orderByElements = select.getOrderByElements();\n                select.setOrderByElements(null);\n                return orderByElements;\n            } else if (select instanceof ParenthesedSelect) {\n                extraOrderBy(((ParenthesedSelect) select).getSelect());\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/parser/defaults/DefaultSqlServerSqlParser.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.parser.defaults;\n\nimport com.github.pagehelper.PageException;\nimport com.github.pagehelper.parser.SqlParserUtil;\nimport com.github.pagehelper.parser.SqlServerSqlParser;\nimport net.sf.jsqlparser.expression.Alias;\nimport net.sf.jsqlparser.expression.Expression;\nimport net.sf.jsqlparser.expression.LongValue;\nimport net.sf.jsqlparser.expression.operators.relational.GreaterThan;\nimport net.sf.jsqlparser.schema.Column;\nimport net.sf.jsqlparser.schema.Table;\nimport net.sf.jsqlparser.statement.Statement;\nimport net.sf.jsqlparser.statement.select.*;\n\nimport java.util.*;\n\n/**\n * 将sqlserver查询语句转换为分页语句<br>\n * 注意事项：<br>\n * <ol>\n * <li>请先保证你的SQL可以执行</li>\n * <li>sql中最好直接包含order by，可以自动从sql提取</li>\n * <li>如果没有order by，可以通过入参提供，但是需要自己保证正确</li>\n * <li>如果sql有order by，可以通过orderby参数覆盖sql中的order by</li>\n * <li>order by的列名不能使用别名</li>\n * <li>表和列使用别名的时候不要使用单引号(')</li>\n * </ol>\n * 该类设计为一个独立的工具类，依赖jsqlparser,可以独立使用\n *\n * @author liuzh\n */\npublic class DefaultSqlServerSqlParser implements SqlServerSqlParser {\n    //开始行号\n    public static final    String     START_ROW                = String.valueOf(Long.MIN_VALUE);\n    //结束行号\n    public static final    String     PAGE_SIZE                = String.valueOf(Long.MAX_VALUE);\n    //外层包装表\n    protected static final String     WRAP_TABLE               = \"WRAP_OUTER_TABLE\";\n    //表别名名字\n    protected static final String     PAGE_TABLE_NAME          = \"PAGE_TABLE_ALIAS\";\n    //protected\n    public static final    Alias      PAGE_TABLE_ALIAS         = new Alias(PAGE_TABLE_NAME);\n    //行号\n    protected static final String     PAGE_ROW_NUMBER          = \"PAGE_ROW_NUMBER\";\n    //行号列\n    protected static final Column     PAGE_ROW_NUMBER_COLUMN   = new Column(PAGE_ROW_NUMBER);\n    //TOP 100 PERCENT\n    protected static final Top        TOP100_PERCENT;\n    //别名前缀\n    protected static final String     PAGE_COLUMN_ALIAS_PREFIX = \"ROW_ALIAS_\";\n\n    //静态方法处理\n    static {\n        TOP100_PERCENT = new Top();\n        TOP100_PERCENT.setExpression(new LongValue(100));\n        TOP100_PERCENT.setPercentage(true);\n    }\n\n    /**\n     * 转换为分页语句\n     *\n     * @param sql\n     * @return\n     */\n    public String convertToPageSql(String sql) {\n        return convertToPageSql(sql, null, null);\n    }\n\n    /**\n     * 转换为分页语句\n     *\n     * @param sql\n     * @param offset\n     * @param limit\n     * @return\n     */\n    public String convertToPageSql(String sql, Integer offset, Integer limit) {\n        //解析SQL\n        Statement stmt;\n        try {\n            stmt = SqlParserUtil.parse(sql);\n        } catch (Throwable e) {\n            throw new PageException(\"The SQL statement cannot be converted to a pagination query!\", e);\n        }\n        if (!(stmt instanceof Select)) {\n            throw new PageException(\"the pagination statement must be a select query!\");\n        }\n        //获取分页查询的select\n        Select pageSelect = getPageSelect((Select) stmt);\n        String pageSql = pageSelect.toString();\n        //缓存移到外面了，所以不替换参数\n        if (offset != null) {\n            pageSql = pageSql.replace(START_ROW, String.valueOf(offset));\n        }\n        if (limit != null) {\n            pageSql = pageSql.replace(PAGE_SIZE, String.valueOf(limit));\n        }\n        return pageSql;\n    }\n\n    /**\n     * 获取一个外层包装的TOP查询\n     *\n     * @param select\n     * @return\n     */\n    protected Select getPageSelect(Select select) {\n        if (select instanceof SetOperationList) {\n            select = wrapSetOperationList((SetOperationList) select);\n        }\n        //这里的selectBody一定是PlainSelect\n        if (((PlainSelect) select).getTop() != null) {\n            throw new PageException(\"The pagination statement already contains the top, and can no longer be used to query the pagination plugin!\");\n        }\n        //获取查询列\n        List<SelectItem<?>> selectItems = getSelectItems((PlainSelect) select);\n        //对一层的SQL增加ROW_NUMBER()\n        List<SelectItem<?>> autoItems = new ArrayList<>();\n        SelectItem<?> orderByColumn = addRowNumber((PlainSelect) select, autoItems);\n        //加入自动生成列\n        ((PlainSelect) select).addSelectItems(autoItems.toArray(new SelectItem[0]));\n        //处理子语句中的order by\n        processSelectBody(select, 0);\n\n        //中层子查询\n        PlainSelect innerSelectBody = new PlainSelect();\n        //PAGE_ROW_NUMBER\n        innerSelectBody.addSelectItems(orderByColumn);\n        innerSelectBody.addSelectItems(selectItems.toArray(new SelectItem[0]));\n        //将原始查询作为内层子查询\n        ParenthesedSelect fromInnerItem = new ParenthesedSelect();\n        fromInnerItem.setSelect(select);\n        fromInnerItem.setAlias(PAGE_TABLE_ALIAS);\n        innerSelectBody.setFromItem(fromInnerItem);\n\n        //新建一个select\n        PlainSelect newSelect = new PlainSelect();\n        //设置top\n        Top top = new Top();\n        top.setExpression(new LongValue(Long.MAX_VALUE));\n        newSelect.setTop(top);\n        //设置order by\n        List<OrderByElement> orderByElements = new ArrayList<OrderByElement>();\n        OrderByElement orderByElement = new OrderByElement();\n        orderByElement.setExpression(PAGE_ROW_NUMBER_COLUMN);\n        orderByElements.add(orderByElement);\n        newSelect.setOrderByElements(orderByElements);\n        //设置where\n        GreaterThan greaterThan = new GreaterThan();\n        greaterThan.setLeftExpression(PAGE_ROW_NUMBER_COLUMN);\n        greaterThan.setRightExpression(new LongValue(Long.MIN_VALUE));\n        newSelect.setWhere(greaterThan);\n        //设置selectItems\n        newSelect.setSelectItems(selectItems);\n        //设置fromIterm\n        ParenthesedSelect fromItem = new ParenthesedSelect();\n        fromItem.setSelect(innerSelectBody); //中层子查询\n        fromItem.setAlias(PAGE_TABLE_ALIAS);\n        newSelect.setFromItem(fromItem);\n\n        if (isNotEmptyList(select.getWithItemsList())) {\n            newSelect.setWithItemsList(select.getWithItemsList());\n            select.setWithItemsList(null);\n        }\n        return newSelect;\n    }\n\n    /**\n     * 包装SetOperationList\n     *\n     * @param setOperationList\n     * @return\n     */\n    protected Select wrapSetOperationList(SetOperationList setOperationList) {\n        //获取最后一个plainSelect\n        Select setSelectBody = setOperationList.getSelects().get(setOperationList.getSelects().size() - 1);\n        if (!(setSelectBody instanceof PlainSelect)) {\n            throw new PageException(\"Unable to process the SQL, you can submit issues in GitHub for help.!\");\n        }\n        PlainSelect plainSelect = (PlainSelect) setSelectBody;\n        PlainSelect selectBody = new PlainSelect();\n        List<SelectItem<?>> selectItems = getSelectItems(plainSelect);\n        selectBody.setSelectItems(selectItems);\n\n        //设置fromIterm\n        ParenthesedSelect fromItem = new ParenthesedSelect();\n        fromItem.setSelect(setOperationList);\n        fromItem.setAlias(new Alias(WRAP_TABLE));\n        selectBody.setFromItem(fromItem);\n        //order by\n        if (isNotEmptyList(setOperationList.getOrderByElements())) {\n            selectBody.setOrderByElements(setOperationList.getOrderByElements());\n            setOperationList.setOrderByElements(null);\n        }\n        return selectBody;\n    }\n\n    /**\n     * 获取查询列\n     *\n     * @param plainSelect\n     * @return\n     */\n    protected List<SelectItem<?>> getSelectItems(PlainSelect plainSelect) {\n        //设置selectItems\n        List<SelectItem<?>> selectItems = new ArrayList<>();\n        for (SelectItem<?> selectItem : plainSelect.getSelectItems()) {\n            if (selectItem.getExpression() instanceof AllTableColumns) {\n                selectItems.add(new SelectItem<>(new AllColumns()));\n            } else if (selectItem.getAlias() != null) {\n                //直接使用别名\n                Column column = new Column(selectItem.getAlias().getName());\n                SelectItem<?> expressionItem = new SelectItem<>(column);\n                selectItems.add(expressionItem);\n            } else if (selectItem.getExpression() instanceof Column) {\n                Column column = (Column) selectItem.getExpression();\n                SelectItem<?> item = null;\n                if (column.getTable() != null) {\n                    Column newColumn = new Column(column.getColumnName());\n                    item = new SelectItem<>(newColumn);\n                    selectItems.add(item);\n                } else {\n                    selectItems.add(selectItem);\n                }\n            } else {\n                selectItems.add(selectItem);\n            }\n        }\n        // SELECT *, 1 AS alias FROM TEST\n        // 应该为\n        // SELECT * FROM (SELECT *, 1 AS alias FROM TEST)\n        // 不应该为\n        // SELECT *, alias FROM (SELECT *, 1 AS alias FROM TEST)\n        for (SelectItem<?> selectItem : selectItems) {\n            if (selectItem.getExpression() instanceof AllColumns) {\n                return Collections.singletonList(selectItem);\n            }\n        }\n        return selectItems;\n    }\n\n    /**\n     * 获取 ROW_NUMBER() 列\n     *\n     * @param plainSelect 原查询\n     * @param autoItems   自动生成的查询列\n     * @return ROW_NUMBER() 列\n     */\n    protected SelectItem<?> addRowNumber(PlainSelect plainSelect, List<SelectItem<?>> autoItems) {\n        //增加ROW_NUMBER()\n        StringBuilder orderByBuilder = new StringBuilder();\n        orderByBuilder.append(\"ROW_NUMBER() OVER (\");\n        if (isNotEmptyList(plainSelect.getOrderByElements())) {\n            orderByBuilder.append(PlainSelect.orderByToString(\n                    getOrderByElements(plainSelect, autoItems)).substring(1));\n            //清空排序列表\n            plainSelect.setOrderByElements(null);\n        } else {\n            orderByBuilder.append(\"ORDER BY RAND()\");\n        }\n        orderByBuilder.append(\") \");\n        orderByBuilder.append(PAGE_ROW_NUMBER);\n        return new SelectItem<>(new Column(orderByBuilder.toString()));\n    }\n\n    /**\n     * 处理selectBody去除Order by\n     *\n     * @param select\n     */\n    protected void processSelectBody(Select select, int level) {\n        if (select != null) {\n            if (select instanceof PlainSelect) {\n                processPlainSelect((PlainSelect) select, level + 1);\n            } else if (select instanceof WithItem) {\n                WithItem withItem = (WithItem) select;\n                if (withItem.getSelect() != null) {\n                    processSelectBody(withItem.getSelect(), level + 1);\n                }\n            } else {\n                SetOperationList operationList = (SetOperationList) select;\n                if (operationList.getSelects() != null && !operationList.getSelects().isEmpty()) {\n                    List<Select> plainSelects = operationList.getSelects();\n                    for (Select plainSelect : plainSelects) {\n                        processSelectBody(plainSelect, level + 1);\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * 处理PlainSelect类型的selectBody\n     *\n     * @param plainSelect\n     */\n    protected void processPlainSelect(PlainSelect plainSelect, int level) {\n        if (level > 1) {\n            if (isNotEmptyList(plainSelect.getOrderByElements())) {\n                if (plainSelect.getTop() == null) {\n                    plainSelect.setTop(TOP100_PERCENT);\n                }\n            }\n        }\n        if (plainSelect.getFromItem() != null) {\n            processFromItem(plainSelect.getFromItem(), level + 1);\n        }\n        if (plainSelect.getJoins() != null && !plainSelect.getJoins().isEmpty()) {\n            List<Join> joins = plainSelect.getJoins();\n            for (Join join : joins) {\n                if (join.getRightItem() != null) {\n                    processFromItem(join.getRightItem(), level + 1);\n                }\n            }\n        }\n    }\n\n    /**\n     * 处理子查询\n     *\n     * @param fromItem\n     */\n    protected void processFromItem(FromItem fromItem, int level) {\n        if (fromItem instanceof LateralSubSelect) {\n            processSelectBody(((LateralSubSelect) fromItem).getSelect(), level + 1);\n        } else if (fromItem instanceof ParenthesedSelect) {\n            processSelectBody(((ParenthesedSelect) fromItem).getSelect(), level + 1);\n        } else if (fromItem instanceof Select) {\n            processSelectBody((Select) fromItem, level + 1);\n        } else if (fromItem instanceof ParenthesedFromItem) {\n            processFromItem(((ParenthesedFromItem) fromItem).getFromItem(), level + 1);\n        }\n        //Table时不用处理\n    }\n\n    /**\n     * List不空\n     *\n     * @param list\n     * @return\n     */\n    public boolean isNotEmptyList(List<?> list) {\n        if (list == null || list.isEmpty()) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * 复制 OrderByElement\n     *\n     * @param orig  原 OrderByElement\n     * @param alias 新 OrderByElement 的排序要素\n     * @return 复制的新 OrderByElement\n     */\n    protected OrderByElement cloneOrderByElement(OrderByElement orig, String alias) {\n        return cloneOrderByElement(orig, new Column(alias));\n    }\n\n    /**\n     * 复制 OrderByElement\n     *\n     * @param orig       原 OrderByElement\n     * @param expression 新 OrderByElement 的排序要素\n     * @return 复制的新 OrderByElement\n     */\n    protected OrderByElement cloneOrderByElement(OrderByElement orig, Expression expression) {\n        OrderByElement element = new OrderByElement();\n        element.setAsc(orig.isAsc());\n        element.setAscDescPresent(orig.isAscDescPresent());\n        element.setNullOrdering(orig.getNullOrdering());\n        element.setExpression(expression);\n        return element;\n    }\n\n    /**\n     * 获取新的排序列表\n     *\n     * @param plainSelect 原始查询\n     * @param autoItems   生成的新查询要素\n     * @return 新的排序列表\n     */\n    protected List<OrderByElement> getOrderByElements(PlainSelect plainSelect,\n                                                      List<SelectItem<?>> autoItems) {\n        List<OrderByElement> orderByElements = plainSelect.getOrderByElements();\n        ListIterator<OrderByElement> iterator = orderByElements.listIterator();\n        OrderByElement orderByElement;\n\n        // 非 `*` 且 非 `t.*` 查询列集合\n        Map<String, SelectItem<?>> selectMap = new HashMap<>();\n        // 别名集合\n        Set<String> aliases = new HashSet<String>();\n        // 是否包含 `*` 查询列\n        boolean allColumns = false;\n        // `t.*` 查询列的表名集合\n        Set<String> allColumnsTables = new HashSet<String>();\n\n        for (SelectItem<?> item : plainSelect.getSelectItems()) {\n            Expression expression = item.getExpression();\n            if (expression instanceof AllTableColumns) {\n                allColumnsTables.add(((AllTableColumns) expression).getTable().getName());\n            } else if (expression instanceof AllColumns) {\n                allColumns = true;\n            } else {\n                selectMap.put(expression.toString(), item);\n                Alias alias = item.getAlias();\n                if (alias != null) {\n                    aliases.add(alias.getName());\n                }\n            }\n        }\n\n        // 开始遍历 OrderByElement 列表\n        int aliasNo = 1;\n        while (iterator.hasNext()) {\n            orderByElement = iterator.next();\n            Expression expression = orderByElement.getExpression();\n            SelectItem<?> selectExpressionItem = selectMap.get(expression.toString());\n            if (selectExpressionItem != null) { // OrderByElement 在查询列表中\n                Alias alias = selectExpressionItem.getAlias();\n                if (alias != null) { // 查询列含有别名时用查询列别名\n                    iterator.set(cloneOrderByElement(orderByElement, alias.getName()));\n\n                } else { // 查询列不包含别名\n                    if (expression instanceof Column) {\n                        // 查询列为普通列，这时因为列在嵌套查询外时名称中不包含表名，故去除排序列的表名引用\n                        // 例（仅为解释此处逻辑，不代表最终分页结果）：\n                        // SELECT TEST.A FROM TEST ORDER BY TEST.A\n                        // -->\n                        // SELECT A FROM (SELECT TEST.A FROM TEST) ORDER BY A\n                        ((Column) expression).setTable(null);\n\n                    } else {\n                        // 查询列不为普通列时（例如函数列）不支持分页\n                        // 此种情况比较难预测，简单的增加新列容易产生不可预料的结果\n                        // 而为列增加别名是非常简单的，故此要求排序复杂列必须使用别名\n                        throw new PageException(\"The column \\\"\" + expression + \"\\\" needs to define an alias\");\n                    }\n                }\n\n            } else { // OrderByElement 不在查询列表中，需要自动生成一个查询列\n                if (expression instanceof Column) { // OrderByElement 为普通列\n                    Table table = ((Column) expression).getTable();\n                    if (table == null) { // 表名为空\n                        if (allColumns ||\n                                (allColumnsTables.size() == 1 && plainSelect.getJoins() == null) ||\n                                aliases.contains(((Column) expression).getColumnName())) {\n                            // 包含`*`查询列 或者 只有一个 `t.*`列且为单表查询 或者 其实排序列是一个别名\n                            // 此时排序列其实已经包含在查询列表中了，不需做任何操作\n                            continue;\n                        }\n\n                    } else { //表名不为空\n                        String tableName = table.getName();\n                        if (allColumns || allColumnsTables.contains(tableName)) {\n                            // 包含`*`查询列 或者 包含特定的`t.*`列\n                            // 此时排序列其实已经包含在查询列表中了，只需去除排序列的表名引\n                            ((Column) expression).setTable(null);\n                            continue;\n                        }\n                    }\n                }\n\n                // 将排序列加入查询列中\n                String aliasName = PAGE_COLUMN_ALIAS_PREFIX + aliasNo++;\n\n                SelectItem<?> item = new SelectItem<>(expression);\n                item.setAlias(new Alias(aliasName));\n                autoItems.add(item);\n\n                iterator.set(cloneOrderByElement(orderByElement, aliasName));\n            }\n        }\n\n        return orderByElements;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/util/ClassUtil.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;\n\nimport com.github.pagehelper.PageException;\nimport com.github.pagehelper.PageProperties;\n\nimport java.util.Properties;\nimport java.util.ServiceLoader;\nimport java.util.function.Supplier;\n\npublic class ClassUtil {\n\n    /**\n     * 支持配置和SPI，优先级：配置类 > SPI > 默认值\n     *\n     * @param classStr        配置串，可空\n     * @param spi             SPI 接口\n     * @param properties      配置属性\n     * @param defaultSupplier 默认值\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T newInstance(String classStr, Class<T> spi, Properties properties, Supplier<T> defaultSupplier) {\n        if (StringUtil.isNotEmpty(classStr)) {\n            try {\n                Class<?> cls = Class.forName(classStr);\n                return (T) newInstance(cls, properties);\n            } catch (Exception ignored) {\n            }\n        }\n        T result = null;\n        if (spi != null) {\n            ServiceLoader<T> loader = ServiceLoader.load(spi);\n            for (T t : loader) {\n                result = t;\n                break;\n            }\n        }\n        if (result == null) {\n            result = defaultSupplier.get();\n        }\n        if (result instanceof PageProperties) {\n            ((PageProperties) result).setProperties(properties);\n        }\n        return result;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T newInstance(String classStr, Properties properties) {\n        try {\n            Class<?> cls = Class.forName(classStr);\n            return (T) newInstance(cls, properties);\n        } catch (Exception e) {\n            throw new PageException(e);\n        }\n    }\n\n    public static <T> T newInstance(Class<T> cls, Properties properties) {\n        try {\n            T instance = cls.newInstance();\n            if (instance instanceof PageProperties) {\n                ((PageProperties) instance).setProperties(properties);\n            }\n            return instance;\n        } catch (Exception e) {\n            throw new PageException(e);\n        }\n    }\n\n    public static Class<?> getServletRequestClass() throws ClassNotFoundException {\n        Class<?> requestClass = null;\n        try {\n            requestClass = Class.forName(\"javax.servlet.ServletRequest\");\n        }catch (ClassNotFoundException exception){\n        }\n        if (requestClass != null){\n            return requestClass;\n        }\n        return Class.forName(\"jakarta.servlet.ServletRequest\");\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/util/ExecutorUtil.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;\n\nimport com.github.pagehelper.BoundSqlInterceptor;\nimport com.github.pagehelper.Dialect;\nimport com.github.pagehelper.PageException;\nimport org.apache.ibatis.builder.annotation.ProviderSqlSource;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.executor.Executor;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.session.Configuration;\nimport org.apache.ibatis.session.ResultHandler;\nimport org.apache.ibatis.session.RowBounds;\n\nimport java.lang.reflect.Field;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @author liuzenghui\n */\npublic abstract class ExecutorUtil {\n\n    private static Field additionalParametersField;\n\n    private static Field providerMethodArgumentNamesField;\n\n    static {\n        try {\n            additionalParametersField = BoundSql.class.getDeclaredField(\"additionalParameters\");\n            additionalParametersField.setAccessible(true);\n        } catch (NoSuchFieldException e) {\n            throw new PageException(\"Failed to get the BoundSql property additionalParameters: \" + e, e);\n        }\n        try {\n            //兼容低版本\n            providerMethodArgumentNamesField = ProviderSqlSource.class.getDeclaredField(\"providerMethodArgumentNames\");\n            providerMethodArgumentNamesField.setAccessible(true);\n        } catch (NoSuchFieldException ignore) {\n        }\n    }\n\n    /**\n     * 获取 BoundSql 属性值 additionalParameters\n     *\n     * @param boundSql\n     * @return\n     */\n    public static Map<String, Object> getAdditionalParameter(BoundSql boundSql) {\n        try {\n            return (Map<String, Object>) additionalParametersField.get(boundSql);\n        } catch (IllegalAccessException e) {\n            throw new PageException(\"Failed to get the BoundSql property additionalParameters: \" + e, e);\n        }\n    }\n\n    /**\n     * 获取 ProviderSqlSource 属性值 providerMethodArgumentNames\n     *\n     * @param providerSqlSource\n     * @return\n     */\n    public static String[] getProviderMethodArgumentNames(ProviderSqlSource providerSqlSource) {\n        try {\n            return providerMethodArgumentNamesField != null ? (String[]) providerMethodArgumentNamesField.get(providerSqlSource) : null;\n        } catch (IllegalAccessException e) {\n            throw new PageException(\"Get the ProviderSqlSource property value of providerMethodArgumentNames: \" + e, e);\n        }\n    }\n\n    /**\n     * 尝试获取已经存在的在 MS，提供对手写count和page的支持\n     *\n     * @param configuration\n     * @param msId\n     * @return\n     */\n    public static MappedStatement getExistedMappedStatement(Configuration configuration, String msId) {\n        MappedStatement mappedStatement = null;\n        try {\n            mappedStatement = configuration.getMappedStatement(msId, false);\n        } catch (Throwable t) {\n            //ignore\n        }\n        return mappedStatement;\n    }\n\n    /**\n     * 执行手动设置的 count 查询，该查询支持的参数必须和被分页的方法相同\n     *\n     * @param executor\n     * @param countMs\n     * @param parameter\n     * @param boundSql\n     * @param resultHandler\n     * @return\n     * @throws SQLException\n     */\n    public static Long executeManualCount(Executor executor, MappedStatement countMs,\n                                          Object parameter, BoundSql boundSql,\n                                          ResultHandler resultHandler) throws SQLException {\n        CacheKey countKey = executor.createCacheKey(countMs, parameter, RowBounds.DEFAULT, boundSql);\n        BoundSql countBoundSql = countMs.getBoundSql(parameter);\n        Object countResultList = executor.query(countMs, parameter, RowBounds.DEFAULT, resultHandler, countKey, countBoundSql);\n        //某些数据（如 TDEngine）查询 count 无结果时返回 null\n        if (countResultList == null || ((List) countResultList).isEmpty()) {\n            return 0L;\n        }\n        return ((Number) ((List) countResultList).get(0)).longValue();\n    }\n\n    /**\n     * 执行自动生成的 count 查询\n     *\n     * @param dialect\n     * @param executor\n     * @param countMs\n     * @param parameter\n     * @param boundSql\n     * @param rowBounds\n     * @param resultHandler\n     * @return\n     * @throws SQLException\n     */\n    public static Long executeAutoCount(Dialect dialect, Executor executor, MappedStatement countMs,\n                                        Object parameter, BoundSql boundSql,\n                                        RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {\n        Map<String, Object> additionalParameters = getAdditionalParameter(boundSql);\n        //创建 count 查询的缓存 key\n        CacheKey countKey = executor.createCacheKey(countMs, parameter, RowBounds.DEFAULT, boundSql);\n        //调用方言获取 count sql\n        String countSql = dialect.getCountSql(countMs, boundSql, parameter, rowBounds, countKey);\n        //countKey.update(countSql);\n        BoundSql countBoundSql = new BoundSql(countMs.getConfiguration(), countSql, boundSql.getParameterMappings(), parameter);\n        //当使用动态 SQL 时，可能会产生临时的参数，这些参数需要手动设置到新的 BoundSql 中\n        for (String key : additionalParameters.keySet()) {\n            countBoundSql.setAdditionalParameter(key, additionalParameters.get(key));\n        }\n        //对 boundSql 的拦截处理\n        if (dialect instanceof BoundSqlInterceptor.Chain) {\n            countBoundSql = ((BoundSqlInterceptor.Chain) dialect).doBoundSql(BoundSqlInterceptor.Type.COUNT_SQL, countBoundSql, countKey);\n        }\n        //执行 count 查询\n        Object countResultList = executor.query(countMs, parameter, RowBounds.DEFAULT, resultHandler, countKey, countBoundSql);\n        //某些数据（如 TDEngine）查询 count 无结果时返回 null\n        if (countResultList == null || ((List) countResultList).isEmpty()) {\n            return 0L;\n        }\n        return ((Number) ((List) countResultList).get(0)).longValue();\n    }\n\n    /**\n     * 分页查询\n     *\n     * @param dialect\n     * @param executor\n     * @param ms\n     * @param parameter\n     * @param rowBounds\n     * @param resultHandler\n     * @param boundSql\n     * @param cacheKey\n     * @param <E>\n     * @return\n     * @throws SQLException\n     */\n    public static <E> List<E> pageQuery(Dialect dialect, Executor executor, MappedStatement ms, Object parameter,\n                                        RowBounds rowBounds, ResultHandler resultHandler,\n                                        BoundSql boundSql, CacheKey cacheKey) throws SQLException {\n        //判断是否需要进行分页查询\n        if (dialect.beforePage(ms, parameter, rowBounds)) {\n            //生成分页的缓存 key\n            CacheKey pageKey = cacheKey;\n            //处理参数对象\n            parameter = dialect.processParameterObject(ms, parameter, boundSql, pageKey);\n            //调用方言获取分页 sql\n            String pageSql = dialect.getPageSql(ms, boundSql, parameter, rowBounds, pageKey);\n            BoundSql pageBoundSql = new BoundSql(ms.getConfiguration(), pageSql, boundSql.getParameterMappings(), parameter);\n\n            Map<String, Object> additionalParameters = getAdditionalParameter(boundSql);\n            //设置动态参数\n            for (String key : additionalParameters.keySet()) {\n                pageBoundSql.setAdditionalParameter(key, additionalParameters.get(key));\n            }\n            //对 boundSql 的拦截处理\n            if (dialect instanceof BoundSqlInterceptor.Chain) {\n                pageBoundSql = ((BoundSqlInterceptor.Chain) dialect).doBoundSql(BoundSqlInterceptor.Type.PAGE_SQL, pageBoundSql, pageKey);\n            }\n            //执行分页查询\n            return executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, pageKey, pageBoundSql);\n        } else {\n            //不执行分页的情况下，也不执行内存分页\n            return executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, boundSql);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/util/MSUtils.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;\n\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.mapping.ResultMap;\nimport org.apache.ibatis.mapping.ResultMapping;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 创建新的MappedStatement,主要是Count返回值int\n *\n * @author liuzh\n */\npublic class MSUtils {\n    private static final List<ResultMapping> EMPTY_RESULTMAPPING = new ArrayList<ResultMapping>(0);\n\n    /**\n     * 新建count查询的MappedStatement\n     *\n     * @param ms\n     * @param newMsId\n     * @return\n     */\n    public static MappedStatement newCountMappedStatement(MappedStatement ms, String newMsId) {\n        MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), newMsId, ms.getSqlSource(), ms.getSqlCommandType());\n        builder.resource(ms.getResource());\n        builder.fetchSize(ms.getFetchSize());\n        builder.statementType(ms.getStatementType());\n        builder.keyGenerator(ms.getKeyGenerator());\n        if (ms.getKeyProperties() != null && ms.getKeyProperties().length != 0) {\n            StringBuilder keyProperties = new StringBuilder();\n            for (String keyProperty : ms.getKeyProperties()) {\n                keyProperties.append(keyProperty).append(\",\");\n            }\n            keyProperties.delete(keyProperties.length() - 1, keyProperties.length());\n            builder.keyProperty(keyProperties.toString());\n        }\n        builder.timeout(ms.getTimeout());\n        builder.parameterMap(ms.getParameterMap());\n        //count查询返回值int\n        List<ResultMap> resultMaps = new ArrayList<ResultMap>();\n        ResultMap resultMap = new ResultMap.Builder(ms.getConfiguration(), ms.getId(), Long.class, EMPTY_RESULTMAPPING).build();\n        resultMaps.add(resultMap);\n        builder.resultMaps(resultMaps);\n        builder.resultSetType(ms.getResultSetType());\n        builder.cache(ms.getCache());\n        builder.flushCacheRequired(ms.isFlushCacheRequired());\n        builder.useCache(ms.isUseCache());\n\n        return builder.build();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/util/MetaObjectUtil.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;\n\nimport com.github.pagehelper.PageException;\nimport org.apache.ibatis.reflection.MetaObject;\n\nimport java.lang.reflect.Method;\n\n/**\n * @author liuzh\n */\npublic class MetaObjectUtil {\n    public static Method method;\n\n    static {\n        try {\n            // 高版本中的 MetaObject.forObject 有 4 个参数，低版本是 1 个\n            //先判断当前使用的是否为高版本\n            Class.forName(\"org.apache.ibatis.reflection.ReflectorFactory\");\n            // 下面这个 MetaObjectWithReflectCache 带反射的缓存信息\n            Class<?> metaClass = Class.forName(\"com.github.pagehelper.util.MetaObjectWithReflectCache\");\n            method = metaClass.getDeclaredMethod(\"forObject\", Object.class);\n        } catch (Throwable e1) {\n            try {\n                Class<?> metaClass = Class.forName(\"org.apache.ibatis.reflection.SystemMetaObject\");\n                method = metaClass.getDeclaredMethod(\"forObject\", Object.class);\n            } catch (Exception e2) {\n                try {\n                    Class<?> metaClass = Class.forName(\"org.apache.ibatis.reflection.MetaObject\");\n                    method = metaClass.getDeclaredMethod(\"forObject\", Object.class);\n                } catch (Exception e3) {\n                    throw new PageException(e3);\n                }\n            }\n        }\n    }\n\n    public static MetaObject forObject(Object object) {\n        try {\n            return (MetaObject) method.invoke(null, object);\n        } catch (Exception e) {\n            throw new PageException(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/util/MetaObjectWithReflectCache.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;\n\nimport com.github.pagehelper.PageException;\nimport org.apache.ibatis.reflection.DefaultReflectorFactory;\nimport org.apache.ibatis.reflection.MetaObject;\nimport org.apache.ibatis.reflection.ReflectorFactory;\nimport org.apache.ibatis.reflection.factory.DefaultObjectFactory;\nimport org.apache.ibatis.reflection.factory.ObjectFactory;\nimport org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;\nimport org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;\n\n/**\n * 反射带缓存，提高反射性能\n *\n * @author liuzh\n */\npublic class MetaObjectWithReflectCache {\n    public static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();\n    public static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();\n    public static final ReflectorFactory DEFAULT_REFLECTOR_FACTORY = new DefaultReflectorFactory();\n\n    public static MetaObject forObject(Object object) {\n        try {\n            return MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);\n        } catch (Exception e) {\n            throw new PageException(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/util/PageObjectUtil.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;\n\nimport com.github.pagehelper.IPage;\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageException;\nimport org.apache.ibatis.reflection.MetaObject;\n\nimport java.lang.reflect.Method;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 分页参数对象工具类\n *\n * @author liuzh\n */\npublic abstract class PageObjectUtil {\n    //request获取方法\n    protected static Boolean hasRequest;\n    protected static Class<?> requestClass;\n    protected static Method getParameterMap;\n    protected static Map<String, String> PARAMS = new HashMap<String, String>(6, 1);\n\n    static {\n        try {\n            requestClass = ClassUtil.getServletRequestClass();\n            getParameterMap = requestClass.getMethod(\"getParameterMap\", new Class[]{});\n            hasRequest = true;\n        } catch (Throwable e) {\n            hasRequest = false;\n        }\n        PARAMS.put(\"pageNum\", \"pageNum\");\n        PARAMS.put(\"pageSize\", \"pageSize\");\n        PARAMS.put(\"count\", \"countSql\");\n        PARAMS.put(\"orderBy\", \"orderBy\");\n        PARAMS.put(\"reasonable\", \"reasonable\");\n        PARAMS.put(\"pageSizeZero\", \"pageSizeZero\");\n    }\n\n    /**\n     * 对象中获取分页参数\n     *\n     * @param params\n     * @return\n     */\n    public static <T> Page<T> getPageFromObject(Object params, boolean required) {\n        if (params == null) {\n            throw new PageException(\"unable to get paginated query parameters!\");\n        }\n        if(params instanceof IPage){\n            IPage pageParams = (IPage) params;\n            Page page = null;\n            if(pageParams.getPageNum() != null && pageParams.getPageSize() != null){\n                page = new Page(pageParams.getPageNum(), pageParams.getPageSize());\n            }\n            if (StringUtil.isNotEmpty(pageParams.getOrderBy())) {\n                if(page != null){\n                    page.setOrderBy(pageParams.getOrderBy());\n                } else {\n                    page = new Page();\n                    page.setOrderBy(pageParams.getOrderBy());\n                    page.setOrderByOnly(true);\n                }\n            }\n            return page;\n        }\n        int pageNum;\n        int pageSize;\n        MetaObject paramsObject = null;\n        if (hasRequest && requestClass.isAssignableFrom(params.getClass())) {\n            try {\n                paramsObject = MetaObjectUtil.forObject(getParameterMap.invoke(params, new Object[]{}));\n            } catch (Exception e) {\n                //忽略\n            }\n        } else {\n            paramsObject = MetaObjectUtil.forObject(params);\n        }\n        if (paramsObject == null) {\n            throw new PageException(\"The pagination query parameter failed to be processed!\");\n        }\n        Object orderBy = getParamValue(paramsObject, \"orderBy\", false);\n        boolean hasOrderBy = false;\n        if (orderBy != null && orderBy.toString().length() > 0) {\n            hasOrderBy = true;\n        }\n        try {\n            Object _pageNum = getParamValue(paramsObject, \"pageNum\", required);\n            Object _pageSize = getParamValue(paramsObject, \"pageSize\", required);\n            if (_pageNum == null || _pageSize == null) {\n                if(hasOrderBy){\n                    Page page = new Page();\n                    page.setOrderBy(orderBy.toString());\n                    page.setOrderByOnly(true);\n                    return page;\n                }\n                return null;\n            }\n            pageNum = Integer.parseInt(String.valueOf(_pageNum));\n            pageSize = Integer.parseInt(String.valueOf(_pageSize));\n        } catch (NumberFormatException e) {\n            throw new PageException(\"pagination parameters are not a valid number type!\", e);\n        }\n        Page page = new Page(pageNum, pageSize);\n        //count查询\n        Object _count = getParamValue(paramsObject, \"count\", false);\n        if (_count != null) {\n            page.setCount(Boolean.valueOf(String.valueOf(_count)));\n        }\n        //排序\n        if (hasOrderBy) {\n            page.setOrderBy(orderBy.toString());\n        }\n        //分页合理化\n        Object reasonable = getParamValue(paramsObject, \"reasonable\", false);\n        if (reasonable != null) {\n            page.setReasonable(Boolean.valueOf(String.valueOf(reasonable)));\n        }\n        //查询全部\n        Object pageSizeZero = getParamValue(paramsObject, \"pageSizeZero\", false);\n        if (pageSizeZero != null) {\n            page.setPageSizeZero(Boolean.valueOf(String.valueOf(pageSizeZero)));\n        }\n        return page;\n    }\n\n    /**\n     * 从对象中取参数\n     *\n     * @param paramsObject\n     * @param paramName\n     * @param required\n     * @return\n     */\n    protected static Object getParamValue(MetaObject paramsObject, String paramName, boolean required) {\n        Object value = null;\n        if (paramsObject.hasGetter(PARAMS.get(paramName))) {\n            value = paramsObject.getValue(PARAMS.get(paramName));\n        }\n        if (value != null && value.getClass().isArray()) {\n            Object[] values = (Object[]) value;\n            if (values.length == 0) {\n                value = null;\n            } else {\n                value = values[0];\n            }\n        }\n        if (required && value == null) {\n            throw new PageException(\"Paginated queries are missing the necessary parameters:\" + PARAMS.get(paramName));\n        }\n        return value;\n    }\n\n    public static void setParams(String params) {\n        if (StringUtil.isNotEmpty(params)) {\n            String[] ps = params.split(\"[;|,|&]\");\n            for (String s : ps) {\n                String[] ss = s.split(\"[=|:]\");\n                if (ss.length == 2) {\n                    PARAMS.put(ss[0], ss[1]);\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/util/SqlSafeUtil.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;\n\nimport java.util.regex.Pattern;\n\n/**\n * 更严格的SQL注入检测\n */\npublic class SqlSafeUtil {\n    /**\n     * SQL语法检查正则：符合两个关键字（有先后顺序）才算匹配\n     * <p>\n     * 参考: mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/sql/SqlInjectionUtils.java\n     */\n    private static final Pattern SQL_SYNTAX_PATTERN  = Pattern.compile(\"(insert|delete|update|select|create|drop|truncate|grant|alter|deny|revoke|call|execute|exec|declare|show|rename|set)\" +\n            \"\\\\s+.*(into|from|set|where|table|database|view|index|on|cursor|procedure|trigger|for|password|union|and|or)|(select\\\\s*\\\\*\\\\s*from\\\\s+)\", Pattern.CASE_INSENSITIVE);\n    /**\n     * 使用'、;或注释截断SQL检查正则\n     * <p>\n     * 参考: mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/sql/SqlInjectionUtils.java\n     */\n    private static final Pattern SQL_COMMENT_PATTERN = Pattern.compile(\"'.*(or|union|--|#|/*|;)\", Pattern.CASE_INSENSITIVE);\n\n    /**\n     * 检查参数是否存在 SQL 注入\n     *\n     * @param value 检查参数\n     * @return true 非法 false 合法\n     */\n    public static boolean check(String value) {\n        if (value == null) {\n            return false;\n        }\n        // 不允许使用任何函数（不能出现括号），否则无法检测后面这个注入 order by id,if(1=2,1,(sleep(100)));\n        return value.contains(\"(\") || SQL_COMMENT_PATTERN.matcher(value).find() || SQL_SYNTAX_PATTERN.matcher(value).find();\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/util/StackTraceUtil.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\n\npublic class StackTraceUtil {\n\n    /**\n     * 当前方法堆栈信息\n     */\n    public static String current() {\n        Exception exception = new Exception(\"Stack information when setting pagination parameters\");\n        StringWriter writer = new StringWriter();\n        exception.printStackTrace(new PrintWriter(writer));\n        return writer.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/github/pagehelper/util/StringUtil.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;\n\n/**\n * @author liuzh\n * @since 4.1.0\n */\npublic class StringUtil {\n\n    public static boolean isEmpty(String str) {\n        if (str == null || str.length() == 0) {\n            return true;\n        }\n        return false;\n    }\n\n    public static boolean isNotEmpty(String str) {\n        return !isEmpty(str);\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/mapper/ProviderMethod.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.mapper;\n\nimport com.github.pagehelper.model.User;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @author liuzh\n */\npublic class ProviderMethod {\n\n    public String selectSimple(String str) {\n        return \"select * from user where name like '%\" + str + \"'\";\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public String select(Map<String, Object> map) {\n        Map<String, Object> param = (HashMap<String, Object>) map.get(\"param\");\n        StringBuilder sbSql = new StringBuilder();\n        sbSql.append(\"select * from user where 1=1 \");\n        for (Map.Entry<String, Object> entry : param.entrySet()) {\n            sbSql.append(\" and \" + entry.getKey() + \"= #{param.\" + entry.getKey() + \"} \");\n        }\n        sbSql.append(\"order by id\");\n        return sbSql.toString();\n    }\n\n    public String selectUser(User user) {\n        StringBuilder sbSql = new StringBuilder();\n        sbSql.append(\"select * from user where 1=1 \");\n        if (user.getId() > 0) {\n            sbSql.append(\" and id = #{id} \");\n        }\n        if (user.getPy() != null) {\n            sbSql.append(\" and py = #{py} \");\n        }\n        if (user.getName() != null) {\n            sbSql.append(\" and name = #{name} \");\n        }\n        sbSql.append(\"order by id\");\n        return sbSql.toString();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/mapper/UserMapper.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.mapper;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.model.*;\nimport com.github.pagehelper.test.basic.dynamic.Where;\nimport org.apache.ibatis.annotations.Param;\nimport org.apache.ibatis.annotations.Select;\nimport org.apache.ibatis.annotations.SelectProvider;\nimport org.apache.ibatis.session.RowBounds;\n\nimport java.util.List;\nimport java.util.Map;\n\n@SuppressWarnings(\"rawtypes\")\npublic interface UserMapper {\n\n        @Select(\"select * from user order by ${order}\")\n        List<User> selectByOrder(@Param(\"order\") String order);\n\n        // 增加Provider测试\n        @SelectProvider(type = ProviderMethod.class, method = \"selectSimple\")\n        Page<User> selectSimple(String str);\n\n        // 增加Provider测试\n        @SelectProvider(type = ProviderMethod.class, method = \"select\")\n        List<User> selectByProvider(@Param(\"param\") Map map);\n\n        @SelectProvider(type = ProviderMethod.class, method = \"selectUser\")\n        List<User> selectByUserProvider(User user);\n\n        @Select(\"Select * from user\")\n        List<Map<String, Object>> selectBySelect();\n\n        List<User> selectByOrder2(@Param(\"order\") String order);\n\n        List<User> selectAll();\n\n        // 嵌套查询\n        List<User> selectCollectionMap();\n\n        List<User> selectGreterThanId(int id);\n\n        List<User> selectGreterThanIdAndNotEquelName(@Param(\"id\") int id, @Param(\"name\") String name);\n\n        List<User> selectAll(RowBounds rowBounds);\n\n        List<User> selectAllOrderby();\n\n        List<User> selectAllOrderByParams(@Param(\"order1\") String order1, @Param(\"order2\") String order2);\n\n        // 下面是三种参数类型的测试方法\n        List<User> selectAllOrderByMap(Map orders);\n\n        List<User> selectAllOrderByList(List<Integer> params);\n\n        List<User> selectAllOrderByArray(Integer[] params);\n\n        // 测试动态sql,where/if\n        List<User> selectIf(@Param(\"id\") Integer id);\n\n        List<User> selectIf3(User user);\n\n        List<User> selectIf2(@Param(\"id1\") Integer id1, @Param(\"id2\") Integer id2);\n\n        List<User> selectIf2List(@Param(\"id1\") List<Integer> id1, @Param(\"id2\") List<Integer> id2);\n\n        List<User> selectIf2ListAndOrder(@Param(\"id1\") List<Integer> id1, @Param(\"id2\") List<Integer> id2,\n                        @Param(\"order\") String order);\n\n        List<User> selectChoose(@Param(\"id1\") Integer id1, @Param(\"id2\") Integer id2);\n\n        List<User> selectLike(User user);\n\n        // 特殊sql语句的测试 - 主要测试count查询\n        List<User> selectUnion();\n\n        List<User> selectLeftjoin();\n\n        List<User> selectWith();\n\n        // select column中包含参数时\n        List<User> selectColumns(@Param(\"columns\") String... columns);\n\n        List<User> selectMULId(int mul);\n\n        // group by时\n        List<User> selectGroupBy();\n\n        // select Map\n        List<User> selectByWhereMap(Where where);\n\n        // Example\n        List<User> selectByExample(UserExample example);\n\n        List<User> selectDistinct();\n\n        List<User> selectExists();\n\n        List<User> selectByPageNumSize(@Param(\"pageNum\") int pageNum, @Param(\"pageSize\") int pageSize);\n\n        List<User> selectByPageNumSizeOrderBy(@Param(\"pageNum\") int pageNum, @Param(\"pageSize\") int pageSize,\n                        @Param(\"orderBy\") String orderBy);\n\n        List<User> selectByOrderBy(@Param(\"orderBy\") String orderBy);\n\n        List<User> selectByQueryModel(UserQueryModel queryModel);\n\n        List<User> selectByIdList(@Param(\"idList\") List<Long> idList);\n\n        List<User> selectByIdList2(@Param(\"idList\") List<Long> idList);\n\n        List<Map<String, Object>> execute(@Param(\"sql\") String sql);\n\n        List<UserCode> selectByCode(Code code);\n\n        /**\n         * Test for issue #868: ORDER BY with parameter binding\n         */\n        List<User> selectOrderByWithParam(@Param(\"py\") String py);\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/model/Code.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.model;\n\n/**\n * @author liuzh\n * @since 2017/5/30.\n */\npublic enum Code {\n    LR, LQQ\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/model/User.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.model;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * Description: User\n * Author: liuzh\n * Update: liuzh(2014-06-06 13:38)\n */\npublic class User\n    implements Serializable {\n    private static final long serialVersionUID = 6569081236403751407L;\n\n    private int id;\n    List<User> users;\n    private String name;\n    private String py;\n\n    public int getId() {\n        return id;\n    }\n\n    public void setId(int id) {\n        this.id = id;\n    }\n\n    @Override\n    public String toString() {\n        return \"User{\" +\n            \"id=\" + id +\n            \", name='\" + name + '\\'' +\n            \", py='\" + py + '\\'' +\n            \", user=\" + users +\n            '}';\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getPy() {\n        return py;\n    }\n\n    public void setPy(String py) {\n        this.py = py;\n    }\n\n    public List<User> getUsers() {\n        return users;\n    }\n\n    public void setUsers(List<User> users) {\n        this.users = users;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/model/UserCode.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.model;\n\nimport java.io.Serializable;\nimport java.util.List;\n\npublic class UserCode implements Serializable {\n    private static final long serialVersionUID = 6569081236403751407L;\n\n    private int id;\n    List<UserCode> users;\n    private String name;\n    private Code py;\n\n    public int getId() {\n        return id;\n    }\n\n    public void setId(int id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public UserCode setName(String name) {\n        this.name = name;\n        return this;\n    }\n\n    public Code getPy() {\n        return py;\n    }\n\n    public void setPy(Code py) {\n        this.py = py;\n    }\n\n    public List<UserCode> getUsers() {\n        return users;\n    }\n\n    public void setUsers(List<UserCode> users) {\n        this.users = users;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/model/UserExample.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.model;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class UserExample {\n    protected String orderByClause;\n\n    protected boolean distinct;\n\n    protected List<Criteria> oredCriteria;\n\n    public UserExample() {\n        oredCriteria = new ArrayList<Criteria>();\n    }\n\n    public void or(Criteria criteria) {\n        oredCriteria.add(criteria);\n    }\n\n    public Criteria or() {\n        Criteria criteria = createCriteriaInternal();\n        oredCriteria.add(criteria);\n        return criteria;\n    }\n\n    public Criteria createCriteria() {\n        Criteria criteria = createCriteriaInternal();\n        if (oredCriteria.size() == 0) {\n            oredCriteria.add(criteria);\n        }\n        return criteria;\n    }\n\n    protected Criteria createCriteriaInternal() {\n        Criteria criteria = new Criteria();\n        return criteria;\n    }\n\n    public void clear() {\n        oredCriteria.clear();\n        orderByClause = null;\n        distinct = false;\n    }\n\n    protected abstract static class GeneratedCriteria {\n        protected List<Criterion> criteria;\n\n        protected GeneratedCriteria() {\n            super();\n            criteria = new ArrayList<Criterion>();\n        }\n\n        protected void addCriterion(String condition) {\n            if (condition == null) {\n                throw new RuntimeException(\"Value for condition cannot be null\");\n            }\n            criteria.add(new Criterion(condition));\n        }\n\n        protected void addCriterion(String condition, Object value, String property) {\n            if (value == null) {\n                throw new RuntimeException(\"Value for \" + property + \" cannot be null\");\n            }\n            criteria.add(new Criterion(condition, value));\n        }\n\n        protected void addCriterion(String condition, Object value1, Object value2, String property) {\n            if (value1 == null || value2 == null) {\n                throw new RuntimeException(\"Between values for \" + property + \" cannot be null\");\n            }\n            criteria.add(new Criterion(condition, value1, value2));\n        }\n\n        public Criteria andIdIsNull() {\n            addCriterion(\"Id is null\");\n            return (Criteria) this;\n        }\n\n        public Criteria andIdIsNotNull() {\n            addCriterion(\"Id is not null\");\n            return (Criteria) this;\n        }\n\n        public Criteria andIdEqualTo(Integer value) {\n            addCriterion(\"Id =\", value, \"id\");\n            return (Criteria) this;\n        }\n\n        public Criteria andIdNotEqualTo(Integer value) {\n            addCriterion(\"Id <>\", value, \"id\");\n            return (Criteria) this;\n        }\n\n        public Criteria andIdGreaterThan(Integer value) {\n            addCriterion(\"Id >\", value, \"id\");\n            return (Criteria) this;\n        }\n\n        public Criteria andIdGreaterThanOrEqualTo(Integer value) {\n            addCriterion(\"Id >=\", value, \"id\");\n            return (Criteria) this;\n        }\n\n        public Criteria andIdLessThan(Integer value) {\n            addCriterion(\"Id <\", value, \"id\");\n            return (Criteria) this;\n        }\n\n        public Criteria andIdLessThanOrEqualTo(Integer value) {\n            addCriterion(\"Id <=\", value, \"id\");\n            return (Criteria) this;\n        }\n\n        public Criteria andIdIn(List<Integer> values) {\n            addCriterion(\"Id in\", values, \"id\");\n            return (Criteria) this;\n        }\n\n        public Criteria andIdNotIn(List<Integer> values) {\n            addCriterion(\"Id not in\", values, \"id\");\n            return (Criteria) this;\n        }\n\n        public Criteria andIdBetween(Integer value1, Integer value2) {\n            addCriterion(\"Id between\", value1, value2, \"id\");\n            return (Criteria) this;\n        }\n\n        public Criteria andIdNotBetween(Integer value1, Integer value2) {\n            addCriterion(\"Id not between\", value1, value2, \"id\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsernameIsNull() {\n            addCriterion(\"name is null\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsernameIsNotNull() {\n            addCriterion(\"name is not null\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsernameEqualTo(String value) {\n            addCriterion(\"name =\", value, \"name\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsernameNotEqualTo(String value) {\n            addCriterion(\"name <>\", value, \"name\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsernameGreaterThan(String value) {\n            addCriterion(\"name >\", value, \"name\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsernameGreaterThanOrEqualTo(String value) {\n            addCriterion(\"name >=\", value, \"name\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsernameLessThan(String value) {\n            addCriterion(\"name <\", value, \"name\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsernameLessThanOrEqualTo(String value) {\n            addCriterion(\"name <=\", value, \"name\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsernameLike(String value) {\n            addCriterion(\"name like\", value, \"name\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsernameNotLike(String value) {\n            addCriterion(\"name not like\", value, \"name\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsernameIn(List<String> values) {\n            addCriterion(\"name in\", values, \"name\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsernameNotIn(List<String> values) {\n            addCriterion(\"name not in\", values, \"name\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsernameBetween(String value1, String value2) {\n            addCriterion(\"name between\", value1, value2, \"name\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsernameNotBetween(String value1, String value2) {\n            addCriterion(\"name not between\", value1, value2, \"name\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsercodeIsNull() {\n            addCriterion(\"py is null\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsercodeIsNotNull() {\n            addCriterion(\"py is not null\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsercodeEqualTo(String value) {\n            addCriterion(\"py =\", value, \"py\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsercodeNotEqualTo(String value) {\n            addCriterion(\"py <>\", value, \"py\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsercodeGreaterThan(String value) {\n            addCriterion(\"py >\", value, \"py\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsercodeGreaterThanOrEqualTo(String value) {\n            addCriterion(\"py >=\", value, \"py\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsercodeLessThan(String value) {\n            addCriterion(\"py <\", value, \"py\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsercodeLessThanOrEqualTo(String value) {\n            addCriterion(\"py <=\", value, \"py\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsercodeLike(String value) {\n            addCriterion(\"py like\", value, \"py\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsercodeNotLike(String value) {\n            addCriterion(\"py not like\", value, \"py\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsercodeIn(List<String> values) {\n            addCriterion(\"py in\", values, \"py\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsercodeNotIn(List<String> values) {\n            addCriterion(\"py not in\", values, \"py\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsercodeBetween(String value1, String value2) {\n            addCriterion(\"py between\", value1, value2, \"py\");\n            return (Criteria) this;\n        }\n\n        public Criteria andUsercodeNotBetween(String value1, String value2) {\n            addCriterion(\"py not between\", value1, value2, \"py\");\n            return (Criteria) this;\n        }\n\n        public List<Criterion> getAllCriteria() {\n            return criteria;\n        }\n\n        public List<Criterion> getCriteria() {\n            return criteria;\n        }\n\n        public boolean isValid() {\n            return criteria.size() > 0;\n        }\n    }\n\n    public static class Criteria extends GeneratedCriteria {\n\n        protected Criteria() {\n            super();\n        }\n    }\n\n    public static class Criterion {\n        private String condition;\n\n        private Object value;\n\n        private Object secondValue;\n\n        private boolean noValue;\n\n        private boolean singleValue;\n\n        private boolean betweenValue;\n\n        private boolean listValue;\n\n        private String typeHandler;\n\n        protected Criterion(String condition) {\n            super();\n            this.condition = condition;\n            this.typeHandler = null;\n            this.noValue = true;\n        }\n\n        protected Criterion(String condition, Object value, String typeHandler) {\n            super();\n            this.condition = condition;\n            this.value = value;\n            this.typeHandler = typeHandler;\n            if (value instanceof List<?>) {\n                this.listValue = true;\n            } else {\n                this.singleValue = true;\n            }\n        }\n\n        protected Criterion(String condition, Object value) {\n            this(condition, value, null);\n        }\n\n        protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {\n            super();\n            this.condition = condition;\n            this.value = value;\n            this.secondValue = secondValue;\n            this.typeHandler = typeHandler;\n            this.betweenValue = true;\n        }\n\n        protected Criterion(String condition, Object value, Object secondValue) {\n            this(condition, value, secondValue, null);\n        }\n\n        public String getCondition() {\n            return condition;\n        }\n\n        public Object getSecondValue() {\n            return secondValue;\n        }\n\n        public String getTypeHandler() {\n            return typeHandler;\n        }\n\n        public Object getValue() {\n            return value;\n        }\n\n        public boolean isBetweenValue() {\n            return betweenValue;\n        }\n\n        public boolean isListValue() {\n            return listValue;\n        }\n\n        public boolean isNoValue() {\n            return noValue;\n        }\n\n        public boolean isSingleValue() {\n            return singleValue;\n        }\n    }\n\n    public String getOrderByClause() {\n        return orderByClause;\n    }\n\n    public void setOrderByClause(String orderByClause) {\n        this.orderByClause = orderByClause;\n    }\n\n    public List<Criteria> getOredCriteria() {\n        return oredCriteria;\n    }\n\n    public boolean isDistinct() {\n        return distinct;\n    }\n\n    public void setDistinct(boolean distinct) {\n        this.distinct = distinct;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/model/UserQueryModel.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.model;\n\n/**\n * @author liuzh\n * @since 2015-11-07 14:39\n */\npublic class UserQueryModel {\n\n    private Integer pageNum;\n\n    private Integer pageSize;\n\n    private String orderBy;\n\n    public String getOrderBy() {\n        return orderBy;\n    }\n\n    public void setOrderBy(String orderBy) {\n        this.orderBy = orderBy;\n    }\n\n    public Integer getPageNum() {\n        return pageNum;\n    }\n\n    public void setPageNum(Integer pageNum) {\n        this.pageNum = pageNum;\n    }\n\n    public Integer getPageSize() {\n        return pageSize;\n    }\n\n    public void setPageSize(Integer pageSize) {\n        this.pageSize = pageSize;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/rowbounds/RowBoundsHelper.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.rowbounds;\n\nimport org.apache.ibatis.io.Resources;\nimport org.apache.ibatis.jdbc.ScriptRunner;\nimport org.apache.ibatis.session.SqlSession;\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.apache.ibatis.session.SqlSessionFactoryBuilder;\n\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.sql.Connection;\n\npublic class RowBoundsHelper {\n\n    private static SqlSessionFactory sqlSessionFactory;\n\n    static {\n        try {\n            //创建SqlSessionFactory\n            Reader reader = Resources.getResourceAsReader(\"rowbounds/mybatis-config.xml\");\n            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);\n            reader.close();\n            //创建数据库\n            SqlSession session = null;\n            try {\n                session = sqlSessionFactory.openSession();\n                Connection conn = session.getConnection();\n                reader = Resources.getResourceAsReader(\"rowbounds/hsqldb.sql\");\n                ScriptRunner runner = new ScriptRunner(conn);\n                runner.setLogWriter(null);\n                runner.runScript(reader);\n                reader.close();\n            } finally {\n                if (session != null) {\n                    session.close();\n                }\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 获取Session\n     *\n     * @return\n     */\n    public static SqlSession getSqlSession() {\n        return sqlSessionFactory.openSession();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/rowbounds/test/PageRowBoundsTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.rowbounds.test;\n\nimport com.github.pagehelper.PageRowBounds;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.rowbounds.RowBoundsHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class PageRowBoundsTest {\n\n    /**\n     * 使用Mapper接口调用时，对接口增加RowBounds参数，不需要修改对应的xml配置（或注解配置）\n     * <p/>\n     * RowBounds方式不进行count查询，可以通过修改Page代码实现\n     * <p/>\n     * 这种情况下如果同时使用startPage方法，以startPage为准\n     */\n    @Test\n    public void testMapperWithPageRowBounds() {\n        SqlSession sqlSession = RowBoundsHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageRowBounds pageRowBounds = new PageRowBounds(0, 10);\n            List<User> list = userMapper.selectAll(pageRowBounds);\n            //新增PageInfo对象，对返回结果进行封装\n            assertEquals(10, list.size());\n            assertEquals(183L, pageRowBounds.getTotal().longValue());\n            //判断查询结果的位置是否正确\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.get(list.size() - 1).getId());\n\n\n            //获取第10页，10条内容，显式查询总数count\n            pageRowBounds = new PageRowBounds(90, 10);\n            list = userMapper.selectAll(pageRowBounds);\n            assertEquals(10, list.size());\n            assertEquals(183L, pageRowBounds.getTotal().longValue());\n            //判断查询结果的位置是否正确\n            assertEquals(91, list.get(0).getId());\n            assertEquals(100, list.get(list.size() - 1).getId());\n\n\n            //获取第3页，20条内容，默认查询总数count\n            pageRowBounds = new PageRowBounds(100, 20);\n            list = userMapper.selectAll(pageRowBounds);\n            assertEquals(20, list.size());\n            assertEquals(183L, pageRowBounds.getTotal().longValue());\n            //判断查询结果的位置是否正确\n            assertEquals(101, list.get(0).getId());\n            assertEquals(120, list.get(list.size() - 1).getId());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用命名空间方式的RowBounds进行分页，使用RowBounds时不进行count查询\n     * 通过修改代码可以进行count查询，没法通过其他方法改变参数\n     * 因为如果通过调用一个别的方法来标记count查询，还不如直接startPage\n     * <p/>\n     * 同时使用startPage时，以startPage为准，会根据startPage参数来查询\n     */\n    @Test\n    public void testNamespaceWithPageRowBounds() {\n        SqlSession sqlSession = RowBoundsHelper.getSqlSession();\n        try {\n            //获取从0开始，10条内容\n            PageRowBounds pageRowBounds = new PageRowBounds(0, 10);\n            List<User> list = sqlSession.selectList(\"selectAll\", null, pageRowBounds);\n            assertEquals(10, list.size());\n            assertEquals(183L, pageRowBounds.getTotal().longValue());\n            //判断查询结果的位置是否正确\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.get(list.size() - 1).getId());\n\n\n            //获取从10开始，10条内容\n            pageRowBounds = new PageRowBounds(90, 10);\n            list = sqlSession.selectList(\"selectAll\", null, pageRowBounds);\n            assertEquals(10, list.size());\n            assertEquals(183L, pageRowBounds.getTotal().longValue());\n            //判断查询结果的位置是否正确\n            assertEquals(91, list.get(0).getId());\n            assertEquals(100, list.get(list.size() - 1).getId());\n\n\n            //获取从20开始，20条内容\n            pageRowBounds = new PageRowBounds(100, 20);\n            list = sqlSession.selectList(\"selectAll\", null, pageRowBounds);\n            assertEquals(20, list.size());\n            assertEquals(183L, pageRowBounds.getTotal().longValue());\n            //判断查询结果的位置是否正确\n            assertEquals(101, list.get(0).getId());\n            assertEquals(120, list.get(list.size() - 1).getId());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void testNamespaceWithRowBounds2() {\n        SqlSession sqlSession = RowBoundsHelper.getSqlSession();\n        try {\n            //获取从0开始，10条内容\n            PageRowBounds pageRowBounds = new PageRowBounds(0, 10);\n            List<User> list = sqlSession.selectList(\"selectIf\", null, pageRowBounds);\n            assertEquals(10, list.size());\n            assertEquals(183L, pageRowBounds.getTotal().longValue());\n            //判断查询结果的位置是否正确\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.get(list.size() - 1).getId());\n\n            Map<String, Object> map = new HashMap<String, Object>();\n            map.put(\"id\", 10);\n            //获取从10开始，10条内容\n            pageRowBounds = new PageRowBounds(90, 10);\n            list = sqlSession.selectList(\"selectIf\", map, pageRowBounds);\n            assertEquals(10, list.size());\n            assertEquals(173L, pageRowBounds.getTotal().longValue());\n            //判断查询结果的位置是否正确\n            assertEquals(101, list.get(0).getId());\n            assertEquals(110, list.get(list.size() - 1).getId());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testWithRowboundsAndCountTrue() {\n        SqlSession sqlSession = RowBoundsHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //limit=0,这时候相当于用分页插件求count,但是前提必须是配置rounbounds方式求count，否则都是-1\n            //这里由于没有配置，应该都是-1\n            PageRowBounds pageRowBounds = new PageRowBounds(0, -1);\n            List<User> list = userMapper.selectAll(pageRowBounds);\n            assertEquals(183, list.size());\n\n            //pageSize<0的时候同上\n            list = userMapper.selectAll(new PageRowBounds(0, -100));\n            assertEquals(183, list.size());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    class IdBean {\n        private Integer id;\n\n        public Integer getId() {\n            return id;\n        }\n\n        public void setId(Integer id) {\n            this.id = id;\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/rowbounds/test/RowBoundsTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.rowbounds.test;\n\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.rowbounds.RowBoundsHelper;\nimport org.apache.ibatis.session.RowBounds;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class RowBoundsTest {\n\n    /**\n     * 使用Mapper接口调用时，对接口增加RowBounds参数，不需要修改对应的xml配置（或注解配置）\n     * <p/>\n     * RowBounds方式不进行count查询，可以通过修改Page代码实现\n     * <p/>\n     * 这种情况下如果同时使用startPage方法，以startPage为准\n     */\n    @Test\n    public void testMapperWithRowBounds() {\n        SqlSession sqlSession = RowBoundsHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            List<User> list = userMapper.selectAll(new RowBounds(0, 10));\n            //新增PageInfo对象，对返回结果进行封装\n            assertEquals(10, list.size());\n            //判断查询结果的位置是否正确\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.get(list.size() - 1).getId());\n\n\n            //获取第10页，10条内容，显式查询总数count\n            list = userMapper.selectAll(new RowBounds(90, 10));\n            assertEquals(10, list.size());\n            //判断查询结果的位置是否正确\n            assertEquals(91, list.get(0).getId());\n            assertEquals(100, list.get(list.size() - 1).getId());\n\n\n            //获取第3页，20条内容，默认查询总数count\n            list = userMapper.selectAll(new RowBounds(100, 20));\n            assertEquals(20, list.size());\n            //判断查询结果的位置是否正确\n            assertEquals(101, list.get(0).getId());\n            assertEquals(120, list.get(list.size() - 1).getId());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用命名空间方式的RowBounds进行分页，使用RowBounds时不进行count查询\n     * 通过修改代码可以进行count查询，没法通过其他方法改变参数\n     * 因为如果通过调用一个别的方法来标记count查询，还不如直接startPage\n     * <p/>\n     * 同时使用startPage时，以startPage为准，会根据startPage参数来查询\n     */\n    @Test\n    public void testNamespaceWithRowBounds() {\n        SqlSession sqlSession = RowBoundsHelper.getSqlSession();\n        try {\n            //获取从0开始，10条内容\n            List<User> list = sqlSession.selectList(\"selectAll\", null, new RowBounds(0, 10));\n            assertEquals(10, list.size());\n            //判断查询结果的位置是否正确\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.get(list.size() - 1).getId());\n\n\n            //获取从10开始，10条内容\n            list = sqlSession.selectList(\"selectAll\", null, new RowBounds(90, 10));\n            assertEquals(10, list.size());\n            //判断查询结果的位置是否正确\n            assertEquals(91, list.get(0).getId());\n            assertEquals(100, list.get(list.size() - 1).getId());\n\n\n            //获取从20开始，20条内容\n            list = sqlSession.selectList(\"selectAll\", null, new RowBounds(100, 20));\n            assertEquals(20, list.size());\n            //判断查询结果的位置是否正确\n            assertEquals(101, list.get(0).getId());\n            assertEquals(120, list.get(list.size() - 1).getId());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void testNamespaceWithRowBounds2() {\n        SqlSession sqlSession = RowBoundsHelper.getSqlSession();\n        try {\n            //获取从0开始，10条内容\n            List<User> list = sqlSession.selectList(\"selectIf\", null, new RowBounds(0, 10));\n            assertEquals(10, list.size());\n            //判断查询结果的位置是否正确\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.get(list.size() - 1).getId());\n\n            Map<String, Object> map = new HashMap<String, Object>();\n            map.put(\"id\", 10);\n            //获取从10开始，10条内容\n            list = sqlSession.selectList(\"selectIf\", map, new RowBounds(90, 10));\n            assertEquals(10, list.size());\n            //判断查询结果的位置是否正确\n            assertEquals(101, list.get(0).getId());\n            assertEquals(110, list.get(list.size() - 1).getId());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testWithRowboundsAndCountTrue() {\n        SqlSession sqlSession = RowBoundsHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //limit=0,这时候相当于用分页插件求count,但是前提必须是配置rounbounds方式求count，否则都是-1\n            //这里由于没有配置，应该都是-1\n            List<User> list = userMapper.selectAll(new RowBounds(0, -1));\n            assertEquals(183, list.size());\n\n            //pageSize<0的时候同上\n            list = userMapper.selectAll(new RowBounds(0, -100));\n            assertEquals(183, list.size());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    class IdBean {\n        private Integer id;\n\n        public Integer getId() {\n            return id;\n        }\n\n        public void setId(Integer id) {\n            this.id = id;\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/sql/DefaultOrderBySqlParserTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.sql;\n\nimport com.github.pagehelper.parser.OrderBySqlParser;\nimport com.github.pagehelper.parser.defaults.DefaultOrderBySqlParser;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class DefaultOrderBySqlParserTest {\n    private OrderBySqlParser orderBySqlParser = new DefaultOrderBySqlParser();\n\n    @Test\n    public void testOrderBy() {\n        String sql = orderBySqlParser.converToOrderBySql(\"select * from user where length(name) > 0 order by id desc\", \"name desc\");\n        Assert.assertEquals(\"SELECT * FROM user WHERE length(name) > 0 order by name desc\", sql);\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/sql/SqlServerTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.sql;\n\nimport com.github.pagehelper.dialect.ReplaceSql;\nimport com.github.pagehelper.dialect.replace.RegexWithNolockReplaceSql;\nimport com.github.pagehelper.parser.CountSqlParser;\nimport com.github.pagehelper.parser.SqlServerSqlParser;\nimport com.github.pagehelper.parser.defaults.DefaultCountSqlParser;\nimport com.github.pagehelper.parser.defaults.DefaultSqlServerSqlParser;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * @author liuzh\n */\npublic class SqlServerTest {\n    public static final SqlServerSqlParser sqlServer = new DefaultSqlServerSqlParser();\n    CountSqlParser countSqlParser = new DefaultCountSqlParser();\n\n    @Test\n    public void testSqlTestWithlock() {\n        String originalSql = \"select * from Agency with (NOLOCK) where status=0 order by CreateTime\";\n        Assert.assertEquals(\"SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY CreateTime) PAGE_ROW_NUMBER, * FROM (SELECT * FROM Agency WITH (NOLOCK) WHERE status = 0) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSqlTest() {\n        String originalSql = \"Select * from user o where id > 10 order by id desc , name asc\";\n        Assert.assertEquals(\"SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY id DESC, name ASC) PAGE_ROW_NUMBER, * FROM (SELECT * FROM user o WHERE id > 10) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSqlAlias() {\n        String originalSql = \"Select o.* from user o where id > 10 order by id desc , name asc\";\n        Assert.assertEquals(\"SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY id DESC, name ASC) PAGE_ROW_NUMBER, * FROM (SELECT o.* FROM user o WHERE id > 10) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSqlOrderByAlias() {\n        String originalSql = \"select py code from user order by code\";\n        Assert.assertEquals(\"SELECT TOP 10 code FROM (SELECT ROW_NUMBER() OVER (ORDER BY code) PAGE_ROW_NUMBER, code FROM (SELECT py code FROM user) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSqlDistinct() {\n        String originalSql = \"select distinct py,name from user order by py\";\n        Assert.assertEquals(\"SELECT TOP 10 py, name FROM (SELECT ROW_NUMBER() OVER (ORDER BY py) PAGE_ROW_NUMBER, py, name FROM (SELECT DISTINCT py, name FROM user) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSqlTableAll() {\n        String originalSql = \"Select user.* from user where id > 10 order by id desc , name asc\";\n        Assert.assertEquals(\"SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY id DESC, name ASC) PAGE_ROW_NUMBER, * FROM (SELECT user.* FROM user WHERE id > 10) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSqlAs() {\n        String originalSql = \"Select id as id,name name,py as code from user o where id > 10 order by id desc , name asc\";\n        Assert.assertEquals(\"SELECT TOP 10 id, name, code FROM (SELECT ROW_NUMBER() OVER (ORDER BY id DESC, name ASC) PAGE_ROW_NUMBER, id, name, code FROM (SELECT id AS id, name name, py AS code FROM user o WHERE id > 10) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSelectParameter() {\n        //TODO 这种情况会增加?的个数，需要实际在Mybatis中测试\n        String originalSql = \"Select id as id,? name,? from user o where id > 10 order by id desc , name asc\";\n        Assert.assertEquals(\"SELECT TOP 10 id, name, ? FROM (SELECT ROW_NUMBER() OVER (ORDER BY id DESC, name ASC) PAGE_ROW_NUMBER, id, name, ? FROM (SELECT id AS id, ? name, ? FROM user o WHERE id > 10) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSqlWith() {\n        String originalSql = \"with cr as \" +\n                \" (select id \" +\n                \"    from user \" +\n                \"   where id > 100 \" +\n                \"     and id < 120) \" +\n                \"select id, name, py \" +\n                \"  from user \" +\n                \" where id in (select * from cr) order by id\";\n        Assert.assertEquals(\"WITH cr AS (SELECT id FROM user WHERE id > 100 AND id < 120) SELECT TOP 10 id, name, py FROM (SELECT ROW_NUMBER() OVER (ORDER BY id) PAGE_ROW_NUMBER, id, name, py FROM (SELECT id, name, py FROM user WHERE id IN (SELECT * FROM cr)) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSqlLeftJoin() {\n        String originalSql = \"select * \" +\n                \"  from (select distinct A.USERID, \" +\n                \"                        A.USERCODE, \" +\n                \"                        A.USERNAME, \" +\n                \"                        A.USERPWD, \" +\n                \"                        A.CREATEDATE, \" +\n                \"                        A.UPDATEDATE, \" +\n                \"                        A.USERSTATE, \" +\n                \"                        A.MEMO, \" +\n                \"                        A.USERPHONE, \" +\n                \"                        A.USEREMAIL, \" +\n                \"                        A.IDCARD, \" +\n                \"                        D.DEPTNAME, \" +\n                \"                        D.DEPTID \" +\n                \"          from BASE_SYS_USER A \" +\n                \"          left JOIN BASE_SYS_ROLE_USER_REL B \" +\n                \"            ON A.USERID = B.USERID \" +\n                \"          left JOIN BASE_SYS_ROLE C \" +\n                \"            on C.ROLEID = B.ROLEID \" +\n                \"          left join BASE_SYS_DEPT_USER_REL REL \" +\n                \"            on REL.USERID = A.USERID \" +\n                \"          left join BASE_SYS_DEPT D \" +\n                \"            on D.DEPTID = REL.DEPTID \" +\n                \"         where 1 = 1 \" +\n                \"           and C.ROLEID = ? \" +\n                \"           and D.DEPTID = ? \" +\n                \"           and A.USERNAME LIKE '%heh%' \" +\n                \"           and A.USERSTATE = ? \" +\n                \"         ) A Order by A.createDate desc\";\n        Assert.assertEquals(\"SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY createDate DESC) PAGE_ROW_NUMBER, * FROM (SELECT * FROM (SELECT DISTINCT A.USERID, A.USERCODE, A.USERNAME, A.USERPWD, A.CREATEDATE, A.UPDATEDATE, A.USERSTATE, A.MEMO, A.USERPHONE, A.USEREMAIL, A.IDCARD, D.DEPTNAME, D.DEPTID FROM BASE_SYS_USER A LEFT JOIN BASE_SYS_ROLE_USER_REL B ON A.USERID = B.USERID LEFT JOIN BASE_SYS_ROLE C ON C.ROLEID = B.ROLEID LEFT JOIN BASE_SYS_DEPT_USER_REL REL ON REL.USERID = A.USERID LEFT JOIN BASE_SYS_DEPT D ON D.DEPTID = REL.DEPTID WHERE 1 = 1 AND C.ROLEID = ? AND D.DEPTID = ? AND A.USERNAME LIKE '%heh%' AND A.USERSTATE = ?) A) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSqlUnion() {\n        String originalSql = \"select name,py code from user where id >170 \" +\n                \"union all \" +\n                \"select name,py code from user where id < 10 order by code\";\n        Assert.assertEquals(\"SELECT TOP 10 name, code FROM (SELECT ROW_NUMBER() OVER (ORDER BY code) PAGE_ROW_NUMBER, name, code FROM (SELECT name, code FROM (SELECT name, py code FROM user WHERE id > 170 UNION ALL SELECT name, py code FROM user WHERE id < 10) AS WRAP_OUTER_TABLE) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSqlUnion2() {\n        String originalSql = \"select name,code from ( \" +\n                \"\\tselect name,py code from user where id >170 \" +\n                \"\\tunion all \" +\n                \"\\tselect name,py code from user where id < 10 \" +\n                \") as temp \" +\n                \"order by code\";\n        Assert.assertEquals(\"SELECT TOP 10 name, code FROM (SELECT ROW_NUMBER() OVER (ORDER BY code) PAGE_ROW_NUMBER, name, code FROM (SELECT name, code FROM (SELECT name, py code FROM user WHERE id > 170 UNION ALL SELECT name, py code FROM user WHERE id < 10) AS temp) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSqlOrderByFunctionAlias() {\n        String originalSql = \"select py code, func() func_alias from user order by func()\";\n        Assert.assertEquals(\"SELECT TOP 10 code, func_alias FROM (SELECT ROW_NUMBER() OVER (ORDER BY func_alias) PAGE_ROW_NUMBER, code, func_alias FROM (SELECT py code, func() func_alias FROM user) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSqlOrderByUnknown() {\n        String originalSql = \"select name from user order by py\";\n        Assert.assertEquals(\"SELECT TOP 10 name FROM (SELECT ROW_NUMBER() OVER (ORDER BY ROW_ALIAS_1) PAGE_ROW_NUMBER, name FROM (SELECT name, py AS ROW_ALIAS_1 FROM user) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSqlOrderByTable() {\n        String originalSql = \"select t.py, t.name from user t order by t.py\";\n        Assert.assertEquals(\"SELECT TOP 10 py, name FROM (SELECT ROW_NUMBER() OVER (ORDER BY py) PAGE_ROW_NUMBER, py, name FROM (SELECT t.py, t.name FROM user t) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSqlStar() {\n        String originalSql = \"select t.*, 1 alias from user t order by t.py\";\n        Assert.assertEquals(\"SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY py) PAGE_ROW_NUMBER, * FROM (SELECT t.*, 1 alias FROM user t) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    /**\n     * JSqlParser的4.4版本对于 UR RS RR CS 作为别名解析错误\n     * 故将UR更改为SUR\n     * <p>\n     * 详见：https://github.com/JSQLParser/JSqlParser/issues/1520\n     */\n    @Test\n    public void testSql377() {\n        String originalSql = \"select distinct u.user_id, u.dept_id, u.login_name, u.user_name, u.email, u.phonenumber, u.status, u.create_time from sys_user u left join sys_dept d on u.dept_id = d.dept_id left join sys_user_role sur on u.user_id = sur.user_id left join sys_role r on r.role_id = sur.role_id where u.del_flag = '0' and (r.role_id != 1 or r.role_id IS NULL) and u.user_id not in (select u.user_id from sys_user u inner join sys_user_role sur on u.user_id = sur.user_id and sur.role_id = 1)\";\n        Assert.assertEquals(\"SELECT TOP 10 user_id, dept_id, login_name, user_name, email, phonenumber, status, create_time FROM (SELECT ROW_NUMBER() OVER (ORDER BY RAND()) PAGE_ROW_NUMBER, user_id, dept_id, login_name, user_name, email, phonenumber, status, create_time FROM (SELECT DISTINCT u.user_id, u.dept_id, u.login_name, u.user_name, u.email, u.phonenumber, u.status, u.create_time FROM sys_user u LEFT JOIN sys_dept d ON u.dept_id = d.dept_id LEFT JOIN sys_user_role sur ON u.user_id = sur.user_id LEFT JOIN sys_role r ON r.role_id = sur.role_id WHERE u.del_flag = '0' AND (r.role_id != 1 OR r.role_id IS NULL) AND u.user_id NOT IN (SELECT u.user_id FROM sys_user u INNER JOIN sys_user_role sur ON u.user_id = sur.user_id AND sur.role_id = 1)) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSql386() {\n        String originalSql = \" select a.Guid,\\n\" +\n                \"               ProManager,\\n\" +\n                \"               WorkOrderType,\\n\" +\n                \"               a.Name,\\n\" +\n                \"               WorkNote,\\n\" +\n                \"               b.Name                             TeamName,\\n\" +\n                \"               ConstructionSite,\\n\" +\n                \"               iif(a.MaterialGuid is null, 0, 1) as IsMaterial,\\n\" +\n                \"               a.MaterialGuid,\\n\" +\n                \"               c.Code                          as MaterialCode,\\n\" +\n                \"               c.FullName                         MaterialName,\\n\" +\n                \"               d.FullName                         MatStdSortName\\n\" +\n                \"        from RMC_WorkOrder a\\n\" +\n                \"                 left join dbo.SYS_OrgFrame b on a.TeamGuid = b.Code and b.ParentGuid is null\\n\" +\n                \"                 left join dbo.BAS_Material c on a.MaterialGuid = c.Guid\\n\" +\n                \"                 left join BAS_MatStdSort d on a.MatStdSortGuid = d.Guid\\n\" +\n                \"        where a.ConfirmUser is null\\n\" +\n                \"          and b.Guid = 1\\n\" +\n                \"        order by a.ContractBillNO desc\";\n        Assert.assertEquals(\"SELECT TOP 10 Guid, ProManager, WorkOrderType, Name, WorkNote, TeamName, ConstructionSite, IsMaterial, MaterialGuid, MaterialCode, MaterialName, MatStdSortName FROM (SELECT ROW_NUMBER() OVER (ORDER BY ROW_ALIAS_1 DESC) PAGE_ROW_NUMBER, Guid, ProManager, WorkOrderType, Name, WorkNote, TeamName, ConstructionSite, IsMaterial, MaterialGuid, MaterialCode, MaterialName, MatStdSortName FROM (SELECT a.Guid, ProManager, WorkOrderType, a.Name, WorkNote, b.Name TeamName, ConstructionSite, iif(a.MaterialGuid IS NULL, 0, 1) AS IsMaterial, a.MaterialGuid, c.Code AS MaterialCode, c.FullName MaterialName, d.FullName MatStdSortName, a.ContractBillNO AS ROW_ALIAS_1 FROM RMC_WorkOrder a LEFT JOIN dbo.SYS_OrgFrame b ON a.TeamGuid = b.Code AND b.ParentGuid IS NULL LEFT JOIN dbo.BAS_Material c ON a.MaterialGuid = c.Guid LEFT JOIN BAS_MatStdSort d ON a.MatStdSortGuid = d.Guid WHERE a.ConfirmUser IS NULL AND b.Guid = 1) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n\n    @Test\n    public void testSql354() {\n        String originalSql = \"SELECT ISNULL(tb.a, '') from table tb\";\n        Assert.assertEquals(\"SELECT TOP 10 ISNULL(tb.a, '') FROM (SELECT ROW_NUMBER() OVER (ORDER BY RAND()) PAGE_ROW_NUMBER, ISNULL(tb.a, '') FROM (SELECT ISNULL(tb.a, '') FROM table tb) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSql374() {\n        String originalSql = \"select * from table_a order by id\";\n        Assert.assertEquals(\"SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY id) PAGE_ROW_NUMBER, * FROM (SELECT * FROM table_a) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                sqlServer.convertToPageSql(originalSql, 1, 10));\n    }\n\n    @Test\n    public void testSql345() {\n        String originalSql = \"Select CC.ClinicID, CC.CaseHistoryNum, CC.CaseHistoryID, CC.DoctorID, CC.ClientRegisterID\\n\" +\n                \"From Client CC With(Nolock)\\n\" +\n                \"Left Outer Join Register CR With(Nolock) On CC.ClientRegisterID = CR.ClientRegisterID\\n\" +\n                \"Where CC.ClientID = 14374\";\n        ReplaceSql replaceSql = new RegexWithNolockReplaceSql();\n        String replace = replaceSql.replace(originalSql);\n        String pageSql = sqlServer.convertToPageSql(replace, 1, 10);\n        String result = replaceSql.restore(pageSql);\n        Assert.assertEquals(\"SELECT TOP 10 ClinicID, CaseHistoryNum, CaseHistoryID, DoctorID, ClientRegisterID FROM (SELECT ROW_NUMBER() OVER (ORDER BY RAND()) PAGE_ROW_NUMBER, ClinicID, CaseHistoryNum, CaseHistoryID, DoctorID, ClientRegisterID FROM (SELECT CC.ClinicID, CC.CaseHistoryNum, CC.CaseHistoryID, CC.DoctorID, CC.ClientRegisterID FROM Client CC WITH(NOLOCK) LEFT OUTER JOIN Register CR WITH(NOLOCK) ON CC.ClientRegisterID = CR.ClientRegisterID WHERE CC.ClientID = 14374) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\", result);\n    }\n\n    @Test\n    public void testSql306() {\n        String originalSql = \"Select * FROM table1 t1 with(nolock)\\n\" +\n                \"left join table2 t2 with(nolock) on t1.id=t2.id\\n\" +\n                \"left join table3 t3 with(nolock) on t1.id=t3.id\";\n        ReplaceSql replaceSql = new RegexWithNolockReplaceSql();\n        String replace = replaceSql.replace(originalSql);\n        String pageSql = sqlServer.convertToPageSql(replace, 1, 10);\n        String result = replaceSql.restore(pageSql);\n        Assert.assertEquals(\"SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY RAND()) PAGE_ROW_NUMBER, * FROM (SELECT * FROM table1 t1 WITH(NOLOCK) LEFT JOIN table2 t2 WITH(NOLOCK) ON t1.id = t2.id LEFT JOIN table3 t3 WITH(NOLOCK) ON t1.id = t3.id) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\", result);\n    }\n\n    @Test\n    public void testSql66() {\n        String originalSql = \"SELECT *\\n\" +\n                \"FROM\\n\" +\n                \"forum_post_info a with(nolock)\\n\" +\n                \"LEFT JOIN forum_carcase_tags as b with(nolock) on a.id = b.carcase_id where b.tag_id = 127\";\n        ReplaceSql replaceSql = new RegexWithNolockReplaceSql();\n        String replace = replaceSql.replace(originalSql);\n        String pageSql = sqlServer.convertToPageSql(replace, 1, 10);\n\n\n        String smartCountSql = countSqlParser.getSmartCountSql(replace);\n        smartCountSql = replaceSql.restore(smartCountSql);\n        Assert.assertEquals(\"SELECT count(0) FROM forum_post_info a WITH(NOLOCK) LEFT JOIN forum_carcase_tags AS b WITH(NOLOCK) ON a.id = b.carcase_id WHERE b.tag_id = 127\",\n                smartCountSql);\n\n\n        String result = replaceSql.restore(pageSql);\n        Assert.assertEquals(\"SELECT TOP 10 * FROM (SELECT ROW_NUMBER() OVER (ORDER BY RAND()) PAGE_ROW_NUMBER, * FROM (SELECT * FROM forum_post_info a WITH(NOLOCK) LEFT JOIN forum_carcase_tags AS b WITH(NOLOCK) ON a.id = b.carcase_id WHERE b.tag_id = 127) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                result);\n    }\n\n    @Test\n    public void testSql398() {\n        String originalSql = \"Select AUS.ScheduleID, AUS.SystemID, AUS.ClinicID, AUS.DoctorID, AUS.ScheduleDate, \\n\" +\n                \"\\tAUS.StartTime, AUS.EndTime, AUS.Status, AUS.BookBy, AUS.Note, AUS.Remark, AUS.SourceType, CM.CompanyName,\\n\" +\n                \"\\tAU.UserName As DoctorName, AU.UserNumber As DoctorNumber, CC.CodeDesc As ClinicName, CD.Lat, CD.Lng,\\n\" +\n                \"\\tCD.ContactTel, CD.Address, CR.ConsultationStatusID, CR.RegisterStatus,A1.CodeDesc as AreaLevel1, A2.CodeDesc as AreaLevel2\\n\" +\n                \"\\tFrom ACM_User_Schedule AUS with(nolock)\\n\" +\n                \"\\tLeft Join Client_Register CR with(nolock) On AUS.BookBy=CR.ClientID And CR.SourceType='F' And AUS.ClientRegisterNum=CR.ClientRegisterNum \\n\" +\n                \"\\tInner Join ACM_User AU with(nolock) On AU.UserID = AUS.DoctorID \\n\" +\n                \"\\tInner Join Code_Clinic CC with(nolock) On AUS.ClinicID=CC.CodeID\\n\" +\n                \"\\tInner Join Clinic_Detail CD with(nolock) On CC.CodeID = CD.ClinicID\\n\" +\n                \"\\tInner Join Code_Area A1 with(nolock) On CD.AreaLevel1ID=A1.CodeID\\n\" +\n                \"\\tInner Join Code_Area A2 with(nolock) On CD.AreaLevel2ID=A2.CodeID\\n\" +\n                \"\\tInner Join Company_Master CM with(nolock) On CC.SystemID = CM.SystemID\\n\" +\n                \"\\tWhere BookBy=1\";\n        ReplaceSql replaceSql = new RegexWithNolockReplaceSql();\n        String replace = replaceSql.replace(originalSql);\n        String pageSql = sqlServer.convertToPageSql(replace, 1, 10);\n\n        String smartCountSql = countSqlParser.getSmartCountSql(replace);\n        smartCountSql = replaceSql.restore(smartCountSql);\n        Assert.assertEquals(\"SELECT count(0) FROM ACM_User_Schedule AUS WITH(NOLOCK) LEFT JOIN Client_Register CR WITH(NOLOCK) ON AUS.BookBy = CR.ClientID AND CR.SourceType = 'F' AND AUS.ClientRegisterNum = CR.ClientRegisterNum INNER JOIN ACM_User AU WITH(NOLOCK) ON AU.UserID = AUS.DoctorID INNER JOIN Code_Clinic CC WITH(NOLOCK) ON AUS.ClinicID = CC.CodeID INNER JOIN Clinic_Detail CD WITH(NOLOCK) ON CC.CodeID = CD.ClinicID INNER JOIN Code_Area A1 WITH(NOLOCK) ON CD.AreaLevel1ID = A1.CodeID INNER JOIN Code_Area A2 WITH(NOLOCK) ON CD.AreaLevel2ID = A2.CodeID INNER JOIN Company_Master CM WITH(NOLOCK) ON CC.SystemID = CM.SystemID WHERE BookBy = 1\",\n                smartCountSql);\n\n\n        String result = replaceSql.restore(pageSql);\n        Assert.assertEquals(\"SELECT TOP 10 ScheduleID, SystemID, ClinicID, DoctorID, ScheduleDate, StartTime, EndTime, Status, BookBy, Note, Remark, SourceType, CompanyName, DoctorName, DoctorNumber, ClinicName, Lat, Lng, ContactTel, Address, ConsultationStatusID, RegisterStatus, AreaLevel1, AreaLevel2 FROM (SELECT ROW_NUMBER() OVER (ORDER BY RAND()) PAGE_ROW_NUMBER, ScheduleID, SystemID, ClinicID, DoctorID, ScheduleDate, StartTime, EndTime, Status, BookBy, Note, Remark, SourceType, CompanyName, DoctorName, DoctorNumber, ClinicName, Lat, Lng, ContactTel, Address, ConsultationStatusID, RegisterStatus, AreaLevel1, AreaLevel2 FROM (SELECT AUS.ScheduleID, AUS.SystemID, AUS.ClinicID, AUS.DoctorID, AUS.ScheduleDate, AUS.StartTime, AUS.EndTime, AUS.Status, AUS.BookBy, AUS.Note, AUS.Remark, AUS.SourceType, CM.CompanyName, AU.UserName AS DoctorName, AU.UserNumber AS DoctorNumber, CC.CodeDesc AS ClinicName, CD.Lat, CD.Lng, CD.ContactTel, CD.Address, CR.ConsultationStatusID, CR.RegisterStatus, A1.CodeDesc AS AreaLevel1, A2.CodeDesc AS AreaLevel2 FROM ACM_User_Schedule AUS WITH(NOLOCK) LEFT JOIN Client_Register CR WITH(NOLOCK) ON AUS.BookBy = CR.ClientID AND CR.SourceType = 'F' AND AUS.ClientRegisterNum = CR.ClientRegisterNum INNER JOIN ACM_User AU WITH(NOLOCK) ON AU.UserID = AUS.DoctorID INNER JOIN Code_Clinic CC WITH(NOLOCK) ON AUS.ClinicID = CC.CodeID INNER JOIN Clinic_Detail CD WITH(NOLOCK) ON CC.CodeID = CD.ClinicID INNER JOIN Code_Area A1 WITH(NOLOCK) ON CD.AreaLevel1ID = A1.CodeID INNER JOIN Code_Area A2 WITH(NOLOCK) ON CD.AreaLevel2ID = A2.CodeID INNER JOIN Company_Master CM WITH(NOLOCK) ON CC.SystemID = CM.SystemID WHERE BookBy = 1) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                result);\n    }\n\n    @Test\n    public void testSqlServerSquareBrackets() {\n        String originalSql = \"SELECT [ID] AS [ComsnCountID] FROM B_ComsnCount;\";\n        String pageSql = sqlServer.convertToPageSql(originalSql, 1, 20);\n\n        Assert.assertEquals(\"SELECT TOP 20 [ComsnCountID] FROM (SELECT ROW_NUMBER() OVER (ORDER BY RAND()) PAGE_ROW_NUMBER, [ComsnCountID] FROM (SELECT [ID] AS [ComsnCountID] FROM B_ComsnCount) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                pageSql);\n    }\n\n    @Test\n    public void testSqlServer768() {\n        String originalSql = \"SELECT column1, column2, column3 from table1 \\n\" +\n                \"UNION \\n\" +\n                \"SELECT column1, column2, column3 from table2 \\n\" +\n                \"UNION \\n\" +\n                \"SELECT column1, column2, column3 from table3 \\n\" +\n                \"ORDER BY column1, column2\";\n        String pageSql = sqlServer.convertToPageSql(originalSql, 1, 20);\n\n        Assert.assertEquals(\"SELECT TOP 20 column1, column2, column3 FROM (SELECT ROW_NUMBER() OVER (ORDER BY column1, column2) PAGE_ROW_NUMBER, column1, column2, column3 FROM (SELECT column1, column2, column3 FROM (SELECT column1, column2, column3 FROM table1 UNION SELECT column1, column2, column3 FROM table2 UNION SELECT column1, column2, column3 FROM table3) AS WRAP_OUTER_TABLE) AS PAGE_TABLE_ALIAS) AS PAGE_TABLE_ALIAS WHERE PAGE_ROW_NUMBER > 1 ORDER BY PAGE_ROW_NUMBER\",\n                pageSql);\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/sql/SqlTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.sql;\n\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.parser.CountSqlParser;\nimport com.github.pagehelper.parser.SqlParserUtil;\nimport com.github.pagehelper.parser.defaults.DefaultCountSqlParser;\nimport net.sf.jsqlparser.statement.Statement;\nimport net.sf.jsqlparser.statement.select.Select;\nimport org.junit.Assert;\nimport org.junit.Test;\n\n/**\n * @author liuzh\n */\npublic class SqlTest {\n\n    CountSqlParser countSqlParser = new DefaultCountSqlParser();\n    @Test\n    public void testSqlParser() {\n\n        Assert.assertEquals(\"WITH AA AS (SELECT 1 FROM A1), BB AS (SELECT 1 FROM B2), AB AS (SELECT * FROM AA UNION ALL SELECT * FROM BB) SELECT count(0) FROM AB\",\n                countSqlParser.getSmartCountSql(\"WITH AA AS (SELECT 1 FROM A1), BB AS (SELECT 1 FROM B2), AB AS (SELECT * FROM AA UNION ALL SELECT * FROM BB) SELECT * FROM AB\"));\n\n        Assert.assertEquals(\"WITH cr AS (SELECT UserRegionCode FROM person.UserRegion WHERE Name LIKE 'C%') SELECT count(0) FROM person.StateProvince WHERE UserRegionCode IN (SELECT * FROM cr)\",\n                countSqlParser.getSmartCountSql(\"with \" +\n                        \"cr as \" +\n                        \"( \" +\n                        \"    select UserRegionCode from person.UserRegion where Name like 'C%' order by name\" +\n                        \") \" +\n                        \" \" +\n                        \"select * from person.StateProvince where UserRegionCode in (select * from cr)\"));\n\n        Assert.assertEquals(\"WITH cr AS (SELECT aaz093 FROM aa10 WHERE aaa100 LIKE 'AAB05%') SELECT count(0) FROM (SELECT count(1) FROM aa10 WHERE aaz093 IN (SELECT * FROM cr)) table_count\",\n                countSqlParser.getSmartCountSql(\"with cr as \" +\n                        \" (select aaz093 from aa10 where aaa100 like 'AAB05%' order by aaz093 desc) \" +\n                        \"select count(1) from aa10 where aaz093 in (select * from cr)\"));\n\n\n        Assert.assertEquals(\"SELECT count(0) FROM ac02 a LEFT JOIN aa10 b ON b.aaa100 = 'AAC031' AND b.aaa102 = a.aac031\",\n                countSqlParser.getSmartCountSql(\"select a.aac001,a.aac030,b.aaa103 \" +\n                        \"  from ac02 a \" +\n                        \"  left join aa10 b \" +\n                        \"    on b.aaa100 = 'AAC031' \" +\n                        \"   and b.aaa102 = a.aac031 \" +\n                        \"   order by a.aac001\"));\n\n        Assert.assertEquals(\"SELECT count(0) FROM (SELECT * FROM aa10 WHERE aaa100 LIKE 'AAB05%' UNION SELECT * FROM aa10 WHERE aaa100 = 'AAC031') table_count\",\n                countSqlParser.getSmartCountSql(\"select * from aa10 WHERE aaa100 LIKE 'AAB05%' \" +\n                        \"union \" +\n                        \"select * from aa10 where aaa100 = 'AAC031'\"));\n\n        Assert.assertEquals(\"SELECT count(0) FROM (SELECT * FROM aa10 WHERE aaa100 LIKE 'AAB05%' UNION SELECT * FROM aa10 WHERE aaa100 = 'AAC031')\",\n                countSqlParser.getSmartCountSql(\"select * from (select * from aa10 WHERE aaa100 LIKE 'AAB05%' \" +\n                        \"union \" +\n                        \"select * from aa10 where aaa100 = 'AAC031')\"));\n\n        Assert.assertEquals(\"SELECT count(0) FROM (SELECT so.id, so.address, so.area_code, so.area_id, so.del_flag, so.email, so.fax, so.grade, so.icon, so.master, so.name, so.parent_id, so.parent_ids, so.phone, so.remarks, so.type, so.zip_code FROM sys_organization so LEFT JOIN sys_user_organization suo ON (suo.org_id = so.id OR FIND_IN_SET(suo.org_id, so.parent_ids)) WHERE suo.user_id = ? GROUP BY so.id LIMIT ?) table_count\",\n                countSqlParser.getSmartCountSql(\"select so.id,so.address,so.area_code,so.area_id,so.del_flag,so.email,so.fax,so.grade,so.icon,so.master, so.name,so.parent_id,so.parent_ids,so.phone,so.remarks,so.type,so.zip_code from sys_organization so LEFT JOIN sys_user_organization suo ON (suo.org_id = so.id or FIND_IN_SET(suo.org_id,so.parent_ids)) where suo.user_id = ? group by so.id LIMIT ? \"));\n\n        Assert.assertEquals(\"SELECT count(0) FROM xx1 LEFT JOIN xx2 ON xx1.id = xx2.user_id WHERE 1 = 1 AND xx1.`name` LIKE \\\"%ll%\\\" AND xx1.status = 1 AND (xx2.`type` = 1)\",\n                countSqlParser.getSmartCountSql(\"select xx,xx,xx from xx1 left join xx2 on xx1.id=xx2.user_id where 1=1 and xx1.`name` like \\\"%ll%\\\" and  xx1.status = 1 and (xx2.`type` = 1) order by xx1.number asc\"));\n    }\n\n\n    @Test\n    public void testSqlParser11() {\n        Assert.assertEquals(\"SELECT count(0) FROM (SELECT so.id, so.address, so.area_code, so.area_id, so.del_flag, so.email, so.fax, so.grade, so.icon, so.master, so.name, so.parent_id, so.parent_ids, so.phone, so.remarks, so.type, so.zip_code FROM sys_organization so LEFT JOIN sys_user_organization suo ON (suo.org_id = so.id OR FIND_IN_SET(suo.org_id, so.parent_ids)) WHERE suo.user_id = ? GROUP BY so.id LIMIT ?) table_count\",\n                countSqlParser.getSmartCountSql(\n                        \"select so.id,so.address,so.area_code,so.area_id,so.del_flag,so.email,\" +\n                                \"so.fax,so.grade,so.icon,so.master, so.name,so.parent_id,so.parent_ids,\" +\n                                \"so.phone,so.remarks,so.type,so.zip_code \" +\n                                \"from sys_organization so \" +\n                                \"LEFT JOIN sys_user_organization suo ON (suo.org_id = so.id or FIND_IN_SET(suo.org_id,so.parent_ids)) \" +\n                                \"where suo.user_id = ? group by so.id LIMIT ? \"));\n\n        Assert.assertEquals(\"SELECT count(0) FROM sys_organization so LEFT JOIN sys_user_organization suo ON (suo.org_id = so.id OR FIND_IN_SET(suo.org_id, so.parent_ids)) WHERE suo.user_id = ?\",\n                countSqlParser.getSmartCountSql(\n                        \"select so.id,so.address,so.area_code,so.area_id,so.del_flag,so.email,\" +\n                                \"so.fax,so.grade,so.icon,so.master, so.name,so.parent_id,so.parent_ids,\" +\n                                \"so.phone,so.remarks,so.type,so.zip_code \" +\n                                \"from sys_organization so \" +\n                                \"LEFT JOIN sys_user_organization suo ON (suo.org_id = so.id or FIND_IN_SET(suo.org_id,so.parent_ids)) \" +\n                                \"where suo.user_id = ?\"));\n    }\n\n    @Test\n    public void testSqlParser2() {\n        Assert.assertEquals(\"SELECT count(0) FROM (SELECT name, count(id) FROM user GROUP BY name) table_count\",\n                countSqlParser.getSmartCountSql(\"select name,count(id) from user group by name\"));\n    }\n\n\n    @Test\n    public void testSqlParser3() {\n        Assert.assertEquals(\"select count(0) from ( \\n\" +\n                        \"SELECT *\\n\" +\n                        \"    FROM vwdatasearch\\n\" +\n                        \"    WHERE ComId = ?\\n\" +\n                        \"    AND (\\n\" +\n                        \"      Title1 %% ?\\n\" +\n                        \"    )\\n\" +\n                        \"\\n\" +\n                        \" ) tmp_count\",\n                countSqlParser.getSmartCountSql(\"SELECT *\\n\" +\n                        \"    FROM vwdatasearch\\n\" +\n                        \"    WHERE ComId = ?\\n\" +\n                        \"    AND (\\n\" +\n                        \"      Title1 %% ?\\n\" +\n                        \"    )\\n\"));\n    }\n\n    @Test\n    public void testSqlParser4() {\n        String sql = countSqlParser.getSmartCountSql(\"/* test */select name,count(id) from user group by name\");\n        Assert.assertEquals(\"/* test */SELECT count(0) FROM (SELECT name, count(id) FROM user GROUP BY name) table_count\",\n                sql);\n    }\n\n    @Test\n    public void testWithNolock() {\n        String sql = \"SELECT * FROM A WITH(NOLOCK) INNER JOIN B WITH(NOLOCK) ON A.TypeId = B.Id\";\n        sql = sql.replaceAll(\"((?i)\\\\s*(\\\\w?)\\\\s*with\\\\s*\\\\(nolock\\\\))\", \" $2_PAGEWITHNOLOCK\");\n        //解析SQL\n        Statement stmt = SqlParserUtil.parse(sql);\n        Select select = (Select) stmt;\n        sql = select.toString();\n\n        sql = sql.replaceAll(\"\\\\s*(\\\\w*?)_PAGEWITHNOLOCK\", \" $1 WITH(NOLOCK)\");\n        Assert.assertEquals(\"SELECT * FROM A WITH(NOLOCK) INNER JOIN B WITH(NOLOCK) ON A.TypeId = B.Id\", sql);\n    }\n\n    @Test\n    public void testSql375() {\n        Assert.assertEquals(\"SELECT count(0) FROM tbl\", countSqlParser.getSmartCountSql(\"SELECT IF(score >= 60, 'pass', 'failed') FROM tbl\"));\n    }\n\n    @Test\n    public void testSql350() {\n        Assert.assertEquals(\"select count(0) from ( \\n\" +\n                \"select a,b,c from tb_test having a not null\\n\" +\n                \" ) tmp_count\", countSqlParser.getSmartCountSql(\"select a,b,c from tb_test having a not null\"));\n    }\n\n    @Test\n    public void testSql555() {\n        Assert.assertEquals(\"SELECT count(0) FROM (SELECT (a.column1 + a.column2) AS popCount FROM peaf_staff AS a ORDER BY FIELD(a.`store_id`, ?, ?), popCount DESC) table_count\",\n                countSqlParser.getSmartCountSql(\"SELECT (a.column1+a.column2) as popCount  FROM peaf_staff AS a ORDER BY FIELD(a.`store_id`, ?, ?), popCount DESC\\n\"));\n    }\n\n    @Test\n    public void testSql606() {\n        Assert.assertEquals(\"SELECT count(0) FROM (SELECT (SELECT COUNT(1) FROM test1 WHERE test1.id = test.test1_id) AS successCount, (SELECT COUNT(1) FROM test1) AS Total FROM test HAVING successCount = Total) table_count\",\n                countSqlParser.getSmartCountSql(\"select\\n\" +\n                        \"(SELECT COUNT(1) FROM test1 WHERE test1.id = test.test1_id )as successCount ,\\n\" +\n                        \"(SELECT COUNT(1) FROM test1 ) as Total\\n\" +\n                        \"from test\\n\" +\n                        \"Having successCount = Total\"));\n    }\n\n    @Test\n    public void testSql201() {\n        Assert.assertEquals(\"SELECT count(0) FROM BASE_PARENT bp LEFT JOIN (BASE_STUDENT bs, BASE_PARENT_STUDENT bst) ON (bp.ID = bst.PARENT_ID AND bs.ID = bst.STUDENT_ID) WHERE 1 = 1\",\n                countSqlParser.getSmartCountSql(\"SELECT bp.ID, bp.NAME, bp.PHONE, bp.IDCODE, bp.CREDENTIALS_PIC, bp.ROLE, bs.ID child_id, bs.NAME child_name \" +\n                        \"FROM BASE_PARENT bp \" +\n                        \"LEFT JOIN (BASE_STUDENT bs ,BASE_PARENT_STUDENT bst) ON (bp.ID = bst.PARENT_ID AND bs.ID = bst.STUDENT_ID) \" +\n                        \"WHERE 1 = 1\"));\n    }\n\n    @Test\n    public void testSql545() {\n        Assert.assertEquals(\"SELECT count(0) FROM user_info\",\n                countSqlParser.getSmartCountSql(\" select * from user_info order by [ ]\"));\n    }\n\n    @Test\n    public void testKeepOrderBy() {\n        try {\n            PageHelper.startPage(1, 10).keepOrderBy(true);\n            Assert.assertEquals(\"select count(0) from ( \\n\" +\n                            \" select * from user_info order by name desc\\n\" +\n                            \" ) tmp_count\",\n                    countSqlParser.getSmartCountSql(\" select * from user_info order by name desc\"));\n        } finally {\n            PageHelper.clearPage();\n        }\n        try {\n            PageHelper.startPage(1, 10).keepSubSelectOrderBy(true);\n            Assert.assertEquals(\"SELECT count(0) FROM (SELECT id, name FROM user_info ORDER BY name DESC) temp\",\n                    countSqlParser.getSmartCountSql(\"select * from (select id, name from user_info order by name desc) temp order by id\"));\n        } finally {\n            PageHelper.clearPage();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/ArgumentsMapTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class ArgumentsMapTest {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testArgumentsMap() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            List<User> list = userMapper.selectByPageNumSizeOrderBy(1, 10, \"id desc\");\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n            list = userMapper.selectByPageNumSize(2, 10);\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n\n            list = userMapper.selectByPageNumSize(3, 20);\n            assertEquals(20, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/ArgumentsObjTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.model.UserQueryModel;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class ArgumentsObjTest {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testArgumentsObj() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            UserQueryModel queryModel = new UserQueryModel();\n            queryModel.setPageNum(1);\n            queryModel.setPageSize(10);\n            queryModel.setOrderBy(\"id desc\");\n            List<User> list = userMapper.selectByQueryModel(queryModel);\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n\n            queryModel.setPageNum(2);\n            queryModel.setOrderBy(null);\n            list = userMapper.selectByQueryModel(queryModel);\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n\n            queryModel.setPageNum(3);\n            queryModel.setPageSize(20);\n            list = userMapper.selectByQueryModel(queryModel);\n            assertEquals(20, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/AsyncCountTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.dialect.auto.DataSourceAutoDialect;\nimport com.github.pagehelper.dialect.auto.DataSourceNegotiationAutoDialect;\nimport org.apache.ibatis.datasource.unpooled.UnpooledDataSource;\nimport org.apache.ibatis.io.Resources;\nimport org.apache.ibatis.session.SqlSession;\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.apache.ibatis.session.SqlSessionFactoryBuilder;\nimport org.junit.Ignore;\nimport org.junit.Test;\n\nimport java.io.IOException;\nimport java.io.Reader;\n\n@Ignore\npublic class AsyncCountTest {\n    private static SqlSessionFactory sqlSessionFactory;\n\n    static {\n        try {\n            //创建SqlSessionFactory\n            Reader reader = Resources.getResourceAsReader(\"mybatis-config-async-count.xml\");\n            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);\n            reader.close();\n        } catch (IOException e) {\n        }\n        //添加一个针对 unpool 的 AutoDialect\n        DataSourceNegotiationAutoDialect.registerAutoDialect(new DataSourceAutoDialect<UnpooledDataSource>() {\n            @Override\n            public String getJdbcUrl(UnpooledDataSource unpooledDataSource) {\n                return unpooledDataSource.getUrl();\n            }\n        });\n    }\n\n    /**\n     * 获取Session\n     *\n     * @return\n     */\n    public static SqlSession getSqlSession() {\n        return sqlSessionFactory.openSession();\n    }\n\n    /**\n     * 使用命名空间调用时，使用PageHelper.startPage\n     * <p/>\n     * startPage第三个参数可以控制是(true)否(false)执行count查询，使用两个查询的startPage时默认进行count查询\n     * <p/>\n     * 使用startPage方法时，如果同时使用RowBounds，以startPage为准\n     */\n    @Test\n    public void testAsyncCount() {\n        SqlSession sqlSession = getSqlSession();\n        long start = System.currentTimeMillis();\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10).enableAsyncCount().keepOrderBy(true);\n            sqlSession.selectList(\"selectEmployees\");\n            System.out.println(\"异步耗时: \" + (System.currentTimeMillis() - start));\n        } finally {\n            sqlSession.close();\n        }\n\n        sqlSession = getSqlSession();\n        start = System.currentTimeMillis();\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10).keepOrderBy(true);\n            sqlSession.selectList(\"selectEmployees\");\n            System.out.println(\"同步耗时: \" + (System.currentTimeMillis() - start));\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/CloseableTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport java.util.List;\n\npublic class CloseableTest {\n\n    @Test\n    public void testCloseable() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        //下面注释代码只能在jdk7+中进行测试\n        try (Page<Object> ignored = PageHelper.startPage(1, 10)) {\n            int a = 10 / 0;\n            userMapper.selectAll();\n            Assert.fail();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        //上面分页会被清理，这里不会被分页\n        List<User> user = userMapper.selectAll();\n        Assert.assertEquals(183, user.size());\n        sqlSession.close();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/CollectionMapTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class CollectionMapTest {\n\n    @Test\n    public void test() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 5);\n            List<User> list1 = userMapper.selectGreterThanId(1);\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 5);\n            List<User> list2 = userMapper.selectCollectionMap();\n            assertEquals(5, list2.size());\n            assertEquals(183, ((Page<?>) list2).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/CountColumnTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class CountColumnTest {\n\n    @Test\n    public void testMapperWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10).countColumn(\"id\");\n            User user = new User();\n            user.setName(\"刘\");\n            List<User> list = userMapper.selectLike(user);\n            assertEquals(78, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(15, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(2, 10);\n            list = userMapper.selectLike(user);\n            assertEquals(88, list.get(0).getId());\n            assertEquals(5, list.size());\n            assertEquals(15, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test(expected = Exception.class)\n    public void testCountColumnInject() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10).countColumn(\"delete from user\");\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/EnumTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.Code;\nimport com.github.pagehelper.model.UserCode;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport java.util.List;\n\npublic class EnumTest {\n\n    @Test\n    public void testCloseable() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        PageHelper.startPage(1, 2);\n        List<UserCode> userCodes = userMapper.selectByCode(Code.LR);\n        Assert.assertEquals(1, userCodes.size());\n        sqlSession.close();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/IPageTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.IPage;\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.model.UserQueryModel;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class IPageTest {\n\n    @Test\n    public void testIPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            UserIPage queryModel = new UserIPage();\n            queryModel.setPageNum(1);\n            queryModel.setPageSize(10);\n            queryModel.setOrderBy(\"id desc\");\n            List<User> list = userMapper.selectByQueryModel(queryModel);\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n\n            queryModel.setPageNum(2);\n            queryModel.setOrderBy(null);\n            list = userMapper.selectByQueryModel(queryModel);\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n\n            queryModel.setPageNum(null);\n            queryModel.setPageSize(null);\n            queryModel.setOrderBy(\"id asc\");\n            list = userMapper.selectByQueryModel(queryModel);\n            assertEquals(1, list.get(0).getId());\n            assertEquals(183, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    public static class UserIPage extends UserQueryModel implements IPage {\n\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/OffsetTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageInfo;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class OffsetTest {\n    @Test\n    public void testOffset() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            PageHelper.startPage(1, 6);\n            List<User> list = userMapper.selectAll();\n            assertEquals(6, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n\n            PageHelper.offsetPage(6, 20);\n            list = userMapper.selectAll();\n            PageInfo<User> pageInfo = new PageInfo<User>(list);\n            System.out.println(pageInfo.toString());\n            assertEquals(2, ((Page<?>) list).getPageNum());\n            assertEquals(20, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n\n            PageHelper.offsetPage(1, 180);\n            list = userMapper.selectAll();\n            pageInfo = new PageInfo<User>(list);\n            System.out.println(pageInfo.toString());\n            assertEquals(2, ((Page<?>) list).getPageNum());\n            assertEquals(180, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n\n            PageHelper.offsetPage(0, Integer.MAX_VALUE);\n            list = userMapper.selectAll();\n            pageInfo = new PageInfo<User>(list);\n            System.out.println(pageInfo.toString());\n            assertEquals(1, ((Page<?>) list).getPageNum());\n            assertEquals(183, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void testPageNum() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            PageHelper.offsetPage(5, 5);\n            List<User> list = userMapper.selectAll();\n            assertEquals(2, ((Page<?>) list).getPageNum());\n            assertEquals(5, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n\n            PageHelper.offsetPage(15, 5);\n            list = userMapper.selectAll();\n            assertEquals(4, ((Page<?>) list).getPageNum());\n            assertEquals(5, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/PageHelperTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageParam;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.RowBounds;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class PageHelperTest {\n\n    @Test\n    public void shouldGetAllCountries() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        try {\n            List<User> list = sqlSession.selectList(\"selectAll\");\n            assertEquals(183, list.size());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用Mapper接口调用时，对接口增加RowBounds参数，不需要修改对应的xml配置（或注解配置）\n     * <p/>\n     * RowBounds方式不进行count查询，可以通过修改Page代码实现\n     * <p/>\n     * 这种情况下如果同时使用startPage方法，以startPage为准\n     */\n    @Test\n    public void testMapperWithRowBounds() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            List<User> list = userMapper.selectAll(new RowBounds(0, 10));\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.get(list.size() - 1).getId());\n\n\n            //获取第2页，10条内容，显式查询总数count\n            list = userMapper.selectAll(new RowBounds(10, 10));\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(11, list.get(0).getId());\n            assertEquals(20, list.get(list.size() - 1).getId());\n\n\n            //获取第3页，20条内容，默认查询总数count\n            list = userMapper.selectAll(new RowBounds(60, 20));\n            assertEquals(20, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(61, list.get(0).getId());\n            assertEquals(80, list.get(list.size() - 1).getId());\n\n\n            //同时使用startPage和RowBounds时，以startPage为准\n            PageHelper.startPage(1, 20);\n            list = userMapper.selectAll(new RowBounds(60, 20));\n            assertEquals(20, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(1, list.get(0).getId());\n            assertEquals(20, list.get(list.size() - 1).getId());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用命名空间调用时，使用PageHelper.startPage\n     * <p/>\n     * startPage第三个参数可以控制是(true)否(false)执行count查询，使用两个查询的startPage时默认进行count查询\n     * <p/>\n     * 使用startPage方法时，如果同时使用RowBounds，以startPage为准\n     */\n    @Test\n    public void testNamespaceWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = sqlSession.selectList(\"selectAll\");\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n\n            //获取第2页，10条内容，显式查询总数count\n            PageHelper.startPage(2, 10, true);\n            list = sqlSession.selectList(\"selectAll\");\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n\n            //获取第2页，10条内容，不查询总数count\n            PageHelper.startPage(2, 10, false);\n            list = sqlSession.selectList(\"selectAll\");\n            assertEquals(10, list.size());\n            assertEquals(-1, ((Page<?>) list).getTotal());\n\n            //获取第3页，20条内容，默认查询总数count\n            PageHelper.startPage(3, 20);\n            list = sqlSession.selectList(\"selectAll\");\n            assertEquals(20, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n\n            //获取第3页，20条内容，默认查询总数count\n            PageHelper.startPage(new PageParam(4, 20));\n            list = sqlSession.selectList(\"selectAll\");\n            assertEquals(20, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用命名空间方式的RowBounds进行分页，使用RowBounds时不进行count查询\n     * 通过修改代码可以进行count查询，没法通过其他方法改变参数\n     * 因为如果通过调用一个别的方法来标记count查询，还不如直接startPage\n     * <p/>\n     * 同时使用startPage时，以startPage为准，会根据startPage参数来查询\n     */\n    @Test\n    public void testNamespaceWithRowBounds() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        try {\n            //获取从0开始，10条内容\n            List<User> list = sqlSession.selectList(\"selectAll\", null, new RowBounds(0, 10));\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.get(list.size() - 1).getId());\n\n\n            //获取从10开始，10条内容\n            list = sqlSession.selectList(\"selectAll\", null, new RowBounds(10, 10));\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(11, list.get(0).getId());\n            assertEquals(20, list.get(list.size() - 1).getId());\n\n\n            //获取从20开始，20条内容\n            list = sqlSession.selectList(\"selectAll\", null, new RowBounds(20, 20));\n            assertEquals(20, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(21, list.get(0).getId());\n            assertEquals(40, list.get(list.size() - 1).getId());\n\n\n            //同时使用startPage和RowBounds时，以startPage为准\n            PageHelper.startPage(1, 20);\n            list = sqlSession.selectList(\"selectAll\", null, new RowBounds(0, 10));\n            assertEquals(20, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(1, list.get(0).getId());\n            assertEquals(20, list.get(list.size() - 1).getId());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/PageInfoTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageInfo;\nimport com.github.pagehelper.PageSerializable;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class PageInfoTest {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testPageSize10() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectAll();\n            System.out.println(list);\n            PageInfo<User> page = new PageInfo<User>(list);\n            assertEquals(1, page.getPageNum());\n            assertEquals(10, page.getPageSize());\n            assertEquals(1, page.getStartRow());\n            assertEquals(10, page.getEndRow());\n            assertEquals(183, page.getTotal());\n            assertEquals(19, page.getPages());\n            assertEquals(true, page.isIsFirstPage());\n            assertEquals(false, page.isIsLastPage());\n            assertEquals(false, page.isHasPreviousPage());\n            assertEquals(true, page.isHasNextPage());\n\n            PageSerializable<User> serializable = PageSerializable.of(list);\n            assertEquals(183, serializable.getTotal());\n\n\n            //获取第2页，10条内容，默认查询总数count\n            PageHelper.startPage(2, 10);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(2, page.getPageNum());\n            assertEquals(10, page.getPageSize());\n            assertEquals(11, page.getStartRow());\n            assertEquals(20, page.getEndRow());\n            assertEquals(183, page.getTotal());\n            assertEquals(19, page.getPages());\n            assertEquals(false, page.isIsFirstPage());\n            assertEquals(false, page.isIsLastPage());\n            assertEquals(true, page.isHasPreviousPage());\n            assertEquals(true, page.isHasNextPage());\n\n\n            //获取第19页，10条内容，默认查询总数count\n            PageHelper.startPage(19, 10);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(19, page.getPageNum());\n            assertEquals(10, page.getPageSize());\n            assertEquals(181, page.getStartRow());\n            assertEquals(183, page.getEndRow());\n            assertEquals(183, page.getTotal());\n            assertEquals(19, page.getPages());\n            assertEquals(false, page.isIsFirstPage());\n            assertEquals(true, page.isIsLastPage());\n            assertEquals(true, page.isHasPreviousPage());\n            assertEquals(false, page.isHasNextPage());\n\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testPageSize50() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，50条内容，默认查询总数count\n            PageHelper.startPage(1, 50);\n            List<User> list = userMapper.selectAll();\n            PageInfo<User> page = new PageInfo<User>(list);\n            assertEquals(1, page.getPageNum());\n            assertEquals(50, page.getPageSize());\n            assertEquals(1, page.getStartRow());\n            assertEquals(50, page.getEndRow());\n            assertEquals(183, page.getTotal());\n            assertEquals(4, page.getPages());\n            assertEquals(true, page.isIsFirstPage());\n            assertEquals(false, page.isIsLastPage());\n            assertEquals(false, page.isHasPreviousPage());\n            assertEquals(true, page.isHasNextPage());\n\n\n            //获取第2页，50条内容，默认查询总数count\n            PageHelper.startPage(2, 50);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(2, page.getPageNum());\n            assertEquals(50, page.getPageSize());\n            assertEquals(51, page.getStartRow());\n            assertEquals(100, page.getEndRow());\n            assertEquals(183, page.getTotal());\n            assertEquals(4, page.getPages());\n            assertEquals(false, page.isIsFirstPage());\n            assertEquals(false, page.isIsLastPage());\n            assertEquals(true, page.isHasPreviousPage());\n            assertEquals(true, page.isHasNextPage());\n\n            //获取第3页，50条内容，默认查询总数count\n            PageHelper.startPage(3, 50);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(3, page.getPageNum());\n            assertEquals(50, page.getPageSize());\n            assertEquals(101, page.getStartRow());\n            assertEquals(150, page.getEndRow());\n            assertEquals(183, page.getTotal());\n            assertEquals(4, page.getPages());\n            assertEquals(false, page.isIsFirstPage());\n            assertEquals(false, page.isIsLastPage());\n            assertEquals(true, page.isHasPreviousPage());\n            assertEquals(true, page.isHasNextPage());\n\n\n            //获取第4页，50条内容，默认查询总数count\n            PageHelper.startPage(4, 50);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(4, page.getPageNum());\n            assertEquals(50, page.getPageSize());\n            assertEquals(151, page.getStartRow());\n            assertEquals(183, page.getEndRow());\n            assertEquals(183, page.getTotal());\n            assertEquals(4, page.getPages());\n            assertEquals(false, page.isIsFirstPage());\n            assertEquals(true, page.isIsLastPage());\n            assertEquals(true, page.isHasPreviousPage());\n            assertEquals(false, page.isHasNextPage());\n\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testNavigatePages() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectAll();\n            PageInfo<User> page = new PageInfo<User>(list, 20);\n            assertEquals(1, page.getPageNum());\n            assertEquals(10, page.getPageSize());\n            assertEquals(1, page.getStartRow());\n            assertEquals(10, page.getEndRow());\n            assertEquals(183, page.getTotal());\n            assertEquals(19, page.getPages());\n            assertEquals(true, page.isIsFirstPage());\n            assertEquals(false, page.isIsLastPage());\n            assertEquals(false, page.isHasPreviousPage());\n            assertEquals(true, page.isHasNextPage());\n\n            //获取第2页，50条内容，默认查询总数count\n            PageHelper.startPage(2, 50);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list, 2);\n            assertEquals(2, page.getPageNum());\n            assertEquals(50, page.getPageSize());\n            assertEquals(51, page.getStartRow());\n            assertEquals(100, page.getEndRow());\n            assertEquals(183, page.getTotal());\n            assertEquals(4, page.getPages());\n            assertEquals(false, page.isIsFirstPage());\n            assertEquals(false, page.isIsLastPage());\n            assertEquals(true, page.isHasPreviousPage());\n            assertEquals(true, page.isHasNextPage());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n\n    /**\n     * 手动指定记录总数，返回分页信息\n     */\n    @Test\n    public void testPageInfoOfTotal() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，关闭查询总数\n            PageHelper.startPage(1, 10, false);\n            List<User> list = userMapper.selectAll();\n            System.out.println(list);\n\n            //手动指定总数\n            PageInfo<User> page = PageInfo.of(183L, list);\n\n            assertEquals(1, page.getPageNum());\n            assertEquals(10, page.getPageSize());\n            assertEquals(1, page.getStartRow());\n            assertEquals(10, page.getEndRow());\n            assertEquals(183, page.getTotal());\n            assertEquals(19, page.getPages());\n            assertEquals(true, page.isIsFirstPage());\n            assertEquals(false, page.isIsLastPage());\n            assertEquals(false, page.isHasPreviousPage());\n            assertEquals(true, page.isHasNextPage());\n\n            PageSerializable<User> serializable = PageSerializable.of(list);\n            assertEquals(183, serializable.getTotal());\n\n\n            //获取第2页，10条内容，关闭查询总数\n            PageHelper.startPage(2, 10, false);\n            list = userMapper.selectAll();\n\n            //手动指定总数\n            page = PageInfo.of(183L, list);\n\n            assertEquals(2, page.getPageNum());\n            assertEquals(10, page.getPageSize());\n            assertEquals(11, page.getStartRow());\n            assertEquals(20, page.getEndRow());\n            assertEquals(183, page.getTotal());\n            assertEquals(19, page.getPages());\n            assertEquals(false, page.isIsFirstPage());\n            assertEquals(false, page.isIsLastPage());\n            assertEquals(true, page.isHasPreviousPage());\n            assertEquals(true, page.isHasNextPage());\n\n\n            //获取第19页，10条内容，关闭查询总数\n            PageHelper.startPage(19, 10, false);\n            list = userMapper.selectAll();\n\n            //手动指定总数\n            page = PageInfo.of(183L, list);\n\n            assertEquals(19, page.getPageNum());\n            assertEquals(10, page.getPageSize());\n            assertEquals(181, page.getStartRow());\n            assertEquals(183, page.getEndRow());\n            assertEquals(183, page.getTotal());\n            assertEquals(19, page.getPages());\n            assertEquals(false, page.isIsFirstPage());\n            assertEquals(true, page.isIsLastPage());\n            assertEquals(true, page.isHasPreviousPage());\n            assertEquals(false, page.isHasNextPage());\n\n\n            //不使用PageHelper.startPage\n            list = userMapper.selectAll();\n\n            //手动指定总数\n            page = PageInfo.of(183L, list);\n\n            assertEquals(1, page.getPageNum());\n            assertEquals(183, page.getPageSize());\n            assertEquals(0, page.getStartRow());\n            assertEquals(182, page.getEndRow());\n            assertEquals(183, page.getTotal());\n            assertEquals(1, page.getPages());\n            assertEquals(true, page.isIsFirstPage());\n            assertEquals(true, page.isIsLastPage());\n            assertEquals(false, page.isHasPreviousPage());\n            assertEquals(false, page.isHasNextPage());\n\n\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/RemoveOrderTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport java.util.List;\n\n/**\n * Created by Administrator on 14-8-24.\n */\npublic class RemoveOrderTest {\n\n    @Test\n    public void simpleOrderTest() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        //主要观看查询执行count查询的sql\n        try {\n            PageHelper.startPage(1, 50);\n            List<User> list = userMapper.selectAllOrderby();\n            //总数183\n            Assert.assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n\n    @Test\n    public void paramsOrderTest() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        //主要观看查询执行count查询的sql\n        try {\n            PageHelper.startPage(1, 50);\n            List<User> list = userMapper.selectAllOrderByParams(\"name\", \"py\");\n            //总数183\n            Assert.assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/TestDistinct.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestDistinct {\n\n    @Test\n    public void test() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectDistinct();\n            assertEquals(10, list.size());\n            assertEquals(58, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/TestExecute.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic class TestExecute {\n\n    @Test\n    public void test() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<Map<String, Object>> mapList = userMapper.execute(\"select * from user\");\n            Assert.assertEquals(10, mapList.size());\n            mapList = userMapper.execute(\"select * from user\");\n            Assert.assertEquals(183, mapList.size());\n            List<User> userList = userMapper.selectAll();\n            Assert.assertEquals(183, userList.size());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/TestISelect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.ISelect;\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageInfo;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport static org.junit.Assert.assertEquals;\n\n/**\n * @author liuzh_3nofxnp\n * @since 2015-12-26 09:15\n */\npublic class TestISelect {\n    @Test\n    public void testGroupBy2() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        final UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            Page<User> page = PageHelper.startPage(1, 10).doSelectPage(new ISelect() {\n                @Override\n                public void doSelect() {\n                    userMapper.selectGroupBy();\n                }\n            });\n            //下面是该方法的lambda用法\n            //Page<User> page = PageHelper.startPage(1, 10).setOrderBy(\"id desc\").doSelectPage(()-> userMapper.selectGroupBy());\n            //1,'Angola','AO'\n            assertEquals(1, page.get(0).getId());\n            assertEquals(10, page.size());\n            assertEquals(183, page.getTotal());\n\n            PageInfo<User> pageInfo = page.toPageInfo();\n            System.out.println(pageInfo);\n\n\n            pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(new ISelect() {\n                @Override\n                public void doSelect() {\n                    userMapper.selectGroupBy();\n                }\n            });\n            //lambda\n            //pageInfo = PageHelper.startPage(1, 10).setOrderBy(\"id desc\").doSelectPageInfo(() -> userMapper.selectGroupBy());\n\n            System.out.println(pageInfo);\n\n            final User user = new User();\n            user.setName(\"c\");\n\n            long total = PageHelper.count(new ISelect() {\n                @Override\n                public void doSelect() {\n                    userMapper.selectLike(user);\n                }\n            });\n            //lambda\n            //long total = PageHelper.count(()->userMapper.selectLike(user));\n\n            System.out.println(total);\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/TestIntMax.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestIntMax {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testCountCache() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, Integer.MAX_VALUE);\n            List<User> list = userMapper.selectIf(1);\n            assertEquals(2, list.get(0).getId());\n            assertEquals(182, list.size());\n            assertEquals(182, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, Integer.MAX_VALUE);\n            list = userMapper.selectIf(null);\n            assertEquals(1, list.get(0).getId());\n            assertEquals(183, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/TestLike.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestLike {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            User user = new User();\n            user.setName(\"刘\");\n            List<User> list = userMapper.selectLike(user);\n            assertEquals(78, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(15, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(2, 10);\n            list = userMapper.selectLike(user);\n            assertEquals(88, list.get(0).getId());\n            assertEquals(5, list.size());\n            assertEquals(15, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage_OrderBy() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.orderBy(\"id desc\");\n            User user = new User();\n            user.setName(\"刘\");\n            List<User> list = userMapper.selectLike(user);\n            assertEquals(92, list.get(0).getId());\n            assertEquals(15, list.size());\n            assertEquals(15, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage_OrderBy_issues_641() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 0, false, false, true);\n            PageHelper.orderBy(\"id desc\");\n            User user = new User();\n            user.setName(\"刘\");\n            List<User> list = userMapper.selectLike(user);\n            assertEquals(92, list.get(0).getId());\n            assertEquals(15, list.size());\n            assertEquals(15, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/TestNamespaceMap.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestNamespaceMap {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            Map<String, Object> map = new HashMap<String, Object>();\n            map.put(\"name\", \"刘\");\n            List<User> list = sqlSession.selectList(\"selectLike\", map);\n            assertEquals(78, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(15, ((Page<?>) list).getTotal());\n\n            PageHelper.startPage(1, 10);\n            map.put(\"name\", \"刘睿\");\n            map.put(\"py\", \"LR\");\n            list = sqlSession.selectList(\"selectByMap\", map);\n            assertEquals(78, list.get(0).getId());\n            assertEquals(1, list.size());\n            assertEquals(1, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/annotations/TestAnnotations.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.annotations;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestAnnotations {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectByOrder2(\"id\");\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            list = userMapper.selectByOrder(\"name\");\n            assertEquals(18, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage_OrderBy() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10, \"id desc\");\n            List<User> list = userMapper.selectByOrder2(\"id\");\n            assertEquals(183, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10, \"id desc\");\n            list = userMapper.selectByOrder(\"name\");\n            assertEquals(183, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/cache/CacheTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.cache;\n\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\n/**\n * 针对将ms缓存后的测试\n */\npublic class CacheTest {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectGreterThanId(10);\n            assertEquals(10, list.size());\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(2, 10);\n            list = userMapper.selectGreterThanIdAndNotEquelName(10, \"刘睿\");\n            assertEquals(10, list.size());\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(3, 10);\n            list = userMapper.selectGreterThanIdAndNotEquelName(10, \"刘睿\");\n            assertEquals(10, list.size());\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(4, 10);\n            list = userMapper.selectGreterThanIdAndNotEquelName(10, \"刘睿\");\n            assertEquals(10, list.size());\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(5, 10);\n            list = userMapper.selectGreterThanIdAndNotEquelName(10, \"刘睿\");\n            assertEquals(10, list.size());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testThreads() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        sqlSession.close();\n        try {\n            Thread.sleep(300);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        Thread thread1 = new Thread(new CacheThread());\n        Thread thread2 = new Thread(new CacheThread());\n        Thread thread3 = new Thread(new CacheThread());\n        Thread thread4 = new Thread(new CacheThread());\n        Thread thread5 = new Thread(new CacheThread());\n        thread1.start();\n        thread2.start();\n        thread3.start();\n        thread4.start();\n        thread5.start();\n        try {\n            Thread.sleep(300);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n\n    private class CacheThread implements Runnable {\n        private CacheThread() {\n        }\n\n        public void run() {\n            SqlSession sqlSession = MybatisHelper.getSqlSession();\n            System.out.println(Thread.currentThread().getId() + \"开始运行...\");\n            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectGreterThanIdAndNotEquelName(10, \"刘睿\");\n            assertEquals(10, list.size());\n            //获取第2页，10条内容，默认查询总数count\n            PageHelper.startPage(2, 10);\n            list = userMapper.selectGreterThanIdAndNotEquelName(10, \"刘睿\");\n            assertEquals(10, list.size());\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/cache/SecondCacheTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.cache;\n\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class SecondCacheTest {\n\n    @Test\n    public void test1() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectGreterThanId(10);\n            assertEquals(10, list.size());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            list = userMapper.selectGreterThanId(10);\n            assertEquals(10, list.size());\n        } finally {\n            sqlSession.close();\n        }\n\n        sqlSession = MybatisHelper.getSqlSession();\n        userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectGreterThanId(10);\n            assertEquals(10, list.size());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void test2() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectGreterThanId(10);\n            assertEquals(10, list.size());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void test3() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectGreterThanId(10);\n            assertEquals(10, list.size());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/count/TestGroupBy.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.count;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageInfo;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestGroupBy {\n\n    @Test\n    public void testGroupBy() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            Page<User> page = PageHelper.startPage(1, 10);\n            userMapper.selectGroupBy();\n            //1,'Angola','AO'\n            assertEquals(1, page.get(0).getId());\n            assertEquals(10, page.size());\n            assertEquals(183, page.getTotal());\n\n            PageInfo<User> pageInfo = page.toPageInfo();\n            System.out.println(pageInfo);\n\n            //获取第2页，10条内容，默认查询总数count\n            page = PageHelper.startPage(2, 10);\n            userMapper.selectGroupBy();\n            //1,'Angola','AO'\n            assertEquals(1, page.get(0).getId());\n            assertEquals(10, page.size());\n            assertEquals(183, page.getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/count/TestOrderBy.java",
    "content": "package com.github.pagehelper.test.basic.count;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\n/**\n * Test for ORDER BY with parameters - issue #868\n * \n * @author pwdLight (original fix)\n * @description Test that ORDER BY containing parameters is not removed in count\n *              query\n * @date 2025/10/22\n */\npublic class TestOrderBy {\n\n    /**\n     * Test ORDER BY with parameters - issue #868\n     * When ORDER BY contains parameters (#{param}), it should not be removed in\n     * count query\n     * to avoid JDBC parameter mismatch\n     */\n    @Test\n    public void testOrderByWithParameters() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            // Test with ORDER BY containing parameter binding (#{py})\n            // This will generate ORDER BY with ? placeholder\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectOrderByWithParam(\"ZSJ\");\n\n            // Verify pagination works correctly\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * Test ORDER BY without parameters - should use simple count optimization\n     */\n    @Test\n    public void testOrderByWithoutParameters() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            // Test with simple ORDER BY (no parameters)\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectAllOrderby();\n\n            // Verify pagination works correctly\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/count/TestSelectItems.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.count;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNull;\n\npublic class TestSelectItems {\n\n    /**\n     * 查询自定义列时 - 实际上这个测试由于使用${}，并没有起到真正的目的\n     */\n    @Test\n    public void testSelectColumns() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectColumns();\n            //1,'Angola','AO'\n            assertEquals(1, list.get(0).getId());\n            assertEquals(\"毕淑儒\", list.get(0).getName());\n            assertEquals(\"BSR\", list.get(0).getPy());\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            list = userMapper.selectColumns(\"id\", \"name\");\n            //1,'Angola','AO'\n            assertEquals(1, list.get(0).getId());\n            assertEquals(\"毕淑儒\", list.get(0).getName());\n            assertNull(list.get(0).getPy());\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用#{}在查询列中进行计算，count查询时需要特殊对待\n     */\n    @Test\n    public void testSelectColumn2() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectMULId(1);\n            //1,'Angola','AO'\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            list = userMapper.selectMULId(5);\n            //1,'Angola','AO'\n            assertEquals(5, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/dynamic/CacheTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.dynamic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\n/**\n * 针对将ms缓存后的测试\n */\npublic class CacheTest {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testThreads() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        sqlSession.close();\n        try {\n            Thread.sleep(300);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        Thread thread1 = new Thread(new CacheThread());\n        Thread thread2 = new Thread(new CacheThread());\n        Thread thread3 = new Thread(new CacheThread());\n        Thread thread4 = new Thread(new CacheThread());\n        Thread thread5 = new Thread(new CacheThread());\n        thread1.start();\n        thread2.start();\n        thread3.start();\n        thread4.start();\n        thread5.start();\n        try {\n            Thread.sleep(300);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n\n    private class CacheThread implements Runnable {\n        private CacheThread() {\n        }\n\n        public void run() {\n            SqlSession sqlSession = MybatisHelper.getSqlSession();\n            System.out.println(Thread.currentThread().getId() + \"开始运行...\");\n            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectIf2List(Arrays.asList(1, 2), Arrays.asList(3, 4));\n            assertEquals(5, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(179, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            list = userMapper.selectIf2List(Arrays.asList(1, 2), null);\n            assertEquals(3, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(181, ((Page<?>) list).getTotal());\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/dynamic/TestDynamicChoose.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.dynamic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestDynamicChoose {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectChoose(1, 2);\n            assertEquals(2, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(182, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            list = userMapper.selectChoose(1, 2);\n            assertEquals(2, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(182, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage_OrderBy() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10, \"id desc\");\n            List<User> list = userMapper.selectChoose(183, 2);\n            assertEquals(182, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(182, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10, \"id desc\");\n            list = userMapper.selectChoose(183, 2);\n            assertEquals(182, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(182, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/dynamic/TestDynamicForeach.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.dynamic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestDynamicForeach {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            List<Long> idList = new ArrayList<Long>();\n            idList.add(1L);\n            idList.add(2L);\n            idList.add(3L);\n            PageHelper.startPage(1, 2);\n            List<User> list = userMapper.selectByIdList(idList);\n            assertEquals(1, list.get(0).getId());\n            assertEquals(2, list.size());\n            assertEquals(3, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage2() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            List<Long> idList = new ArrayList<Long>();\n            idList.add(1L);\n            idList.add(2L);\n            idList.add(3L);\n            PageHelper.startPage(1, 2);\n            List<User> list = userMapper.selectByIdList2(idList);\n            assertEquals(1, list.get(0).getId());\n            assertEquals(2, list.size());\n            assertEquals(3, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/dynamic/TestDynamicIf.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.dynamic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestDynamicIf {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testCountCache() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectIf(1);\n            assertEquals(2, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(182, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            list = userMapper.selectIf(null);\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testCountCache2() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectIf(1);\n            assertEquals(2, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(182, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(2, 10);\n            list = userMapper.selectIf(1);\n            assertEquals(12, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(182, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 单个POJO参数情况特殊\n     */\n    @SuppressWarnings({\"rawtypes\", \"unchecked\"})\n    @Test\n    public void testMapper() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            Map map = new HashMap();\n\n            User user = new User();\n            user.setId(1);\n            map.put(\"user\", user);\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectIf3(user);\n            assertEquals(2, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(182, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/dynamic/TestDynamicIf2.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.dynamic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestDynamicIf2 {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectIf2(1, 2);\n            assertEquals(3, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(181, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            list = userMapper.selectIf2(1, null);\n            assertEquals(2, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(182, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/dynamic/TestDynamicIfOrder.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.dynamic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\n/**\n * 针对将ms缓存后的测试\n */\npublic class TestDynamicIfOrder {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectIf2ListAndOrder(Arrays.asList(1, 2), Arrays.asList(3, 4), null);\n            assertEquals(5, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(179, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            list = userMapper.selectIf2ListAndOrder(Arrays.asList(1, 2), null, \"id\");\n            assertEquals(3, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(181, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            list = userMapper.selectIf2ListAndOrder(new ArrayList<Integer>(0), null, \"name\");\n            assertEquals(18, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/dynamic/TestDynamicIfTwoList.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.dynamic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestDynamicIfTwoList {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectIf2List(Arrays.asList(1, 2), Arrays.asList(3, 4));\n            assertEquals(5, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(179, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            list = userMapper.selectIf2List(Arrays.asList(1, 2), null);\n            assertEquals(3, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(181, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            list = userMapper.selectIf2List(new ArrayList<Integer>(0), null);\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/dynamic/TestDynamicWhere.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.dynamic;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestDynamicWhere {\n\n    @Test\n    public void testMapperWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            Map<String, Object> params = new HashMap<String, Object>(2);\n            params.put(\"pageNum\", 1L);\n            params.put(\"pageSize\", \"100\");\n            PageHelper.startPage(params);\n            Map<String, Object> where = new HashMap<String, Object>();\n            where.put(\"id\", 100);\n            List<User> list = userMapper.selectByWhereMap(new Where(where));\n            assertEquals(100, list.get(0).getId());\n            assertEquals(1, list.size());\n            assertEquals(1, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/dynamic/Where.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.dynamic;\n\nimport java.util.Map;\n\n/**\n * Created by liuzh on 2015/1/11.\n */\npublic class Where {\n    private Map<String, Object> map;\n\n    public Where(Map<String, Object> map) {\n        this.map = map;\n    }\n\n    public Map<String, Object> getMap() {\n        return map;\n    }\n\n    public void setMap(Map<String, Object> map) {\n        this.map = map;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/example/TestExample.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.example;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.model.UserExample;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestExample {\n\n    @Test\n    public void testNull() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            PageHelper.startPage(1, 20);\n            List<User> list = userMapper.selectByExample(null);\n            assertEquals(1, list.get(0).getId());\n            assertEquals(20, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void testGreaterThan() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            UserExample example = new UserExample();\n            example.createCriteria().andIdGreaterThan(100);\n            PageHelper.startPage(1, 20);\n            List<User> list = userMapper.selectByExample(example);\n            assertEquals(101, list.get(0).getId());\n            assertEquals(20, list.size());\n            assertEquals(83, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void testInList() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            UserExample example = new UserExample();\n            example.createCriteria().andIdIn(Arrays.asList(1, 2, 3, 4, 5));\n            PageHelper.startPage(1, 20);\n            List<User> list = userMapper.selectByExample(example);\n            assertEquals(1, list.get(0).getId());\n            assertEquals(5, list.size());\n            assertEquals(5, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/parameter/TestParameterArray.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.parameter;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestParameterArray {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectAllOrderByArray(new Integer[]{1, 2});\n            assertEquals(3, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(181, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/parameter/TestParameterList.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.parameter;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestParameterList {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            List<Integer> paList = new ArrayList<Integer>();\n            paList.add(1);\n            paList.add(2);\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectAllOrderByList(paList);\n            assertEquals(3, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(181, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/parameter/TestParameterMap.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.parameter;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestParameterMap {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            Map<String, Object> map = new HashMap<String, Object>();\n            map.put(\"order1\", 1);\n            map.put(\"order2\", 2);\n            map.put(\"tableName\", \"user\");\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectAllOrderByMap(map);\n            assertEquals(3, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(181, ((Page<?>) list).getTotal());\n\n            map.put(\"tableName\", \"user a\");\n            PageHelper.startPage(1, 10);\n            list = userMapper.selectAllOrderByMap(map);\n            assertEquals(3, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(181, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/parameter/TestParameterNone.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.parameter;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestParameterNone {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectAll();\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/parameter/TestParameterOne.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.parameter;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestParameterOne {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectGreterThanId(1);\n            assertEquals(2, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(182, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/provider/SqlCache.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.provider;\n\npublic class SqlCache {\n\n    private static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<String>();\n\n    public static void set(String str) {\n        THREAD_LOCAL.set(str);\n    }\n\n    public static String get() {\n        return THREAD_LOCAL.get();\n    }\n\n    public static void remove() {\n        THREAD_LOCAL.remove();\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/provider/SqlCacheInterceptor.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.provider;\n\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.executor.Executor;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.plugin.*;\nimport org.apache.ibatis.session.ResultHandler;\nimport org.apache.ibatis.session.RowBounds;\n\nimport java.util.Properties;\n\n@Intercepts({\n        @Signature(type = Executor.class, method = \"query\", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),\n        @Signature(type = Executor.class, method = \"query\", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),\n})\npublic class SqlCacheInterceptor implements Interceptor {\n\n    @Override\n    public Object intercept(Invocation invocation) throws Throwable {\n        Object[] args = invocation.getArgs();\n        MappedStatement ms = (MappedStatement) args[0];\n        Object parameter = args[1];\n\n        String sql = ms.getBoundSql(parameter).getSql();\n        SqlCache.set(sql);\n\n        return invocation.proceed();\n    }\n\n    @Override\n    public Object plugin(Object target) {\n        return Plugin.wrap(target, this);\n    }\n\n    @Override\n    public void setProperties(Properties properties) {\n\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/provider/TestBoundSqlInterceptor.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.provider;\n\nimport com.github.pagehelper.BoundSqlInterceptor;\nimport com.github.pagehelper.util.MetaObjectUtil;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.reflection.MetaObject;\n\npublic class TestBoundSqlInterceptor implements BoundSqlInterceptor {\n    public static final String COMMENT = \"\\n /* TestBoundSqlInterceptor */\\n\";\n\n    @Override\n    public BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain) {\n        if (type == Type.ORIGINAL) {\n            String sql = boundSql.getSql();\n            MetaObject metaObject = MetaObjectUtil.forObject(boundSql);\n            metaObject.setValue(\"sql\", sql + COMMENT);\n        }\n        return chain.doBoundSql(type, boundSql, cacheKey);\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/provider/TestProvider.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.provider;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestProvider {\n\n    @Test\n    public void testSelectSimple() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            PageHelper.startPage(1, 10);\n            Page<User> list = userMapper.selectSimple(\"飞\");\n            assertEquals(24, list.get(0).getId());\n            assertEquals(6, list.size());\n            assertEquals(6, list.getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void testProvider() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        Map<String, Object> map = new HashMap<String, Object>();\n        map.put(\"id\", 100);\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectByProvider(map);\n            assertEquals(100, list.get(0).getId());\n            assertEquals(1, list.size());\n            assertEquals(1, ((Page<?>) list).getTotal());\n\n            map.put(\"name\", \"不存在\");\n            PageHelper.startPage(1, 10);\n            list = userMapper.selectByProvider(map);\n            assertEquals(0, list.size());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void testUserProvider() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        User user = new User();\n        user.setId(100);\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectByUserProvider(user);\n            assertEquals(100, list.get(0).getId());\n            assertEquals(1, list.size());\n            assertEquals(1, ((Page<?>) list).getTotal());\n\n            user.setName(\"不存在\");\n            PageHelper.startPage(1, 10);\n            list = userMapper.selectByUserProvider(user);\n            assertEquals(0, list.size());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void testUserSelect() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        User user = new User();\n        user.setId(100);\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            PageHelper.startPage(1, 10);\n            List<Map<String, Object>> userList = userMapper.selectBySelect();\n            System.out.println(userList.size());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/provider/TestProviderInteceptor.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.provider;\n\nimport com.github.pagehelper.BoundSqlInterceptor;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.ProviderMethod;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.util.MybatisInterceptorHelper;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport java.util.Random;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestProviderInteceptor {\n\n    @Test\n    public void testInterceptor() {\n        SqlSession sqlSession = MybatisInterceptorHelper.getSqlSession();\n        final UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            PageHelper.startPage(1, 10).boundSqlInterceptor(new BoundSqlInterceptor() {\n                @Override\n                public BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain) {\n                    System.out.println(\"[\" + Thread.currentThread().getName() + \"] - before: \" + boundSql.getSql());\n                    BoundSql doBoundSql = chain.doBoundSql(type, boundSql, cacheKey);\n                    System.out.println(\"[\" + Thread.currentThread().getName() + \"] - after: \" + doBoundSql.getSql());\n                    if (type == Type.ORIGINAL) {\n                        Assert.assertTrue(doBoundSql.getSql().contains(TestBoundSqlInterceptor.COMMENT));\n                    }\n                    return doBoundSql;\n                }\n            });\n            final String str = \"飞\";\n            userMapper.selectSimple(str);\n            assertEquals(new ProviderMethod().selectSimple(str), SqlCache.get());\n            userMapper.selectSimple(str);\n            assertEquals(new ProviderMethod().selectSimple(str), SqlCache.get());\n            userMapper.selectSimple(str);\n            assertEquals(new ProviderMethod().selectSimple(str), SqlCache.get());\n        } finally {\n            SqlCache.remove();\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void testConcurrentExecution() throws InterruptedException {\n        for (int i = 0; i < 10; i++) {\n            new Thread(new Runnable() {\n                @Override\n                public void run() {\n                    try {\n                        Thread.sleep(100 * new Random().nextInt(10));\n                        testInterceptor();\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                }\n            }).start();\n        }\n        Thread.currentThread().join(1500);\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/sql/TestExists.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.sql;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestExists {\n\n    /**\n     * union的count查询sql特殊\n     */\n    @Test\n    public void testExists() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectExists();\n            assertEquals(101, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(83, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(2, 10);\n            list = userMapper.selectExists();\n            assertEquals(111, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(83, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/sql/TestLeftjoin.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.sql;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestLeftjoin {\n\n    /**\n     * left join的count查询sql特殊\n     */\n    @Test\n    public void testLeftjoin() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectLeftjoin();\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(2, 10);\n            list = userMapper.selectLeftjoin();\n            assertEquals(11, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/sql/TestUnion.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.sql;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestUnion {\n\n    /**\n     * union的count查询sql特殊\n     */\n    @Test\n    public void testUnion() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectUnion();\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(13, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(2, 10);\n            list = userMapper.selectUnion();\n            assertEquals(181, list.get(0).getId());\n            assertEquals(3, list.size());\n            assertEquals(13, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/basic/sql/TestWith.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.basic.sql;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport com.github.pagehelper.util.TestUtil;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class TestWith {\n\n    /**\n     * with的count查询sql特殊 - 只测试oracle,别的可能不支持\n     */\n    @Test\n    public void testUnion() throws Exception {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        //只测试oracle\n        if (!TestUtil.getXmlPath().equalsIgnoreCase(\"oracle\")) {\n            return;\n        }\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectWith();\n            assertEquals(151, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(33, ((Page<?>) list).getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(2, 10);\n            list = userMapper.selectWith();\n            assertEquals(161, list.get(0).getId());\n            assertEquals(10, list.size());\n            assertEquals(33, ((Page<?>) list).getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/features/autodialect/AutoDialectTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.features.autodialect;\n\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageInfo;\nimport com.github.pagehelper.PageSerializable;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisAutoDialectHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class AutoDialectTest {\n\n    @Test\n    public void test() {\n        SqlSession sqlSession = MybatisAutoDialectHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectAll();\n            System.out.println(list);\n            PageInfo<User> page = new PageInfo<User>(list);\n            assertEquals(1, page.getPageNum());\n            assertEquals(10, page.getPageSize());\n            assertEquals(1, page.getStartRow());\n            assertEquals(10, page.getEndRow());\n            assertEquals(183, page.getTotal());\n            assertEquals(19, page.getPages());\n            assertEquals(true, page.isIsFirstPage());\n            assertEquals(false, page.isIsLastPage());\n            assertEquals(false, page.isHasPreviousPage());\n            assertEquals(true, page.isHasNextPage());\n\n            PageSerializable<User> serializable = PageSerializable.of(list);\n            assertEquals(183, serializable.getTotal());\n\n\n            //获取第2页，10条内容，默认查询总数count\n            PageHelper.startPage(2, 10);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(2, page.getPageNum());\n            assertEquals(10, page.getPageSize());\n            assertEquals(11, page.getStartRow());\n            assertEquals(20, page.getEndRow());\n            assertEquals(183, page.getTotal());\n            assertEquals(19, page.getPages());\n            assertEquals(false, page.isIsFirstPage());\n            assertEquals(false, page.isIsLastPage());\n            assertEquals(true, page.isHasPreviousPage());\n            assertEquals(true, page.isHasNextPage());\n\n\n            //获取第19页，10条内容，默认查询总数count\n            PageHelper.startPage(19, 10);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(19, page.getPageNum());\n            assertEquals(10, page.getPageSize());\n            assertEquals(181, page.getStartRow());\n            assertEquals(183, page.getEndRow());\n            assertEquals(183, page.getTotal());\n            assertEquals(19, page.getPages());\n            assertEquals(false, page.isIsFirstPage());\n            assertEquals(true, page.isIsLastPage());\n            assertEquals(true, page.isHasPreviousPage());\n            assertEquals(false, page.isHasNextPage());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/features/autodialect/DataSourceNegotiationAutoDialectTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.features.autodialect;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport com.github.pagehelper.dialect.auto.DataSourceNegotiationAutoDialect;\nimport com.github.pagehelper.dialect.auto.DruidAutoDialect;\nimport com.github.pagehelper.dialect.helper.*;\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.apache.commons.dbcp2.BasicDataSource;\nimport org.apache.ibatis.datasource.unpooled.UnpooledDataSource;\nimport org.junit.Assert;\nimport org.junit.Test;\n\nimport java.util.Properties;\n\npublic class DataSourceNegotiationAutoDialectTest {\n    public static final String HIKARI  = \"jdbc:h2:mem:basetest\";\n    public static final String DRUID   = \"jdbc:herddb:mem:basetest\";\n    public static final String TOMCAT  = \"jdbc:oracle://localhost/test\";\n    public static final String C3P0    = \"jdbc:mysql://localhost/test\";\n    public static final String DBCP    = \"jdbc:postgresql://localhost/test\";\n    public static final String DEFAULT = \"jdbc:hsqldb:mem:basetest\";\n\n    private HikariDataSource getHikari() {\n        HikariDataSource dataSource = new HikariDataSource();\n        dataSource.setJdbcUrl(HIKARI);\n        dataSource.setUsername(\"root\");\n        dataSource.setPassword(\"password\");\n        return dataSource;\n    }\n\n    private DruidDataSource getDriud() {\n        DruidDataSource dataSource = new DruidDataSource();\n        dataSource.setUrl(DRUID);\n        dataSource.setUsername(\"root\");\n        dataSource.setPassword(\"password\");\n        return dataSource;\n    }\n\n    private org.apache.tomcat.jdbc.pool.DataSource getTomcatJdbc() {\n        org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();\n        dataSource.setUrl(TOMCAT);\n        dataSource.setUsername(\"root\");\n        dataSource.setPassword(\"password\");\n        return dataSource;\n    }\n\n    private ComboPooledDataSource getC3P0() {\n        ComboPooledDataSource dataSource = new ComboPooledDataSource();\n        dataSource.setJdbcUrl(C3P0);\n        dataSource.setUser(\"root\");\n        dataSource.setPassword(\"password\");\n        return dataSource;\n    }\n\n    private BasicDataSource getDbcp() {\n        BasicDataSource dataSource = new BasicDataSource();\n        dataSource.setUrl(DBCP);\n        dataSource.setUsername(\"root\");\n        dataSource.setPassword(\"password\");\n        return dataSource;\n    }\n\n    private UnpooledDataSource getDefault() {\n        UnpooledDataSource dataSource = new UnpooledDataSource();\n        dataSource.setUrl(DEFAULT);\n        dataSource.setUsername(\"sa\");\n        dataSource.setDriver(\"org.hsqldb.jdbcDriver\");\n        return dataSource;\n    }\n\n    @Test\n    public void testNegotiation() {\n        Properties properties = new Properties();\n        properties.setProperty(\"closeConn\", \"true\");\n        DataSourceNegotiationAutoDialect autoDialect = new DataSourceNegotiationAutoDialect();\n        String dialectKey = autoDialect.extractDialectKey(null, getHikari(), properties);\n        Assert.assertEquals(HIKARI, dialectKey);\n        AbstractHelperDialect dialect = autoDialect.extractDialect(dialectKey, null, getHikari(), properties);\n        Assert.assertTrue(dialect instanceof HsqldbDialect);\n\n        dialectKey = autoDialect.extractDialectKey(null, getDriud(), properties);\n        Assert.assertEquals(DRUID, dialectKey);\n        dialect = autoDialect.extractDialect(dialectKey, null, getDriud(), properties);\n        Assert.assertTrue(dialect instanceof HerdDBDialect);\n\n        dialectKey = autoDialect.extractDialectKey(null, getTomcatJdbc(), properties);\n        Assert.assertEquals(TOMCAT, dialectKey);\n        dialect = autoDialect.extractDialect(dialectKey, null, getTomcatJdbc(), properties);\n        Assert.assertTrue(dialect instanceof OracleDialect);\n\n        dialectKey = autoDialect.extractDialectKey(null, getC3P0(), properties);\n        Assert.assertEquals(C3P0, dialectKey);\n        dialect = autoDialect.extractDialect(dialectKey, null, getC3P0(), properties);\n        Assert.assertTrue(dialect instanceof MySqlDialect);\n\n        dialectKey = autoDialect.extractDialectKey(null, getDbcp(), properties);\n        Assert.assertEquals(DBCP, dialectKey);\n        dialect = autoDialect.extractDialect(dialectKey, null, getDbcp(), properties);\n        Assert.assertTrue(dialect instanceof PostgreSqlDialect);\n\n        dialectKey = autoDialect.extractDialectKey(null, getDefault(), properties);\n        Assert.assertEquals(DEFAULT, dialectKey);\n        dialect = autoDialect.extractDialect(dialectKey, null, getDefault(), properties);\n        Assert.assertTrue(dialect instanceof HsqldbDialect);\n    }\n\n    @Test\n    public void testDruid() {\n        DruidAutoDialect druidAutoDialect = new DruidAutoDialect();\n        String jdbcUrl = druidAutoDialect.getJdbcUrl(getDriud());\n        Assert.assertEquals(DRUID, jdbcUrl);\n        AbstractHelperDialect dialect = druidAutoDialect.extractDialect(jdbcUrl, null, null, new Properties());\n        Assert.assertTrue(dialect instanceof HerdDBDialect);\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/features/autodialect/SimpleAutoDialect.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.features.autodialect;\n\nimport com.github.pagehelper.AutoDialect;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport com.github.pagehelper.page.PageAutoDialect;\nimport org.apache.ibatis.datasource.unpooled.UnpooledDataSource;\nimport org.apache.ibatis.mapping.MappedStatement;\n\nimport javax.sql.DataSource;\nimport java.util.Properties;\n\n/**\n * 简单示例，直接从属性读取url，无需获取数据库连接，也不需要考虑是否需要关闭\n */\npublic class SimpleAutoDialect implements AutoDialect<UnpooledDataSource> {\n\n    @Override\n    public UnpooledDataSource extractDialectKey(MappedStatement ms, DataSource dataSource, Properties properties) {\n        if (dataSource instanceof UnpooledDataSource) {\n            return (UnpooledDataSource) dataSource;\n\n        }\n        throw new UnsupportedOperationException(\"不支持的数据源类型: \" + dataSource.getClass().getName());\n    }\n\n    @Override\n    public AbstractHelperDialect extractDialect(UnpooledDataSource dialectKey, MappedStatement ms, DataSource dataSource, Properties properties) {\n        String url = dialectKey.getUrl();\n        String dialect = PageAutoDialect.fromJdbcUrl(url);\n        return PageAutoDialect.instanceDialect(dialect, properties);\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/features/dialectclass/UsingDialectClassTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.features.dialectclass;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageInfo;\nimport com.github.pagehelper.PageSerializable;\nimport com.github.pagehelper.dialect.AbstractHelperDialect;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.page.PageAutoDialect;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.cache.CacheKey;\nimport org.apache.ibatis.mapping.BoundSql;\nimport org.apache.ibatis.mapping.MappedStatement;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class UsingDialectClassTest {\n\n    public static final String TEST2_DIALECT_CLASS = Test2Dialect.class.getName();\n\n    static {\n        //一个通过注册方法，另一个直接通过类名\n        PageAutoDialect.registerDialectAlias(\"test1\", Test1Dialect.class);\n    }\n\n    @Test\n    public void test() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            List<User> list = userMapper.selectAll();\n            System.out.println(list);\n            PageInfo<User> page = new PageInfo<User>(list);\n            assertEquals(1, page.getPageNum());\n            assertEquals(10, page.getPageSize());\n            assertEquals(1, page.getStartRow());\n            assertEquals(10, page.getEndRow());\n            assertEquals(183, page.getTotal());\n            assertEquals(19, page.getPages());\n            assertEquals(true, page.isIsFirstPage());\n            assertEquals(false, page.isIsLastPage());\n            assertEquals(false, page.isHasPreviousPage());\n            assertEquals(true, page.isHasNextPage());\n\n            PageSerializable<User> serializable = PageSerializable.of(list);\n            assertEquals(183, serializable.getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10).using(\"test1\");\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(183, list.size());\n            assertEquals(183, page.getTotal());\n\n            serializable = PageSerializable.of(list);\n            assertEquals(183, serializable.getTotal());\n\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(1, 10);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(10, list.size());\n            assertEquals(183, page.getTotal());\n\n            serializable = PageSerializable.of(list);\n            assertEquals(183, serializable.getTotal());\n\n            //获取第1页，10条内容，默认查询总数count\n            PageHelper.startPage(2, 10);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(10, list.size());\n            assertEquals(183, page.getTotal());\n\n            serializable = PageSerializable.of(list);\n            assertEquals(183, serializable.getTotal());\n\n\n            //获取第2页，10条内容，默认查询总数count\n            PageHelper.startPage(2, 10).using(TEST2_DIALECT_CLASS);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n\n            assertEquals(100, list.size());\n            assertEquals(183, page.getTotal());\n\n\n            PageHelper.startPage(3, 10);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n\n            assertEquals(10, list.size());\n            assertEquals(183, page.getTotal());\n\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    public static class Test1Dialect extends AbstractHelperDialect {\n        @Override\n        public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {\n            return paramMap;\n        }\n\n        @Override\n        public String getPageSql(String sql, Page page, CacheKey pageKey) {\n            return \"/*test1*/\" + sql;\n        }\n    }\n\n    public static class Test2Dialect extends AbstractHelperDialect {\n        @Override\n        public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {\n            return paramMap;\n        }\n\n        @Override\n        public String getPageSql(String sql, Page page, CacheKey pageKey) {\n            pageKey.update(100);\n            return \"select * from (\\n\" + sql + \"\\n) temp_table where id <= 100\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/namespace/BasicTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.namespace;\n\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisRowBoundsHelper;\nimport org.apache.ibatis.session.RowBounds;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class BasicTest {\n\n    @Test\n    public void testNamespace1() {\n        SqlSession sqlSession = MybatisRowBoundsHelper.getSqlSession();\n        try {\n            Map<String, Object> map = new HashMap<String, Object>();\n            User user = new User();\n            user.setName(\"刘睿\");\n            map.put(\"user\", user);\n            //同时测试不可变Map\n            map = Collections.unmodifiableMap(map);\n            List<User> list = sqlSession.selectList(\"select1\", map, new RowBounds(1, 10));\n            assertEquals(1, list.size());\n            //判断查询结果的位置是否正确\n            assertEquals(78, list.get(0).getId());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void testNamespace3() {\n        SqlSession sqlSession = MybatisRowBoundsHelper.getSqlSession();\n        try {\n            Map<String, Object> map = new HashMap<String, Object>();\n            User user = new User();\n            map.put(\"user\", user);\n            //同时测试不可变Map\n            map = Collections.unmodifiableMap(map);\n            List<User> list = sqlSession.selectList(\"select1\", map, new RowBounds(1, 10));\n            assertEquals(10, list.size());\n            //判断查询结果的位置是否正确\n            assertEquals(1, list.get(0).getId());\n\n            map = new HashMap<String, Object>();\n            user = new User();\n            user.setName(\"刘睿\");\n            map.put(\"user\", user);\n            //同时测试不可变Map\n            map = Collections.unmodifiableMap(map);\n            list = sqlSession.selectList(\"select1\", map, new RowBounds(1, 10));\n            assertEquals(1, list.size());\n            //判断查询结果的位置是否正确\n            assertEquals(78, list.get(0).getId());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void testNamespace2() {\n        SqlSession sqlSession = MybatisRowBoundsHelper.getSqlSession();\n        try {\n            Map<String, Object> map = new HashMap<String, Object>();\n            User user = new User();\n            user.setName(\"刘睿\");\n            map.put(\"user\", user);\n            PageHelper.startPage(1, 10);\n            List<User> list = sqlSession.selectList(\"select1\", map);\n            assertEquals(1, list.size());\n            //判断查询结果的位置是否正确\n            assertEquals(78, list.get(0).getId());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/pagesize/PageSizeLessThenOrEqualZeroTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.pagesize;\n\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageInfo;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisHelper;\nimport org.apache.ibatis.session.RowBounds;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class PageSizeLessThenOrEqualZeroTest {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testWithStartPage() {\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //pageSize=0,这时候相当于用分页插件求count\n            PageHelper.startPage(1, 0);\n            List<User> list = userMapper.selectAll();\n            PageInfo<User> page = new PageInfo<User>(list);\n            assertEquals(0, list.size());\n            assertEquals(183, page.getTotal());\n\n            //limit<0的时候同上\n            PageHelper.startPage(1, -100);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(0, list.size());\n            assertEquals(183, page.getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testWithRowbounds() {\n        //注意这里是MybatisRowBoundsHelper，会求count\n        SqlSession sqlSession = MybatisHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //limit=0,这时候相当于用分页插件求count,但是前提必须是配置rounbounds方式求count，否则都是-1\n            List<User> list = userMapper.selectAll(new RowBounds(1, -1));\n            PageInfo<User> page = new PageInfo<User>(list);\n            assertEquals(0, list.size());\n            assertEquals(183, page.getTotal());\n\n            //limit<0的时候同上\n            list = userMapper.selectAll(new RowBounds(1, -100));\n            page = new PageInfo<User>(list);\n            assertEquals(0, list.size());\n            assertEquals(183, page.getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/pagesize/PageSizeZeroTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.pagesize;\n\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageInfo;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisPageSizeZeroHelper;\nimport org.apache.ibatis.session.RowBounds;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\n/**\n * @author liuzh\n */\npublic class PageSizeZeroTest {\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testWithStartPage() {\n        SqlSession sqlSession = MybatisPageSizeZeroHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //pageSize=0的时候查询全部结果\n            PageHelper.startPage(1, 0);\n            List<User> list = userMapper.selectAll();\n            PageInfo<User> page = new PageInfo<User>(list);\n            assertEquals(183, list.size());\n            assertEquals(183, page.getTotal());\n\n            //pageSize=0的时候查询全部结果\n            PageHelper.startPage(10, 0);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(183, list.size());\n            assertEquals(183, page.getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testWithRowbounds() {\n        SqlSession sqlSession = MybatisPageSizeZeroHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //pageSize=0的时候查询全部结果\n            List<User> list = userMapper.selectAll(new RowBounds(1, 0));\n            PageInfo<User> page = new PageInfo<User>(list);\n            assertEquals(183, list.size());\n            assertEquals(183, page.getTotal());\n\n            //pageSize=0的时候查询全部结果\n            PageHelper.startPage(10, 0);\n            list = userMapper.selectAll(new RowBounds(1000, 0));\n            page = new PageInfo<User>(list);\n            assertEquals(183, list.size());\n            assertEquals(183, page.getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/reasonable/PageTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.reasonable;\n\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageInfo;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisReasonableHelper;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class PageTest {\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testMapperWithStartPage() {\n        SqlSession sqlSession = MybatisReasonableHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第20页，2条内容\n            //分页插件会自动改为查询最后一页\n            PageHelper.startPage(20, 50);\n            List<User> list = userMapper.selectAll();\n            PageInfo<User> page = new PageInfo<User>(list);\n            assertEquals(33, list.size());\n            assertEquals(151, page.getStartRow());\n            assertEquals(4, page.getPageNum());\n            assertEquals(183, page.getTotal());\n\n            //获取第-3页，2条内容\n            //由于只有7天数据，分页插件会自动改为查询最后一页\n            PageHelper.startPage(-3, 50);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(50, list.size());\n            assertEquals(1, page.getStartRow());\n            assertEquals(1, page.getPageNum());\n            assertEquals(183, page.getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void testMapperWithStartPageAndReasonableFalse() {\n        SqlSession sqlSession = MybatisReasonableHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第20页，2条内容\n            //分页插件会自动改为查询最后一页\n            PageHelper.startPage(20, 50, true, false, false);\n            List<User> list = userMapper.selectAll();\n            PageInfo<User> page = new PageInfo<User>(list);\n            assertEquals(0, list.size());\n            assertEquals(0, page.getStartRow());\n            assertEquals(20, page.getPageNum());\n            assertEquals(183, page.getTotal());\n\n            PageHelper.startPage(4, 50, true, false, false);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(33, list.size());\n            assertEquals(151, page.getStartRow());\n            assertEquals(4, page.getPageNum());\n            assertEquals(183, page.getTotal());\n\n            PageHelper.startPage(-1, 50, true, false, false);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(0, list.size());\n            assertEquals(0, page.getStartRow());\n            assertEquals(-1, page.getPageNum());\n            assertEquals(183, page.getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void testMapperWithStartPageAndReasonableTrue() {\n        SqlSession sqlSession = MybatisReasonableHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第20页，2条内容\n            //分页插件会自动改为查询最后一页\n            PageHelper.startPage(20, 50, true, true, false);\n            List<User> list = userMapper.selectAll();\n            PageInfo<User> page = new PageInfo<User>(list);\n            assertEquals(33, list.size());\n            assertEquals(151, page.getStartRow());\n            assertEquals(4, page.getPageNum());\n            assertEquals(183, page.getTotal());\n\n            PageHelper.startPage(4, 50, true, true, false);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(33, list.size());\n            assertEquals(151, page.getStartRow());\n            assertEquals(4, page.getPageNum());\n            assertEquals(183, page.getTotal());\n\n            PageHelper.startPage(-1, 50, true, true, false);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(50, list.size());\n            assertEquals(1, page.getStartRow());\n            assertEquals(1, page.getPageNum());\n            assertEquals(183, page.getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void testMapperWithStartPageAndPageSizeZeroFalse() {\n        SqlSession sqlSession = MybatisReasonableHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第20页，2条内容\n            //分页插件会自动改为查询最后一页\n            PageHelper.startPage(1, 0, true, true, false);\n            List<User> list = userMapper.selectAll();\n            PageInfo<User> page = new PageInfo<User>(list);\n            assertEquals(0, list.size());\n            assertEquals(0, page.getStartRow());\n            assertEquals(1, page.getPageNum());\n            assertEquals(183, page.getTotal());\n\n            PageHelper.startPage(1, Integer.MAX_VALUE, true, true, false);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(183, list.size());\n            assertEquals(1, page.getStartRow());\n            assertEquals(1, page.getPageNum());\n            assertEquals(183, page.getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void testMapperWithStartPageAndPageSizeZeroTrue() {\n        SqlSession sqlSession = MybatisReasonableHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第20页，2条内容\n            //分页插件会自动改为查询最后一页\n            PageHelper.startPage(1, 0, true, true, true);\n            List<User> list = userMapper.selectAll();\n            PageInfo<User> page = new PageInfo<User>(list);\n            assertEquals(183, list.size());\n            assertEquals(1, page.getStartRow());\n            assertEquals(1, page.getPageNum());\n            assertEquals(183, page.getTotal());\n\n            PageHelper.startPage(1, -1, true, true, true);\n            list = userMapper.selectAll();\n            page = new PageInfo<User>(list);\n            assertEquals(0, list.size());\n            assertEquals(0, page.getStartRow());\n            assertEquals(1, page.getPageNum());\n            assertEquals(183, page.getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/test/rowbounds/RowBoundsTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.test.rowbounds;\n\nimport com.github.pagehelper.Page;\nimport com.github.pagehelper.PageHelper;\nimport com.github.pagehelper.PageInfo;\nimport com.github.pagehelper.mapper.UserMapper;\nimport com.github.pagehelper.model.User;\nimport com.github.pagehelper.util.MybatisRowBoundsHelper;\nimport org.apache.ibatis.session.RowBounds;\nimport org.apache.ibatis.session.SqlSession;\nimport org.junit.Test;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class RowBoundsTest {\n\n    /**\n     * 使用Mapper接口调用时，对接口增加RowBounds参数，不需要修改对应的xml配置（或注解配置）\n     * <p/>\n     * RowBounds方式不进行count查询，可以通过修改Page代码实现\n     * <p/>\n     * 这种情况下如果同时使用startPage方法，以startPage为准\n     */\n    @Test\n    public void testMapperWithRowBounds() {\n        SqlSession sqlSession = MybatisRowBoundsHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //获取第1页，10条内容，默认查询总数count\n            List<User> list = userMapper.selectAll(new RowBounds(1, 10));\n            //新增PageInfo对象，对返回结果进行封装\n            PageInfo<User> page = new PageInfo<User>(list);\n            assertEquals(10, list.size());\n            assertEquals(183, page.getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.get(list.size() - 1).getId());\n\n\n            //获取第10页，10条内容，显式查询总数count\n            list = userMapper.selectAll(new RowBounds(10, 10));\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(91, list.get(0).getId());\n            assertEquals(100, list.get(list.size() - 1).getId());\n\n\n            //获取第3页，20条内容，默认查询总数count\n            list = userMapper.selectAll(new RowBounds(6, 20));\n            assertEquals(20, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(101, list.get(0).getId());\n            assertEquals(120, list.get(list.size() - 1).getId());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用命名空间方式的RowBounds进行分页，使用RowBounds时不进行count查询\n     * 通过修改代码可以进行count查询，没法通过其他方法改变参数\n     * 因为如果通过调用一个别的方法来标记count查询，还不如直接startPage\n     * <p/>\n     * 同时使用startPage时，以startPage为准，会根据startPage参数来查询\n     */\n    @Test\n    public void testNamespaceWithRowBounds() {\n        SqlSession sqlSession = MybatisRowBoundsHelper.getSqlSession();\n        try {\n            //获取从0开始，10条内容\n            List<User> list = sqlSession.selectList(\"selectAll\", null, new RowBounds(1, 10));\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.get(list.size() - 1).getId());\n\n\n            //获取从10开始，10条内容\n            list = sqlSession.selectList(\"selectAll\", null, new RowBounds(10, 10));\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(91, list.get(0).getId());\n            assertEquals(100, list.get(list.size() - 1).getId());\n\n\n            //获取从20开始，20条内容\n            list = sqlSession.selectList(\"selectAll\", null, new RowBounds(6, 20));\n            assertEquals(20, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(101, list.get(0).getId());\n            assertEquals(120, list.get(list.size() - 1).getId());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void testNamespaceWithRowBounds2() {\n        SqlSession sqlSession = MybatisRowBoundsHelper.getSqlSession();\n        try {\n            //获取从0开始，10条内容\n            List<User> list = sqlSession.selectList(\"selectIf\", null, new RowBounds(1, 10));\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.get(list.size() - 1).getId());\n\n            Map<String, Object> map = new HashMap<String, Object>();\n            map.put(\"id\", 10);\n            //获取从10开始，10条内容\n            list = sqlSession.selectList(\"selectIf\", map, new RowBounds(10, 10));\n            assertEquals(10, list.size());\n            assertEquals(173, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(101, list.get(0).getId());\n            assertEquals(110, list.get(list.size() - 1).getId());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    @Test\n    public void testNamespaceWithRowBounds3() {\n        SqlSession sqlSession = MybatisRowBoundsHelper.getSqlSession();\n        try {\n            //获取从0开始，10条内容\n            PageHelper.startPage(1, 10);\n            List<User> list = sqlSession.selectList(\"selectIf\", null);\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(1, list.get(0).getId());\n            assertEquals(10, list.get(list.size() - 1).getId());\n\n            Map<String, Object> map = new HashMap<String, Object>();\n            map.put(\"id\", 10);\n            //获取从10开始，10条内容\n            PageHelper.startPage(10, 10);\n            list = sqlSession.selectList(\"selectIf\", map);\n            assertEquals(10, list.size());\n            assertEquals(173, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(101, list.get(0).getId());\n            assertEquals(110, list.get(list.size() - 1).getId());\n\n            IdBean user = new IdBean();\n            //获取从10开始，10条内容\n            PageHelper.startPage(10, 10);\n            list = sqlSession.selectList(\"selectIf\", user);\n            assertEquals(10, list.size());\n            assertEquals(183, ((Page<?>) list).getTotal());\n            //判断查询结果的位置是否正确\n            assertEquals(91, list.get(0).getId());\n            assertEquals(100, list.get(list.size() - 1).getId());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    /**\n     * 使用Mapper接口调用时，使用PageHelper.startPage效果更好，不需要添加Mapper接口参数\n     */\n    @Test\n    public void testWithRowboundsAndCountTrue() {\n        SqlSession sqlSession = MybatisRowBoundsHelper.getSqlSession();\n        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);\n        try {\n            //limit=0,这时候相当于用分页插件求count,但是前提必须是配置rounbounds方式求count，否则都是-1\n            //这里由于没有配置，应该都是-1\n            List<User> list = userMapper.selectAll(new RowBounds(1, -1));\n            PageInfo<User> page = new PageInfo<User>(list);\n            assertEquals(0, list.size());\n            assertEquals(183, page.getTotal());\n\n            //pageSize<0的时候同上\n            list = userMapper.selectAll(new RowBounds(1, -100));\n            page = new PageInfo<User>(list);\n            assertEquals(0, list.size());\n            assertEquals(183, page.getTotal());\n        } finally {\n            sqlSession.close();\n        }\n    }\n\n    class IdBean {\n        private Integer id;\n\n        public Integer getId() {\n            return id;\n        }\n\n        public void setId(Integer id) {\n            this.id = id;\n        }\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/util/MybatisAutoDialectHelper.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;\n\nimport org.apache.ibatis.io.Resources;\nimport org.apache.ibatis.jdbc.ScriptRunner;\nimport org.apache.ibatis.session.SqlSession;\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.apache.ibatis.session.SqlSessionFactoryBuilder;\n\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.sql.Connection;\n\n/**\n * Description: MybatisHelper\n * Author: liuzh\n * Update: liuzh(2014-06-06 13:33)\n */\npublic class MybatisAutoDialectHelper {\n\n    private static SqlSessionFactory sqlSessionFactory;\n\n    static {\n        try {\n            //创建SqlSessionFactory\n            Reader reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + \"/mybatis-config-autodialect.xml\");\n            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);\n            reader.close();\n            if (TestUtil.getXmlPath().equalsIgnoreCase(\"hsqldb\")\n                    || TestUtil.getXmlPath().equalsIgnoreCase(\"h2\")\n                    || TestUtil.getXmlPath().equalsIgnoreCase(\"derby\")) {\n                //创建数据库\n                SqlSession session = null;\n                try {\n                    session = sqlSessionFactory.openSession();\n                    Connection conn = session.getConnection();\n                    reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + \"/\" + TestUtil.getXmlPath() + \".sql\");\n                    ScriptRunner runner = new ScriptRunner(conn);\n                    runner.setLogWriter(null);\n                    runner.runScript(reader);\n                    reader.close();\n                } finally {\n                    if (session != null) {\n                        session.close();\n                    }\n                }\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 获取Session\n     *\n     * @return\n     */\n    public static SqlSession getSqlSession() {\n        return sqlSessionFactory.openSession();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/util/MybatisHelper.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;\n\nimport com.github.pagehelper.dialect.auto.DataSourceAutoDialect;\nimport com.github.pagehelper.dialect.auto.DataSourceNegotiationAutoDialect;\nimport org.apache.ibatis.datasource.unpooled.UnpooledDataSource;\nimport org.apache.ibatis.io.Resources;\nimport org.apache.ibatis.jdbc.ScriptRunner;\nimport org.apache.ibatis.session.SqlSession;\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.apache.ibatis.session.SqlSessionFactoryBuilder;\n\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.sql.Connection;\n\n/**\n * Description: MybatisHelper\n * Author: liuzh\n * Update: liuzh(2014-06-06 13:33)\n */\npublic class MybatisHelper {\n\n    private static SqlSessionFactory sqlSessionFactory;\n\n    static {\n        try {\n            //创建SqlSessionFactory\n            Reader reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + \"/mybatis-config.xml\");\n            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);\n            reader.close();\n            if (TestUtil.getXmlPath().equalsIgnoreCase(\"hsqldb\")\n                    || TestUtil.getXmlPath().equalsIgnoreCase(\"h2\")\n                    || TestUtil.getXmlPath().equalsIgnoreCase(\"derby\")) {\n                //创建数据库\n                SqlSession session = null;\n                try {\n                    session = sqlSessionFactory.openSession();\n                    Connection conn = session.getConnection();\n                    reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + \"/\" + TestUtil.getXmlPath() + \".sql\");\n                    ScriptRunner runner = new ScriptRunner(conn);\n                    runner.setLogWriter(null);\n                    runner.runScript(reader);\n                    reader.close();\n                } finally {\n                    if (session != null) {\n                        session.close();\n                    }\n                }\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        //添加一个针对 unpool 的 AutoDialect\n        DataSourceNegotiationAutoDialect.registerAutoDialect(new DataSourceAutoDialect<UnpooledDataSource>() {\n            @Override\n            public String getJdbcUrl(UnpooledDataSource unpooledDataSource) {\n                return unpooledDataSource.getUrl();\n            }\n        });\n    }\n\n    /**\n     * 获取Session\n     *\n     * @return\n     */\n    public static SqlSession getSqlSession() {\n        return sqlSessionFactory.openSession();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/util/MybatisInterceptorHelper.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;\n\nimport org.apache.ibatis.io.Resources;\nimport org.apache.ibatis.jdbc.ScriptRunner;\nimport org.apache.ibatis.session.SqlSession;\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.apache.ibatis.session.SqlSessionFactoryBuilder;\n\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.sql.Connection;\n\n/**\n * Description: MybatisHelper\n * Author: liuzh\n * Update: liuzh(2014-06-06 13:33)\n */\npublic class MybatisInterceptorHelper {\n\n    private static SqlSessionFactory sqlSessionFactory;\n\n    static {\n        try {\n            //创建SqlSessionFactory\n            Reader reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + \"/mybatis-config-interceptor.xml\");\n            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);\n            reader.close();\n            if (TestUtil.getXmlPath().equalsIgnoreCase(\"hsqldb\")\n                    || TestUtil.getXmlPath().equalsIgnoreCase(\"h2\")\n                    || TestUtil.getXmlPath().equalsIgnoreCase(\"derby\")) {\n                //创建数据库\n                SqlSession session = null;\n                try {\n                    session = sqlSessionFactory.openSession();\n                    Connection conn = session.getConnection();\n                    reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + \"/\" + TestUtil.getXmlPath() + \".sql\");\n                    ScriptRunner runner = new ScriptRunner(conn);\n                    runner.setLogWriter(null);\n                    runner.runScript(reader);\n                    reader.close();\n                } finally {\n                    if (session != null) {\n                        session.close();\n                    }\n                }\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 获取Session\n     *\n     * @return\n     */\n    public static SqlSession getSqlSession() {\n        return sqlSessionFactory.openSession();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/util/MybatisPageSizeZeroHelper.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;\n\nimport org.apache.ibatis.io.Resources;\nimport org.apache.ibatis.jdbc.ScriptRunner;\nimport org.apache.ibatis.session.SqlSession;\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.apache.ibatis.session.SqlSessionFactoryBuilder;\n\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.sql.Connection;\n\n/**\n * Description: MybatisHelper\n * Author: liuzh\n * Update: liuzh(2014-06-06 13:33)\n */\npublic class MybatisPageSizeZeroHelper {\n\n    private static SqlSessionFactory sqlSessionFactory;\n\n    static {\n        try {\n            //创建SqlSessionFactory\n            Reader reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + \"/mybatis-config-pagesizezero.xml\");\n            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);\n            reader.close();\n            if (TestUtil.getXmlPath().equalsIgnoreCase(\"hsqldb\")\n                    || TestUtil.getXmlPath().equalsIgnoreCase(\"h2\")\n                    || TestUtil.getXmlPath().equalsIgnoreCase(\"derby\")) {\n                //创建数据库\n                SqlSession session = null;\n                try {\n                    session = sqlSessionFactory.openSession();\n                    Connection conn = session.getConnection();\n                    reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + \"/\" + TestUtil.getXmlPath() + \".sql\");\n                    ScriptRunner runner = new ScriptRunner(conn);\n                    runner.setLogWriter(null);\n                    runner.runScript(reader);\n                    reader.close();\n                } finally {\n                    if (session != null) {\n                        session.close();\n                    }\n                }\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 获取Session\n     *\n     * @return\n     */\n    public static SqlSession getSqlSession() {\n        return sqlSessionFactory.openSession();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/util/MybatisReasonableHelper.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;\n\nimport org.apache.ibatis.io.Resources;\nimport org.apache.ibatis.jdbc.ScriptRunner;\nimport org.apache.ibatis.session.SqlSession;\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.apache.ibatis.session.SqlSessionFactoryBuilder;\n\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.sql.Connection;\n\n/**\n * Description: MybatisHelper\n * Author: liuzh\n * Update: liuzh(2014-06-06 13:33)\n */\npublic class MybatisReasonableHelper {\n\n    private static SqlSessionFactory sqlSessionFactory;\n\n    static {\n        try {\n            //创建SqlSessionFactory\n            Reader reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + \"/mybatis-config-reasonable.xml\");\n            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);\n            reader.close();\n            if (TestUtil.getXmlPath().equalsIgnoreCase(\"hsqldb\")\n                    || TestUtil.getXmlPath().equalsIgnoreCase(\"h2\")\n                    || TestUtil.getXmlPath().equalsIgnoreCase(\"derby\")) {\n                //创建数据库\n                SqlSession session = null;\n                try {\n                    session = sqlSessionFactory.openSession();\n                    Connection conn = session.getConnection();\n                    reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + \"/\" + TestUtil.getXmlPath() + \".sql\");\n                    ScriptRunner runner = new ScriptRunner(conn);\n                    runner.setLogWriter(null);\n                    runner.runScript(reader);\n                    reader.close();\n                } finally {\n                    if (session != null) {\n                        session.close();\n                    }\n                }\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 获取Session\n     *\n     * @return\n     */\n    public static SqlSession getSqlSession() {\n        return sqlSessionFactory.openSession();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/util/MybatisRowBoundsHelper.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;\n\nimport org.apache.ibatis.io.Resources;\nimport org.apache.ibatis.jdbc.ScriptRunner;\nimport org.apache.ibatis.session.SqlSession;\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.apache.ibatis.session.SqlSessionFactoryBuilder;\n\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.sql.Connection;\n\n/**\n * Description: MybatisHelper\n * Author: liuzh\n * Update: liuzh(2014-06-06 13:33)\n */\npublic class MybatisRowBoundsHelper {\n\n    private static SqlSessionFactory sqlSessionFactory;\n\n    static {\n        try {\n            //创建SqlSessionFactory\n            Reader reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + \"/mybatis-config-rowbounds.xml\");\n            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);\n            reader.close();\n            if (TestUtil.getXmlPath().equalsIgnoreCase(\"hsqldb\")\n                    || TestUtil.getXmlPath().equalsIgnoreCase(\"h2\")\n                    || TestUtil.getXmlPath().equalsIgnoreCase(\"derby\")) {\n                //创建数据库\n                SqlSession session = null;\n                try {\n                    session = sqlSessionFactory.openSession();\n                    Connection conn = session.getConnection();\n                    reader = Resources.getResourceAsReader(TestUtil.getXmlPath() + \"/\" + TestUtil.getXmlPath() + \".sql\");\n                    ScriptRunner runner = new ScriptRunner(conn);\n                    runner.setLogWriter(null);\n                    runner.runScript(reader);\n                    reader.close();\n                } finally {\n                    if (session != null) {\n                        session.close();\n                    }\n                }\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 获取Session\n     *\n     * @return\n     */\n    public static SqlSession getSqlSession() {\n        return sqlSessionFactory.openSession();\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/util/Ognl.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;/**\n * @author liuzh\n */\npublic class Ognl {\n    public static boolean isNotNull(Object obj) {\n        return obj != null;\n    }\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/util/SqlSafeUtilTest.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class SqlSafeUtilTest {\n\n\t@Test\n\tpublic void check() {\n\t\tassertSql(true, \"insert into xx\");\n\t\t// 无空格\n\t\tassertSql(false, \"insertxxinto xx\");\n\t\tassertSql(false, \"insert_into\");\n\t\tassertSql(true, \"SELECT aa FROM user\");\n\t\t// 无空格\n\t\tassertSql(true, \"SELECT*FROM user\");\n\t\t// 左空格\n\t\tassertSql(true, \"SELECT *FROM user\");\n\t\t// 右空格\n\t\tassertSql(true, \"SELECT* FROM user\");\n\t\t// 左tab\n\t\tassertSql(true, \"SELECT                 *FROM user\");\n\t\t// 右tab\n\t\tassertSql(true, \"SELECT*        FROM user\");\n\t\tassertSql(false, \"SELECT*FROMuser\");\n\n\t\t// 验证 issue #707 问题\n\t\tassertSql(false, \"databaseType desc,orderNum desc\");\n\t}\n\n\tprivate void assertSql(boolean injection, String sql) {\n\t\tassertEquals(injection, SqlSafeUtil.check(sql));\n\t}\n}\n"
  },
  {
    "path": "src/test/java/com/github/pagehelper/util/TestUtil.java",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2023 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\npackage com.github.pagehelper.util;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Properties;\n\n/**\n * @author liuzh\n */\npublic class TestUtil {\n    public static String XML_PATH;\n\n    public synchronized static String getXmlPath() throws IOException {\n        if (XML_PATH != null) {\n            return XML_PATH;\n        }\n        Properties properties = new Properties();\n        InputStream is = null;\n        try {\n            is = TestUtil.class.getResourceAsStream(\"/test.properties\");\n            properties.load(is);\n            XML_PATH = properties.getProperty(\"database\");\n        } finally {\n            if (is != null) {\n                is.close();\n            }\n        }\n        return XML_PATH;\n    }\n}\n"
  },
  {
    "path": "src/test/resources/cirrodata/cirrodata.sql",
    "content": "﻿/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2022 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\nCREATE\nDATABASE `pagehelper` CHARACTER\nSET 'UTF-8';\n\nCREATE USER TEST_USER identified by '123456_'\n\nDROP TABLE `user`;\n\nCREATE TABLE `user`\n(\n    `id`   int(11),\n    `name` varchar(50) DEFAULT NULL,\n    `py`   varchar(50) DEFAULT NULL\n);\n\ninsert into user(id, name, py) values('1','毕淑儒','BSR');\ninsert into user(id, name, py) values('2','蔡兴熙','CXX');\ninsert into user(id, name, py) values('3','曾三杰','ZSJ');\ninsert into user(id, name, py) values('4','常元琴','CYQ');\ninsert into user(id, name, py) values('5','陈栋芬','CDF');\ninsert into user(id, name, py) values('6','陈宁婷','CNZ');\ninsert into user(id, name, py) values('7','陈瑞','CR');\ninsert into user(id, name, py) values('8','陈武宵','CWX');\ninsert into user(id, name, py) values('9','陈晓丽','CXL');\ninsert into user(id, name, py) values('10','陈翼涛','CYT');\ninsert into user(id, name, py) values('11','陈宇然','CYR');\ninsert into user(id, name, py) values('12','陈震','CZ');\ninsert into user(id, name, py) values('13','程太君','CTJ');\ninsert into user(id, name, py) values('14','程玉娜','CYN');\ninsert into user(id, name, py) values('15','丛贺轩','CHX');\ninsert into user(id, name, py) values('16','戴国宇','DGY');\ninsert into user(id, name, py) values('17','戴杰亮','DJL');\ninsert into user(id, name, py) values('18','丁玉华','DYH');\ninsert into user(id, name, py) values('19','董秋明','DQM');\ninsert into user(id, name, py) values('20','董政厚','DZH');\ninsert into user(id, name, py) values('21','杜玉焱','DYZ');\ninsert into user(id, name, py) values('22','段瑜芝','DZZ');\ninsert into user(id, name, py) values('23','傅广友','FGY');\ninsert into user(id, name, py) values('24','傅井飞','FJF');\ninsert into user(id, name, py) values('25','高辉涛','GHT');\ninsert into user(id, name, py) values('26','高龙飞','GLF');\ninsert into user(id, name, py) values('27','高汝英','GRY');\ninsert into user(id, name, py) values('28','高云天','GYT');\ninsert into user(id, name, py) values('29','郭义民','GYM');\ninsert into user(id, name, py) values('30','郭永洪','GYH');\ninsert into user(id, name, py) values('31','韩国茜','HGZ');\ninsert into user(id, name, py) values('32','韩龙康','HLK');\ninsert into user(id, name, py) values('33','韩伟佳','HWJ');\ninsert into user(id, name, py) values('34','韩扬谦','HYQ');\ninsert into user(id, name, py) values('35','郝静生','HJS');\ninsert into user(id, name, py) values('36','何柏红','HBH');\ninsert into user(id, name, py) values('37','何彩智','HCZ');\ninsert into user(id, name, py) values('38','何陶增','HTZ');\ninsert into user(id, name, py) values('39','何薇','HZ');\ninsert into user(id, name, py) values('40','何小凡','HXF');\ninsert into user(id, name, py) values('41','何振平','HZP');\ninsert into user(id, name, py) values('42','洪彩辉','HCH');\ninsert into user(id, name, py) values('43','胡仕明','HSM');\ninsert into user(id, name, py) values('44','黄建朋','HJP');\ninsert into user(id, name, py) values('45','黄祥荣','HXR');\ninsert into user(id, name, py) values('46','黄璇平','HZP');\ninsert into user(id, name, py) values('47','贾茂飞','JMF');\ninsert into user(id, name, py) values('48','李迪茹','LDR');\ninsert into user(id, name, py) values('49','李桂博','LGB');\ninsert into user(id, name, py) values('50','李国祯','LGZ');\ninsert into user(id, name, py) values('51','李宏川','LHC');\ninsert into user(id, name, py) values('52','李梅','LM');\ninsert into user(id, name, py) values('53','李媚文','LMW');\ninsert into user(id, name, py) values('54','李孟惠','LMH');\ninsert into user(id, name, py) values('55','李南懋','LNZ');\ninsert into user(id, name, py) values('56','李鹏龙','LPL');\ninsert into user(id, name, py) values('57','李诗庸','LSY');\ninsert into user(id, name, py) values('58','李姝勇','LZY');\ninsert into user(id, name, py) values('59','李树鹏','LSP');\ninsert into user(id, name, py) values('60','李薇红','LZH');\ninsert into user(id, name, py) values('61','李文章','LWZ');\ninsert into user(id, name, py) values('62','李星佳','LXJ');\ninsert into user(id, name, py) values('63','李兴','LX');\ninsert into user(id, name, py) values('64','李秀倩','LXZ');\ninsert into user(id, name, py) values('65','李艳生','LYS');\ninsert into user(id, name, py) values('66','李燕金','LYJ');\ninsert into user(id, name, py) values('67','李玉彪','LYB');\ninsert into user(id, name, py) values('68','李振峰','LZF');\ninsert into user(id, name, py) values('69','梁斌芳','LBF');\ninsert into user(id, name, py) values('70','梁国云','LGY');\ninsert into user(id, name, py) values('71','梁巧爱','LQA');\ninsert into user(id, name, py) values('72','梁照金','LZJ');\ninsert into user(id, name, py) values('73','林婧美','LZM');\ninsert into user(id, name, py) values('74','林沛寿','LPS');\ninsert into user(id, name, py) values('75','林薇程','LZC');\ninsert into user(id, name, py) values('76','林伟玉','LWY');\ninsert into user(id, name, py) values('77','林艺玲','LYL');\ninsert into user(id, name, py) values('78','刘睿','LR');\ninsert into user(id, name, py) values('79','刘芊芊','LQQ');\ninsert into user(id, name, py) values('80','刘海波','LHB');\ninsert into user(id, name, py) values('81','刘斓琴','LZQ');\ninsert into user(id, name, py) values('82','刘磊东','LLD');\ninsert into user(id, name, py) values('83','刘明琪','LMZ');\ninsert into user(id, name, py) values('84','刘铭恩','LME');\ninsert into user(id, name, py) values('85','刘任恺','LRZ');\ninsert into user(id, name, py) values('86','刘水秋','LSQ');\ninsert into user(id, name, py) values('87','刘文萱','LWZ');\ninsert into user(id, name, py) values('88','刘祥瑶','LXY');\ninsert into user(id, name, py) values('89','刘薪坪','LXP');\ninsert into user(id, name, py) values('90','刘秀涛','LXT');\ninsert into user(id, name, py) values('91','刘彦利','LYL');\ninsert into user(id, name, py) values('92','刘益存','LYC');\ninsert into user(id, name, py) values('93','龙子苹','LZP');\ninsert into user(id, name, py) values('94','卢秀剑','LXJ');\ninsert into user(id, name, py) values('95','罗乔华','LQH');\ninsert into user(id, name, py) values('96','罗希清','LXQ');\ninsert into user(id, name, py) values('97','马家兰','MJL');\ninsert into user(id, name, py) values('98','马莲莹','MLY');\ninsert into user(id, name, py) values('99','马宁文','MNW');\ninsert into user(id, name, py) values('100','马水鹏','MSP');\ninsert into user(id, name, py) values('101','孟三云','MSY');\ninsert into user(id, name, py) values('102','孟寿云','MSY');\ninsert into user(id, name, py) values('103','聂伟元','NWY');\ninsert into user(id, name, py) values('104','潘永飞','PYF');\ninsert into user(id, name, py) values('105','彭健颖','PJY');\ninsert into user(id, name, py) values('106','钱文松','QWS');\ninsert into user(id, name, py) values('107','屈江珍','QJZ');\ninsert into user(id, name, py) values('108','邵建林','SJL');\ninsert into user(id, name, py) values('109','施家晖','SJZ');\ninsert into user(id, name, py) values('110','施艺英','SYY');\ninsert into user(id, name, py) values('111','孙常程','SCC');\ninsert into user(id, name, py) values('112','谭佳盈','TJY');\ninsert into user(id, name, py) values('113','唐春珊','TCS');\ninsert into user(id, name, py) values('114','唐军霞','TJX');\ninsert into user(id, name, py) values('115','唐里丽','TLL');\ninsert into user(id, name, py) values('116','陶姐华','TJH');\ninsert into user(id, name, py) values('117','万圻艳','WZY');\ninsert into user(id, name, py) values('118','王傲凤','WAF');\ninsert into user(id, name, py) values('119','王德英','WDY');\ninsert into user(id, name, py) values('120','王鼎华','WDH');\ninsert into user(id, name, py) values('121','王慧','WH');\ninsert into user(id, name, py) values('122','王佳光','WJG');\ninsert into user(id, name, py) values('123','王家胜','WJS');\ninsert into user(id, name, py) values('124','王竞飞','WJF');\ninsert into user(id, name, py) values('125','王科磊','WKL');\ninsert into user(id, name, py) values('126','王丽章','WLZ');\ninsert into user(id, name, py) values('127','王励苗','WLM');\ninsert into user(id, name, py) values('128','王美东','WMD');\ninsert into user(id, name, py) values('129','王美媛','WMZ');\ninsert into user(id, name, py) values('130','王蕊颖','WRY');\ninsert into user(id, name, py) values('131','王士成','WSC');\ninsert into user(id, name, py) values('132','王熙斌','WXB');\ninsert into user(id, name, py) values('133','王香军','WXJ');\ninsert into user(id, name, py) values('134','王休娜','WXN');\ninsert into user(id, name, py) values('135','王仪行','WYX');\ninsert into user(id, name, py) values('136','王赢基','WYJ');\ninsert into user(id, name, py) values('137','王云芯','WYX');\ninsert into user(id, name, py) values('138','王郑林','WZL');\ninsert into user(id, name, py) values('139','王治良','WZL');\ninsert into user(id, name, py) values('140','王忠宇','WZY');\ninsert into user(id, name, py) values('141','王子冰','WZB');\ninsert into user(id, name, py) values('142','韦新裕','WXY');\ninsert into user(id, name, py) values('143','魏复冉','WFR');\ninsert into user(id, name, py) values('144','吴翰志','WHZ');\ninsert into user(id, name, py) values('145','吴美森','WMS');\ninsert into user(id, name, py) values('146','吴翔良','WXL');\ninsert into user(id, name, py) values('147','吴艳伟','WYW');\ninsert into user(id, name, py) values('148','吴钲辉','WZH');\ninsert into user(id, name, py) values('149','向盼洛','XPL');\ninsert into user(id, name, py) values('150','萧恩','XE');\ninsert into user(id, name, py) values('151','萧军杰','XJJ');\ninsert into user(id, name, py) values('152','萧圣梅','XSM');\ninsert into user(id, name, py) values('153','谢辰吉','XCJ');\ninsert into user(id, name, py) values('154','徐郎求','XLQ');\ninsert into user(id, name, py) values('155','徐铭森','XMS');\ninsert into user(id, name, py) values('156','徐蓉伟','XRW');\ninsert into user(id, name, py) values('157','许为梧','XWW');\ninsert into user(id, name, py) values('158','阎皓河','YZH');\ninsert into user(id, name, py) values('159','阎思华','YSH');\ninsert into user(id, name, py) values('160','杨爱秀','YAX');\ninsert into user(id, name, py) values('161','杨昆飞','YKF');\ninsert into user(id, name, py) values('162','杨良林','YLL');\ninsert into user(id, name, py) values('163','杨少君','YSJ');\ninsert into user(id, name, py) values('164','杨玉丽','YYL');\ninsert into user(id, name, py) values('165','杨之安','YZA');\ninsert into user(id, name, py) values('166','尤榕锋','YZF');\ninsert into user(id, name, py) values('167','余俊珠','YJZ');\ninsert into user(id, name, py) values('168','袁江蔓','YJM');\ninsert into user(id, name, py) values('169','张必翰','ZBH');\ninsert into user(id, name, py) values('170','张昌颜','ZCY');\ninsert into user(id, name, py) values('171','张恩星','ZEX');\ninsert into user(id, name, py) values('172','张飞强','ZFQ');\ninsert into user(id, name, py) values('173','张凤焯','ZFZ');\ninsert into user(id, name, py) values('174','张国强','ZGQ');\ninsert into user(id, name, py) values('175','张计欣','ZJX');\ninsert into user(id, name, py) values('176','张家颖','ZJY');\ninsert into user(id, name, py) values('177','张金安','ZJA');\ninsert into user(id, name, py) values('178','张莉','ZL');\ninsert into user(id, name, py) values('179','张米龙','ZML');\ninsert into user(id, name, py) values('180','张善渊','ZSY');\ninsert into user(id, name, py) values('181','张万敏','ZWM');\ninsert into user(id, name, py) values('182','张晓林','ZXL');\ninsert into user(id, name, py) values('183','张秀高','ZXG');\n"
  },
  {
    "path": "src/test/resources/cirrodata/mybatis-config-pagesizezero.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"helperDialect\" value=\"xcloud\"/>\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <property name=\"pageSizeZero\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.bonc.xcloud.jdbc.XCloudDriver\"/>\n                <property name=\"url\" value=\"jdbc:xcloud:@localhost:12341/pagehelper\"/>\n                <property name=\"username\" value=\"TEST_USER\"/>\n                <property name=\"password\" value=\"\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/cirrodata/mybatis-config-reasonable.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"helperDialect\" value=\"xcloud\"/>\n            <property name=\"reasonable\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.bonc.xcloud.jdbc.XCloudDriver\"/>\n                <property name=\"url\" value=\"jdbc:xcloud:@localhost:12341/pagehelper\"/>\n                <property name=\"username\" value=\"TEST_USER\"/>\n                <property name=\"password\" value=\"\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/cirrodata/mybatis-config-rowbounds.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"helperDialect\" value=\"xcloud\"/>\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.bonc.xcloud.jdbc.XCloudDriver\"/>\n                <property name=\"url\" value=\"jdbc:xcloud:@localhost:12341/pagehelper\"/>\n                <property name=\"username\" value=\"TEST_USER\"/>\n                <property name=\"password\" value=\"\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/cirrodata/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <!-- 支持通过Mapper接口参数来传递分页参数 -->\n            <property name=\"helperDialect\" value=\"xcloud\"/>\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.bonc.xcloud.jdbc.XCloudDriver\"/>\n                <property name=\"url\" value=\"jdbc:xcloud:@localhost:12341/pagehelper\"/>\n                <property name=\"username\" value=\"TEST_USER\"/>\n                <property name=\"password\" value=\"\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/com/github/pagehelper/mapper/UserMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE mapper\n        PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n\n<mapper namespace=\"com.github.pagehelper.mapper.UserMapper\">\n    <!--    <cache/>-->\n    <select id=\"selectAll\" resultType=\"User\">\n        select * from user order by id -- comment\n    </select>\n    <select id=\"selectAll_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user\n    </select>\n\n    <select id=\"selectGreterThanId\" resultType=\"User\">\n        select * from user where id &gt;#{id} order by id -- comment\n    </select>\n    <select id=\"selectGreterThanId_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user where id &gt;#{id}\n    </select>\n\n    <select id=\"selectGreterThanIdAndNotEquelName\" resultType=\"User\">\n        select a.* from user a left join user b on a.id = b.id where a.id &gt;#{id} and b.name &lt;&gt;\n        #{name} order by a.id\n    </select>\n    <select id=\"selectGreterThanIdAndNotEquelName_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct a.id) from user a left join user b on a.id = b.id where a.id &gt;#{id} and b.name &lt;&gt;\n        #{name}\n    </select>\n\n    <select id=\"selectAllOrderby\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user order by py desc\n    </select>\n    <select id=\"selectAllOrderby_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user\n    </select>\n\n    <select id=\"selectAllOrderByParams\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user order by ${order1} desc,${order2} asc\n    </select>\n    <select id=\"selectAllOrderByParams_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user\n    </select>\n\n    <select id=\"selectAllOrderByMap\" resultType=\"com.github.pagehelper.model.User\">\n        select * from ${tableName} where id &lt;&gt; #{order1} and id &lt;&gt; #{order2} order by id\n    </select>\n    <select id=\"selectAllOrderByMap_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user where id &lt;&gt; #{order1} and id &lt;&gt; #{order2}\n    </select>\n\n    <select id=\"selectAllOrderByList\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user where id not in\n        <foreach collection=\"list\" item=\"par\" separator=\",\" open=\"(\" close=\")\">\n            #{par}\n        </foreach>\n        order by id\n    </select>\n    <select id=\"selectAllOrderByList_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user where id not in\n        <foreach collection=\"list\" item=\"par\" separator=\",\" open=\"(\" close=\")\">\n            #{par}\n        </foreach>\n    </select>\n\n    <select id=\"selectAllOrderByArray\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user where id not in\n        <foreach collection=\"array\" item=\"par\" separator=\",\" open=\"(\" close=\")\">\n            #{par}\n        </foreach>\n        order by id\n    </select>\n    <select id=\"selectAllOrderByArray_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user where id not in\n        <foreach collection=\"array\" item=\"par\" separator=\",\" open=\"(\" close=\")\">\n            #{par}\n        </foreach>\n    </select>\n\n    <select id=\"selectIf\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user\n        <if test=\"@com.github.pagehelper.util.Ognl@isNotNull(id)\">\n            <!--<if test=\"id!=null\">-->\n            where id &gt; #{id}\n        </if>\n        order by id\n    </select>\n    <select id=\"selectIf_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user\n        <if test=\"@com.github.pagehelper.util.Ognl@isNotNull(id)\">\n            <!--<if test=\"id!=null\">-->\n            where id &gt; #{id}\n        </if>\n    </select>\n\n    <select id=\"selectIf3\" parameterType=\"User\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user\n        <if test=\"id > 0\">\n            where id &gt; #{id}\n        </if>\n        order by id\n    </select>\n    <select id=\"selectIf3_TESTCOUNT\" parameterType=\"User\" resultType=\"Long\">\n        select count(distinct id) from user\n        <if test=\"id > 0\">\n            where id &gt; #{id}\n        </if>\n    </select>\n\n    <select id=\"selectIf2\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user where id &gt; #{id1}\n        <if test=\"id2!=null\">\n            and id &gt; #{id2}\n        </if>\n    </select>\n    <select id=\"selectIf2_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user where id &gt; #{id1}\n        <if test=\"id2!=null\">\n            and id &gt; #{id2}\n        </if>\n    </select>\n\n    <select id=\"selectIf2List\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user\n        <where>\n            <if test=\"id1!=null and id1.size>0\">\n                id not in\n                <foreach collection=\"id1\" item=\"id\" open=\"(\" close=\")\" separator=\",\">\n                    #{id}\n                </foreach>\n            </if>\n            <if test=\"id2!=null and id2.size>0\">\n                and id not in\n                <foreach collection=\"id2\" item=\"id\" open=\"(\" close=\")\" separator=\",\">\n                    #{id}\n                </foreach>\n            </if>\n        </where>\n        order by id\n    </select>\n    <select id=\"selectIf2List_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user\n        <where>\n            <if test=\"id1!=null and id1.size>0\">\n                id not in\n                <foreach collection=\"id1\" item=\"id\" open=\"(\" close=\")\" separator=\",\">\n                    #{id}\n                </foreach>\n            </if>\n            <if test=\"id2!=null and id2.size>0\">\n                and id not in\n                <foreach collection=\"id2\" item=\"id\" open=\"(\" close=\")\" separator=\",\">\n                    #{id}\n                </foreach>\n            </if>\n        </where>\n    </select>\n\n    <select id=\"selectIf2ListAndOrder\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user\n        <where>\n            <if test=\"id1!=null and id1.size>0\">\n                id not in\n                <foreach collection=\"id1\" item=\"id\" open=\"(\" close=\")\" separator=\",\">\n                    #{id}\n                </foreach>\n            </if>\n            <if test=\"id2!=null and id2.size>0\">\n                and id not in\n                <foreach collection=\"id2\" item=\"id\" open=\"(\" close=\")\" separator=\",\">\n                    #{id}\n                </foreach>\n            </if>\n        </where>\n        <if test=\"order!=null and order!=''\">\n            order by ${order}\n        </if>\n        <if test=\"order==null or order==''\">\n            order by id\n        </if>\n    </select>\n    <select id=\"selectIf2ListAndOrder_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user\n        <where>\n            <if test=\"id1!=null and id1.size>0\">\n                id not in\n                <foreach collection=\"id1\" item=\"id\" open=\"(\" close=\")\" separator=\",\">\n                    #{id}\n                </foreach>\n            </if>\n            <if test=\"id2!=null and id2.size>0\">\n                and id not in\n                <foreach collection=\"id2\" item=\"id\" open=\"(\" close=\")\" separator=\",\">\n                    #{id}\n                </foreach>\n            </if>\n        </where>\n    </select>\n\n    <select id=\"selectChoose\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user\n        <where>\n            <choose>\n                <when test=\"id1!=null\">\n                    id &lt;&gt; #{id1}\n                </when>\n                <otherwise>\n                    and id &lt;&gt; #{id2}\n                </otherwise>\n            </choose>\n        </where>\n        order by id\n    </select>\n    <select id=\"selectChoose_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user\n        <where>\n            <choose>\n                <when test=\"id1!=null\">\n                    id &lt;&gt; #{id1}\n                </when>\n                <otherwise>\n                    and id &lt;&gt; #{id2}\n                </otherwise>\n            </choose>\n        </where>\n    </select>\n\n    <select id=\"selectLike\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user where 1=1\n        <if test=\"name!=null and name!=''\">\n            and lower(name) like '%${name}%'\n        </if>\n        order by id\n    </select>\n    <select id=\"selectLike_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user where 1=1\n        <if test=\"name!=null and name!=''\">\n            and lower(name) like '%${name}%'\n        </if>\n    </select>\n\n    <select id=\"selectByMap\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user where 1=1\n        <if test=\"name!=null and name !=''\">\n            and name= #{name}\n        </if>\n        <if test=\"py!=null and py !=''\">\n            and py= #{py}\n        </if>\n    </select>\n    <select id=\"selectByMap_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user where 1=1\n        <if test=\"name!=null and name !=''\">\n            and name= #{name}\n        </if>\n        <if test=\"py!=null and py !=''\">\n            and py= #{py}\n        </if>\n    </select>\n\n    <select id=\"selectByOrder2\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user order by ${order}\n    </select>\n    <select id=\"selectByOrder2_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user\n    </select>\n\n    <select id=\"selectUnion\" resultType=\"com.github.pagehelper.model.User\">\n        select id,name,py from user where id &gt;180\n        union\n        select id,name,py from user where id &lt;=10 order by id\n    </select>\n    <select id=\"selectUnion_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from (\n        select id,name,py from user where id &gt;180\n        union\n        select id,name,py from user where id &lt;=10) temp\n    </select>\n\n    <select id=\"selectLeftjoin\" resultType=\"com.github.pagehelper.model.User\">\n        select a.id,b.name,a.py from user a\n        left join user b on a.id = b.id\n        order by a.id\n    </select>\n    <select id=\"selectLeftjoin_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct a.id) from user a\n        left join user b on a.id = b.id\n    </select>\n\n    <select id=\"selectWith\" resultType=\"com.github.pagehelper.model.User\">\n        with rs as (select id from user where id>150) select * from user where id in (select * from rs) order by\n        id\n    </select>\n    <select id=\"selectWith_TESTCOUNT\" resultType=\"Long\">\n        with rs as (select id from user where id>150) select count(distinct id) from user where id in (select * from rs)\n    </select>\n\n    <!--select column中包含参数时-->\n    <select id=\"selectColumns\" resultType=\"com.github.pagehelper.model.User\">\n        select\n        <if test=\"columns==null or columns.length == 0\">\n            *\n        </if>\n        <if test=\"columns!=null and columns.length > 0\">\n            <foreach collection=\"columns\" item=\"column\" separator=\",\">\n                ${column}\n            </foreach>\n        </if>\n        from user order by id\n    </select>\n    <!--select column中包含参数时-->\n    <select id=\"selectColumns_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user\n    </select>\n\n    <select id=\"selectMULId\" resultType=\"com.github.pagehelper.model.User\">\n        select id * #{mul} as id,name,py from user order by id\n    </select>\n    <select id=\"selectMULId_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user\n    </select>\n\n    <select id=\"selectGroupBy\" resultType=\"com.github.pagehelper.model.User\">\n        /*keep orderby*/select name,py,count(id) id from user\n        group by name,py\n        order by name,py\n    </select>\n    <select id=\"selectGroupBy_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct name) from (\n        select name,py,count(id) id from user\n        group by name,py\n        order by name,py) as temp\n    </select>\n\n    <select id=\"selectByWhereMap\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user\n        <where>\n            <foreach collection=\"map\" item=\"val\" index=\"key\" separator=\"and\">\n                ${key} = #{val}\n            </foreach>\n        </where>\n        order by id\n    </select>\n    <select id=\"selectByWhereMap_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user\n        <where>\n            <foreach collection=\"map\" item=\"val\" index=\"key\" separator=\"and\">\n                ${key} = #{val}\n            </foreach>\n        </where>\n    </select>\n\n    <sql id=\"Example_Where_Clause\">\n        <where>\n            <foreach collection=\"oredCriteria\" item=\"criteria\" separator=\"or\">\n                <if test=\"criteria.valid\">\n                    <trim prefix=\"(\" suffix=\")\" prefixOverrides=\"and\">\n                        <foreach collection=\"criteria.criteria\" item=\"criterion\">\n                            <choose>\n                                <when test=\"criterion.noValue\">\n                                    and ${criterion.condition}\n                                </when>\n                                <when test=\"criterion.singleValue\">\n                                    and ${criterion.condition} #{criterion.value}\n                                </when>\n                                <when test=\"criterion.betweenValue\">\n                                    and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}\n                                </when>\n                                <when test=\"criterion.listValue\">\n                                    and ${criterion.condition}\n                                    <foreach collection=\"criterion.value\" item=\"listItem\" open=\"(\" close=\")\"\n                                             separator=\",\">\n                                        #{listItem}\n                                    </foreach>\n                                </when>\n                            </choose>\n                        </foreach>\n                    </trim>\n                </if>\n            </foreach>\n        </where>\n    </sql>\n\n    <select id=\"selectByExample\" resultType=\"com.github.pagehelper.model.User\"\n            parameterType=\"com.github.pagehelper.model.UserExample\">\n        select\n        <if test=\"distinct\">\n            distinct\n        </if>\n        Id, name, py\n        from user\n        <if test=\"_parameter != null\">\n            <include refid=\"Example_Where_Clause\"/>\n        </if>\n        <if test=\"orderByClause != null\">\n            order by ${orderByClause}\n        </if>\n        <if test=\"orderByClause == null\">\n            order by id\n        </if>\n    </select>\n    <select id=\"selectByExample_TESTCOUNT\" resultType=\"Long\"\n            parameterType=\"com.github.pagehelper.model.UserExample\">\n        select\n        count(\n        <if test=\"distinct\">\n            distinct\n        </if>\n        Id)\n        from user\n        <if test=\"_parameter != null\">\n            <include refid=\"Example_Where_Clause\"/>\n        </if>\n    </select>\n\n    <select id=\"selectDistinct\" resultType=\"com.github.pagehelper.model.User\">\n        select distinct SUBSTR(name,1,1) name from user\n    </select>\n    <select id=\"selectDistinct_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct SUBSTR(name,1,1)) from user\n    </select>\n\n    <select id=\"selectExists\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user a where exists(select 1 from user b where a.id = b.id and b.id >100)\n    </select>\n    <select id=\"selectExists_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user a where exists(select 1 from user b where a.id = b.id and b.id >100)\n    </select>\n\n    <select id=\"select1\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user a where 1=1\n        <if test=\"user!=null and user.name !=null and user.name!=null\">\n            and name = #{user.name}\n        </if>\n    </select>\n    <select id=\"select1_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user a where 1=1\n        <if test=\"user!=null and user.name !=null and user.name!=null\">\n            and name = #{user.name}\n        </if>\n    </select>\n\n    <select id=\"selectByPageNumSize\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user\n    </select>\n    <select id=\"selectByPageNumSize_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user\n    </select>\n\n    <select id=\"selectByPageNumSizeOrderBy\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user\n    </select>\n    <select id=\"selectByPageNumSizeOrderBy_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user\n    </select>\n\n    <select id=\"selectByOrderBy\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user\n    </select>\n    <select id=\"selectByOrderBy_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user\n    </select>\n\n    <select id=\"selectByQueryModel\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user\n    </select>\n    <select id=\"selectByQueryModel_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user\n    </select>\n\n    <select id=\"selectByIdList\" resultType=\"com.github.pagehelper.model.User\">\n        select * from user\n        <if test=\"idList != null and idList.size()>0\">\n            where id in\n            <foreach collection=\"idList\" item=\"id\" open=\"(\" close=\")\" separator=\",\">\n                #{id}\n            </foreach>\n        </if>\n    </select>\n    <select id=\"selectByIdList_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user\n        <if test=\"idList != null and idList.size()>0\">\n            where id in\n            <foreach collection=\"idList\" item=\"id\" open=\"(\" close=\")\" separator=\",\">\n              #{id}\n            </foreach>\n        </if>\n    </select>\n\n    <select id=\"selectByIdList2\" resultType=\"com.github.pagehelper.model.User\">\n        <foreach collection=\"idList\" item=\"id\" separator=\"union all\">\n            select * from user where id = #{id}\n        </foreach>\n    </select>\n    <select id=\"selectByIdList2_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from(\n        <foreach collection=\"idList\" item=\"id\" separator=\"union all\">\n            select * from user where id = #{id}\n        </foreach>\n        ) temp\n    </select>\n\n    <select id=\"execute\" resultType=\"map\">\n        ${sql}\n    </select>\n\n    <resultMap id=\"collectionMap\" type=\"com.github.pagehelper.model.User\">\n        <id column=\"id\" property=\"id\"/>\n        <collection property=\"users\" column=\"{id=id}\" ofType=\"com.github.pagehelper.model.User\"\n                    select=\"selectGreterThanId\"/>\n    </resultMap>\n\n    <select id=\"selectCollectionMap\" resultMap=\"collectionMap\">\n        select * from user\n    </select>\n    <select id=\"selectCollectionMap_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user\n    </select>\n\n    <resultMap id=\"codeMap\" type=\"com.github.pagehelper.model.UserCode\">\n        <id column=\"id\" property=\"id\"/>\n        <result column=\"py\" property=\"py\" typeHandler=\"org.apache.ibatis.type.EnumTypeHandler\"/>\n    </resultMap>\n\n    <select id=\"selectByCode\" resultMap=\"codeMap\">\n        select * from user where py = #{code, typeHandler=org.apache.ibatis.type.EnumTypeHandler}\n    </select>\n    <select id=\"selectByCode_TESTCOUNT\" resultType=\"Long\">\n        select count(distinct id) from user where py = #{code, typeHandler=org.apache.ibatis.type.EnumTypeHandler}\n    </select>\n    <!-- 数据来源：https://github.com/datacharmer/test_db -->\n    <select id=\"selectEmployees\" resultType=\"map\">\n        select d.dept_name , e.emp_no ,e.first_name ,e.last_name ,e.gender , e.hire_date , s.from_date ,s.to_date\n        ,s.salary\n        from employees e\n        inner join dept_emp de on e.emp_no = de.emp_no\n        inner join departments d on de.dept_no = d.dept_no\n        left join salaries s on e.emp_no = s.emp_no\n        order by d.dept_name , e.emp_no, s.from_date\n    </select>\n    <select id=\"selectEmployees2\" resultType=\"map\">\n        select e.emp_no ,e.first_name ,e.last_name ,e.gender , e.hire_date , s.from_date ,s.to_date ,s.salary\n        from employees e\n        inner join dept_emp de on e.emp_no = de.emp_no\n        left join salaries s on e.emp_no = s.emp_no\n        order by e.emp_no, s.from_date\n    </select>\n\n    <!-- Test for issue #868: ORDER BY with parameter binding -->\n    <select id=\"selectOrderByWithParam\" resultType=\"com.github.pagehelper.model.User\">\n        select *\n        from user\n        order by CASE WHEN py = #{py} THEN 0 ELSE 1 END, id\n    </select>\n</mapper>\n"
  },
  {
    "path": "src/test/resources/db2/mybatis-config-pagesizezero.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <property name=\"pageSizeZero\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.ibm.db2.jcc.DB2Driver\"/>\n                <property name=\"url\" value=\"jdbc:db2://192.168.16.141:50000/SAMPLE\"/>\n                <property name=\"username\" value=\"mybatis\"/>\n                <property name=\"password\" value=\"jj\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/db2/mybatis-config-reasonable.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"reasonable\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.ibm.db2.jcc.DB2Driver\"/>\n                <property name=\"url\" value=\"jdbc:db2://192.168.16.141:50000/SAMPLE\"/>\n                <property name=\"username\" value=\"mybatis\"/>\n                <property name=\"password\" value=\"jj\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/db2/mybatis-config-rowbounds.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.ibm.db2.jcc.DB2Driver\"/>\n                <property name=\"url\" value=\"jdbc:db2://192.168.16.141:50000/SAMPLE\"/>\n                <property name=\"username\" value=\"mybatis\"/>\n                <property name=\"password\" value=\"jj\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/db2/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <!-- 支持通过Mapper接口参数来传递分页参数 -->\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.ibm.db2.jcc.DB2Driver\"/>\n                <property name=\"url\" value=\"jdbc:db2://192.168.16.141:50000/SAMPLE\"/>\n                <property name=\"username\" value=\"mybatis\"/>\n                <property name=\"password\" value=\"jj\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/derby/derby.sql",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2022 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\ndrop table user;\n\ncreate table user\n(\n    id   integer,\n    name varchar(32),\n    py   varchar(5)\n);\n\ninsert into user(id, name, py)\nvalues ('1', '毕淑儒', 'BSR');\ninsert into user(id, name, py) values('2','蔡兴熙','CXX');\ninsert into user(id, name, py) values('3','曾三杰','ZSJ');\ninsert into user(id, name, py) values('4','常元琴','CYQ');\ninsert into user(id, name, py) values('5','陈栋芬','CDF');\ninsert into user(id, name, py) values('6','陈宁婷','CNZ');\ninsert into user(id, name, py) values('7','陈瑞','CR');\ninsert into user(id, name, py) values('8','陈武宵','CWX');\ninsert into user(id, name, py) values('9','陈晓丽','CXL');\ninsert into user(id, name, py) values('10','陈翼涛','CYT');\ninsert into user(id, name, py) values('11','陈宇然','CYR');\ninsert into user(id, name, py) values('12','陈震','CZ');\ninsert into user(id, name, py) values('13','程太君','CTJ');\ninsert into user(id, name, py) values('14','程玉娜','CYN');\ninsert into user(id, name, py) values('15','丛贺轩','CHX');\ninsert into user(id, name, py) values('16','戴国宇','DGY');\ninsert into user(id, name, py) values('17','戴杰亮','DJL');\ninsert into user(id, name, py) values('18','丁玉华','DYH');\ninsert into user(id, name, py) values('19','董秋明','DQM');\ninsert into user(id, name, py) values('20','董政厚','DZH');\ninsert into user(id, name, py) values('21','杜玉焱','DYZ');\ninsert into user(id, name, py) values('22','段瑜芝','DZZ');\ninsert into user(id, name, py) values('23','傅广友','FGY');\ninsert into user(id, name, py) values('24','傅井飞','FJF');\ninsert into user(id, name, py) values('25','高辉涛','GHT');\ninsert into user(id, name, py) values('26','高龙飞','GLF');\ninsert into user(id, name, py) values('27','高汝英','GRY');\ninsert into user(id, name, py) values('28','高云天','GYT');\ninsert into user(id, name, py) values('29','郭义民','GYM');\ninsert into user(id, name, py) values('30','郭永洪','GYH');\ninsert into user(id, name, py) values('31','韩国茜','HGZ');\ninsert into user(id, name, py) values('32','韩龙康','HLK');\ninsert into user(id, name, py) values('33','韩伟佳','HWJ');\ninsert into user(id, name, py) values('34','韩扬谦','HYQ');\ninsert into user(id, name, py) values('35','郝静生','HJS');\ninsert into user(id, name, py) values('36','何柏红','HBH');\ninsert into user(id, name, py) values('37','何彩智','HCZ');\ninsert into user(id, name, py) values('38','何陶增','HTZ');\ninsert into user(id, name, py) values('39','何薇','HZ');\ninsert into user(id, name, py) values('40','何小凡','HXF');\ninsert into user(id, name, py) values('41','何振平','HZP');\ninsert into user(id, name, py) values('42','洪彩辉','HCH');\ninsert into user(id, name, py) values('43','胡仕明','HSM');\ninsert into user(id, name, py) values('44','黄建朋','HJP');\ninsert into user(id, name, py) values('45','黄祥荣','HXR');\ninsert into user(id, name, py) values('46','黄璇平','HZP');\ninsert into user(id, name, py) values('47','贾茂飞','JMF');\ninsert into user(id, name, py) values('48','李迪茹','LDR');\ninsert into user(id, name, py) values('49','李桂博','LGB');\ninsert into user(id, name, py) values('50','李国祯','LGZ');\ninsert into user(id, name, py) values('51','李宏川','LHC');\ninsert into user(id, name, py) values('52','李梅','LM');\ninsert into user(id, name, py) values('53','李媚文','LMW');\ninsert into user(id, name, py) values('54','李孟惠','LMH');\ninsert into user(id, name, py) values('55','李南懋','LNZ');\ninsert into user(id, name, py) values('56','李鹏龙','LPL');\ninsert into user(id, name, py) values('57','李诗庸','LSY');\ninsert into user(id, name, py) values('58','李姝勇','LZY');\ninsert into user(id, name, py) values('59','李树鹏','LSP');\ninsert into user(id, name, py) values('60','李薇红','LZH');\ninsert into user(id, name, py) values('61','李文章','LWZ');\ninsert into user(id, name, py) values('62','李星佳','LXJ');\ninsert into user(id, name, py) values('63','李兴','LX');\ninsert into user(id, name, py) values('64','李秀倩','LXZ');\ninsert into user(id, name, py) values('65','李艳生','LYS');\ninsert into user(id, name, py) values('66','李燕金','LYJ');\ninsert into user(id, name, py) values('67','李玉彪','LYB');\ninsert into user(id, name, py) values('68','李振峰','LZF');\ninsert into user(id, name, py) values('69','梁斌芳','LBF');\ninsert into user(id, name, py) values('70','梁国云','LGY');\ninsert into user(id, name, py) values('71','梁巧爱','LQA');\ninsert into user(id, name, py) values('72','梁照金','LZJ');\ninsert into user(id, name, py) values('73','林婧美','LZM');\ninsert into user(id, name, py) values('74','林沛寿','LPS');\ninsert into user(id, name, py) values('75','林薇程','LZC');\ninsert into user(id, name, py) values('76','林伟玉','LWY');\ninsert into user(id, name, py) values('77','林艺玲','LYL');\ninsert into user(id, name, py) values('78','刘睿','LR');\ninsert into user(id, name, py) values('79','刘芊芊','LQQ');\ninsert into user(id, name, py) values('80','刘海波','LHB');\ninsert into user(id, name, py) values('81','刘斓琴','LZQ');\ninsert into user(id, name, py) values('82','刘磊东','LLD');\ninsert into user(id, name, py) values('83','刘明琪','LMZ');\ninsert into user(id, name, py) values('84','刘铭恩','LME');\ninsert into user(id, name, py) values('85','刘任恺','LRZ');\ninsert into user(id, name, py) values('86','刘水秋','LSQ');\ninsert into user(id, name, py) values('87','刘文萱','LWZ');\ninsert into user(id, name, py) values('88','刘祥瑶','LXY');\ninsert into user(id, name, py) values('89','刘薪坪','LXP');\ninsert into user(id, name, py) values('90','刘秀涛','LXT');\ninsert into user(id, name, py) values('91','刘彦利','LYL');\ninsert into user(id, name, py) values('92','刘益存','LYC');\ninsert into user(id, name, py) values('93','龙子苹','LZP');\ninsert into user(id, name, py) values('94','卢秀剑','LXJ');\ninsert into user(id, name, py) values('95','罗乔华','LQH');\ninsert into user(id, name, py) values('96','罗希清','LXQ');\ninsert into user(id, name, py) values('97','马家兰','MJL');\ninsert into user(id, name, py) values('98','马莲莹','MLY');\ninsert into user(id, name, py) values('99','马宁文','MNW');\ninsert into user(id, name, py) values('100','马水鹏','MSP');\ninsert into user(id, name, py) values('101','孟三云','MSY');\ninsert into user(id, name, py) values('102','孟寿云','MSY');\ninsert into user(id, name, py) values('103','聂伟元','NWY');\ninsert into user(id, name, py) values('104','潘永飞','PYF');\ninsert into user(id, name, py) values('105','彭健颖','PJY');\ninsert into user(id, name, py) values('106','钱文松','QWS');\ninsert into user(id, name, py) values('107','屈江珍','QJZ');\ninsert into user(id, name, py) values('108','邵建林','SJL');\ninsert into user(id, name, py) values('109','施家晖','SJZ');\ninsert into user(id, name, py) values('110','施艺英','SYY');\ninsert into user(id, name, py) values('111','孙常程','SCC');\ninsert into user(id, name, py) values('112','谭佳盈','TJY');\ninsert into user(id, name, py) values('113','唐春珊','TCS');\ninsert into user(id, name, py) values('114','唐军霞','TJX');\ninsert into user(id, name, py) values('115','唐里丽','TLL');\ninsert into user(id, name, py) values('116','陶姐华','TJH');\ninsert into user(id, name, py) values('117','万圻艳','WZY');\ninsert into user(id, name, py) values('118','王傲凤','WAF');\ninsert into user(id, name, py) values('119','王德英','WDY');\ninsert into user(id, name, py) values('120','王鼎华','WDH');\ninsert into user(id, name, py) values('121','王慧','WH');\ninsert into user(id, name, py) values('122','王佳光','WJG');\ninsert into user(id, name, py) values('123','王家胜','WJS');\ninsert into user(id, name, py) values('124','王竞飞','WJF');\ninsert into user(id, name, py) values('125','王科磊','WKL');\ninsert into user(id, name, py) values('126','王丽章','WLZ');\ninsert into user(id, name, py) values('127','王励苗','WLM');\ninsert into user(id, name, py) values('128','王美东','WMD');\ninsert into user(id, name, py) values('129','王美媛','WMZ');\ninsert into user(id, name, py) values('130','王蕊颖','WRY');\ninsert into user(id, name, py) values('131','王士成','WSC');\ninsert into user(id, name, py) values('132','王熙斌','WXB');\ninsert into user(id, name, py) values('133','王香军','WXJ');\ninsert into user(id, name, py) values('134','王休娜','WXN');\ninsert into user(id, name, py) values('135','王仪行','WYX');\ninsert into user(id, name, py) values('136','王赢基','WYJ');\ninsert into user(id, name, py) values('137','王云芯','WYX');\ninsert into user(id, name, py) values('138','王郑林','WZL');\ninsert into user(id, name, py) values('139','王治良','WZL');\ninsert into user(id, name, py) values('140','王忠宇','WZY');\ninsert into user(id, name, py) values('141','王子冰','WZB');\ninsert into user(id, name, py) values('142','韦新裕','WXY');\ninsert into user(id, name, py) values('143','魏复冉','WFR');\ninsert into user(id, name, py) values('144','吴翰志','WHZ');\ninsert into user(id, name, py) values('145','吴美森','WMS');\ninsert into user(id, name, py) values('146','吴翔良','WXL');\ninsert into user(id, name, py) values('147','吴艳伟','WYW');\ninsert into user(id, name, py) values('148','吴钲辉','WZH');\ninsert into user(id, name, py) values('149','向盼洛','XPL');\ninsert into user(id, name, py) values('150','萧恩','XE');\ninsert into user(id, name, py) values('151','萧军杰','XJJ');\ninsert into user(id, name, py) values('152','萧圣梅','XSM');\ninsert into user(id, name, py) values('153','谢辰吉','XCJ');\ninsert into user(id, name, py) values('154','徐郎求','XLQ');\ninsert into user(id, name, py) values('155','徐铭森','XMS');\ninsert into user(id, name, py) values('156','徐蓉伟','XRW');\ninsert into user(id, name, py) values('157','许为梧','XWW');\ninsert into user(id, name, py) values('158','阎皓河','YZH');\ninsert into user(id, name, py) values('159','阎思华','YSH');\ninsert into user(id, name, py) values('160','杨爱秀','YAX');\ninsert into user(id, name, py) values('161','杨昆飞','YKF');\ninsert into user(id, name, py) values('162','杨良林','YLL');\ninsert into user(id, name, py) values('163','杨少君','YSJ');\ninsert into user(id, name, py) values('164','杨玉丽','YYL');\ninsert into user(id, name, py) values('165','杨之安','YZA');\ninsert into user(id, name, py) values('166','尤榕锋','YZF');\ninsert into user(id, name, py) values('167','余俊珠','YJZ');\ninsert into user(id, name, py) values('168','袁江蔓','YJM');\ninsert into user(id, name, py) values('169','张必翰','ZBH');\ninsert into user(id, name, py) values('170','张昌颜','ZCY');\ninsert into user(id, name, py) values('171','张恩星','ZEX');\ninsert into user(id, name, py) values('172','张飞强','ZFQ');\ninsert into user(id, name, py) values('173','张凤焯','ZFZ');\ninsert into user(id, name, py) values('174','张国强','ZGQ');\ninsert into user(id, name, py) values('175','张计欣','ZJX');\ninsert into user(id, name, py) values('176','张家颖','ZJY');\ninsert into user(id, name, py) values('177','张金安','ZJA');\ninsert into user(id, name, py) values('178','张莉','ZL');\ninsert into user(id, name, py) values('179','张米龙','ZML');\ninsert into user(id, name, py) values('180','张善渊','ZSY');\ninsert into user(id, name, py) values('181','张万敏','ZWM');\ninsert into user(id, name, py) values('182','张晓林','ZXL');\ninsert into user(id, name, py) values('183','张秀高','ZXG');\n\n"
  },
  {
    "path": "src/test/resources/derby/mybatis-config-pagesizezero.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <property name=\"pageSizeZero\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.apache.derby.jdbc.EmbeddedDriver\"/>\n                <property name=\"url\" value=\"jdbc:derby:ibderby2;create=true\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/derby/mybatis-config-reasonable.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"reasonable\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.apache.derby.jdbc.EmbeddedDriver\"/>\n                <property name=\"url\" value=\"jdbc:derby:ibderby3;create=true\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/derby/mybatis-config-rowbounds.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.apache.derby.jdbc.EmbeddedDriver\"/>\n                <property name=\"url\" value=\"jdbc:derby:ibderby4;create=true\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/derby/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <!-- 支持通过Mapper接口参数来传递分页参数 -->\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.apache.derby.jdbc.EmbeddedDriver\"/>\n                <property name=\"url\" value=\"jdbc:derby:ibderby1;create=true\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/h2/h2.sql",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2022 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\ndrop table user if exists;\n\ncreate table user\n(\n    id   integer,\n    name varchar(32),\n    py   varchar(5)\n);\n\ninsert into user(id, name, py)\nvalues ('1', '毕淑儒', 'BSR');\ninsert into user(id, name, py) values('2','蔡兴熙','CXX');\ninsert into user(id, name, py) values('3','曾三杰','ZSJ');\ninsert into user(id, name, py) values('4','常元琴','CYQ');\ninsert into user(id, name, py) values('5','陈栋芬','CDF');\ninsert into user(id, name, py) values('6','陈宁婷','CNZ');\ninsert into user(id, name, py) values('7','陈瑞','CR');\ninsert into user(id, name, py) values('8','陈武宵','CWX');\ninsert into user(id, name, py) values('9','陈晓丽','CXL');\ninsert into user(id, name, py) values('10','陈翼涛','CYT');\ninsert into user(id, name, py) values('11','陈宇然','CYR');\ninsert into user(id, name, py) values('12','陈震','CZ');\ninsert into user(id, name, py) values('13','程太君','CTJ');\ninsert into user(id, name, py) values('14','程玉娜','CYN');\ninsert into user(id, name, py) values('15','丛贺轩','CHX');\ninsert into user(id, name, py) values('16','戴国宇','DGY');\ninsert into user(id, name, py) values('17','戴杰亮','DJL');\ninsert into user(id, name, py) values('18','丁玉华','DYH');\ninsert into user(id, name, py) values('19','董秋明','DQM');\ninsert into user(id, name, py) values('20','董政厚','DZH');\ninsert into user(id, name, py) values('21','杜玉焱','DYZ');\ninsert into user(id, name, py) values('22','段瑜芝','DZZ');\ninsert into user(id, name, py) values('23','傅广友','FGY');\ninsert into user(id, name, py) values('24','傅井飞','FJF');\ninsert into user(id, name, py) values('25','高辉涛','GHT');\ninsert into user(id, name, py) values('26','高龙飞','GLF');\ninsert into user(id, name, py) values('27','高汝英','GRY');\ninsert into user(id, name, py) values('28','高云天','GYT');\ninsert into user(id, name, py) values('29','郭义民','GYM');\ninsert into user(id, name, py) values('30','郭永洪','GYH');\ninsert into user(id, name, py) values('31','韩国茜','HGZ');\ninsert into user(id, name, py) values('32','韩龙康','HLK');\ninsert into user(id, name, py) values('33','韩伟佳','HWJ');\ninsert into user(id, name, py) values('34','韩扬谦','HYQ');\ninsert into user(id, name, py) values('35','郝静生','HJS');\ninsert into user(id, name, py) values('36','何柏红','HBH');\ninsert into user(id, name, py) values('37','何彩智','HCZ');\ninsert into user(id, name, py) values('38','何陶增','HTZ');\ninsert into user(id, name, py) values('39','何薇','HZ');\ninsert into user(id, name, py) values('40','何小凡','HXF');\ninsert into user(id, name, py) values('41','何振平','HZP');\ninsert into user(id, name, py) values('42','洪彩辉','HCH');\ninsert into user(id, name, py) values('43','胡仕明','HSM');\ninsert into user(id, name, py) values('44','黄建朋','HJP');\ninsert into user(id, name, py) values('45','黄祥荣','HXR');\ninsert into user(id, name, py) values('46','黄璇平','HZP');\ninsert into user(id, name, py) values('47','贾茂飞','JMF');\ninsert into user(id, name, py) values('48','李迪茹','LDR');\ninsert into user(id, name, py) values('49','李桂博','LGB');\ninsert into user(id, name, py) values('50','李国祯','LGZ');\ninsert into user(id, name, py) values('51','李宏川','LHC');\ninsert into user(id, name, py) values('52','李梅','LM');\ninsert into user(id, name, py) values('53','李媚文','LMW');\ninsert into user(id, name, py) values('54','李孟惠','LMH');\ninsert into user(id, name, py) values('55','李南懋','LNZ');\ninsert into user(id, name, py) values('56','李鹏龙','LPL');\ninsert into user(id, name, py) values('57','李诗庸','LSY');\ninsert into user(id, name, py) values('58','李姝勇','LZY');\ninsert into user(id, name, py) values('59','李树鹏','LSP');\ninsert into user(id, name, py) values('60','李薇红','LZH');\ninsert into user(id, name, py) values('61','李文章','LWZ');\ninsert into user(id, name, py) values('62','李星佳','LXJ');\ninsert into user(id, name, py) values('63','李兴','LX');\ninsert into user(id, name, py) values('64','李秀倩','LXZ');\ninsert into user(id, name, py) values('65','李艳生','LYS');\ninsert into user(id, name, py) values('66','李燕金','LYJ');\ninsert into user(id, name, py) values('67','李玉彪','LYB');\ninsert into user(id, name, py) values('68','李振峰','LZF');\ninsert into user(id, name, py) values('69','梁斌芳','LBF');\ninsert into user(id, name, py) values('70','梁国云','LGY');\ninsert into user(id, name, py) values('71','梁巧爱','LQA');\ninsert into user(id, name, py) values('72','梁照金','LZJ');\ninsert into user(id, name, py) values('73','林婧美','LZM');\ninsert into user(id, name, py) values('74','林沛寿','LPS');\ninsert into user(id, name, py) values('75','林薇程','LZC');\ninsert into user(id, name, py) values('76','林伟玉','LWY');\ninsert into user(id, name, py) values('77','林艺玲','LYL');\ninsert into user(id, name, py) values('78','刘睿','LR');\ninsert into user(id, name, py) values('79','刘芊芊','LQQ');\ninsert into user(id, name, py) values('80','刘海波','LHB');\ninsert into user(id, name, py) values('81','刘斓琴','LZQ');\ninsert into user(id, name, py) values('82','刘磊东','LLD');\ninsert into user(id, name, py) values('83','刘明琪','LMZ');\ninsert into user(id, name, py) values('84','刘铭恩','LME');\ninsert into user(id, name, py) values('85','刘任恺','LRZ');\ninsert into user(id, name, py) values('86','刘水秋','LSQ');\ninsert into user(id, name, py) values('87','刘文萱','LWZ');\ninsert into user(id, name, py) values('88','刘祥瑶','LXY');\ninsert into user(id, name, py) values('89','刘薪坪','LXP');\ninsert into user(id, name, py) values('90','刘秀涛','LXT');\ninsert into user(id, name, py) values('91','刘彦利','LYL');\ninsert into user(id, name, py) values('92','刘益存','LYC');\ninsert into user(id, name, py) values('93','龙子苹','LZP');\ninsert into user(id, name, py) values('94','卢秀剑','LXJ');\ninsert into user(id, name, py) values('95','罗乔华','LQH');\ninsert into user(id, name, py) values('96','罗希清','LXQ');\ninsert into user(id, name, py) values('97','马家兰','MJL');\ninsert into user(id, name, py) values('98','马莲莹','MLY');\ninsert into user(id, name, py) values('99','马宁文','MNW');\ninsert into user(id, name, py) values('100','马水鹏','MSP');\ninsert into user(id, name, py) values('101','孟三云','MSY');\ninsert into user(id, name, py) values('102','孟寿云','MSY');\ninsert into user(id, name, py) values('103','聂伟元','NWY');\ninsert into user(id, name, py) values('104','潘永飞','PYF');\ninsert into user(id, name, py) values('105','彭健颖','PJY');\ninsert into user(id, name, py) values('106','钱文松','QWS');\ninsert into user(id, name, py) values('107','屈江珍','QJZ');\ninsert into user(id, name, py) values('108','邵建林','SJL');\ninsert into user(id, name, py) values('109','施家晖','SJZ');\ninsert into user(id, name, py) values('110','施艺英','SYY');\ninsert into user(id, name, py) values('111','孙常程','SCC');\ninsert into user(id, name, py) values('112','谭佳盈','TJY');\ninsert into user(id, name, py) values('113','唐春珊','TCS');\ninsert into user(id, name, py) values('114','唐军霞','TJX');\ninsert into user(id, name, py) values('115','唐里丽','TLL');\ninsert into user(id, name, py) values('116','陶姐华','TJH');\ninsert into user(id, name, py) values('117','万圻艳','WZY');\ninsert into user(id, name, py) values('118','王傲凤','WAF');\ninsert into user(id, name, py) values('119','王德英','WDY');\ninsert into user(id, name, py) values('120','王鼎华','WDH');\ninsert into user(id, name, py) values('121','王慧','WH');\ninsert into user(id, name, py) values('122','王佳光','WJG');\ninsert into user(id, name, py) values('123','王家胜','WJS');\ninsert into user(id, name, py) values('124','王竞飞','WJF');\ninsert into user(id, name, py) values('125','王科磊','WKL');\ninsert into user(id, name, py) values('126','王丽章','WLZ');\ninsert into user(id, name, py) values('127','王励苗','WLM');\ninsert into user(id, name, py) values('128','王美东','WMD');\ninsert into user(id, name, py) values('129','王美媛','WMZ');\ninsert into user(id, name, py) values('130','王蕊颖','WRY');\ninsert into user(id, name, py) values('131','王士成','WSC');\ninsert into user(id, name, py) values('132','王熙斌','WXB');\ninsert into user(id, name, py) values('133','王香军','WXJ');\ninsert into user(id, name, py) values('134','王休娜','WXN');\ninsert into user(id, name, py) values('135','王仪行','WYX');\ninsert into user(id, name, py) values('136','王赢基','WYJ');\ninsert into user(id, name, py) values('137','王云芯','WYX');\ninsert into user(id, name, py) values('138','王郑林','WZL');\ninsert into user(id, name, py) values('139','王治良','WZL');\ninsert into user(id, name, py) values('140','王忠宇','WZY');\ninsert into user(id, name, py) values('141','王子冰','WZB');\ninsert into user(id, name, py) values('142','韦新裕','WXY');\ninsert into user(id, name, py) values('143','魏复冉','WFR');\ninsert into user(id, name, py) values('144','吴翰志','WHZ');\ninsert into user(id, name, py) values('145','吴美森','WMS');\ninsert into user(id, name, py) values('146','吴翔良','WXL');\ninsert into user(id, name, py) values('147','吴艳伟','WYW');\ninsert into user(id, name, py) values('148','吴钲辉','WZH');\ninsert into user(id, name, py) values('149','向盼洛','XPL');\ninsert into user(id, name, py) values('150','萧恩','XE');\ninsert into user(id, name, py) values('151','萧军杰','XJJ');\ninsert into user(id, name, py) values('152','萧圣梅','XSM');\ninsert into user(id, name, py) values('153','谢辰吉','XCJ');\ninsert into user(id, name, py) values('154','徐郎求','XLQ');\ninsert into user(id, name, py) values('155','徐铭森','XMS');\ninsert into user(id, name, py) values('156','徐蓉伟','XRW');\ninsert into user(id, name, py) values('157','许为梧','XWW');\ninsert into user(id, name, py) values('158','阎皓河','YZH');\ninsert into user(id, name, py) values('159','阎思华','YSH');\ninsert into user(id, name, py) values('160','杨爱秀','YAX');\ninsert into user(id, name, py) values('161','杨昆飞','YKF');\ninsert into user(id, name, py) values('162','杨良林','YLL');\ninsert into user(id, name, py) values('163','杨少君','YSJ');\ninsert into user(id, name, py) values('164','杨玉丽','YYL');\ninsert into user(id, name, py) values('165','杨之安','YZA');\ninsert into user(id, name, py) values('166','尤榕锋','YZF');\ninsert into user(id, name, py) values('167','余俊珠','YJZ');\ninsert into user(id, name, py) values('168','袁江蔓','YJM');\ninsert into user(id, name, py) values('169','张必翰','ZBH');\ninsert into user(id, name, py) values('170','张昌颜','ZCY');\ninsert into user(id, name, py) values('171','张恩星','ZEX');\ninsert into user(id, name, py) values('172','张飞强','ZFQ');\ninsert into user(id, name, py) values('173','张凤焯','ZFZ');\ninsert into user(id, name, py) values('174','张国强','ZGQ');\ninsert into user(id, name, py) values('175','张计欣','ZJX');\ninsert into user(id, name, py) values('176','张家颖','ZJY');\ninsert into user(id, name, py) values('177','张金安','ZJA');\ninsert into user(id, name, py) values('178','张莉','ZL');\ninsert into user(id, name, py) values('179','张米龙','ZML');\ninsert into user(id, name, py) values('180','张善渊','ZSY');\ninsert into user(id, name, py) values('181','张万敏','ZWM');\ninsert into user(id, name, py) values('182','张晓林','ZXL');\ninsert into user(id, name, py) values('183','张秀高','ZXG');\n\n"
  },
  {
    "path": "src/test/resources/h2/mybatis-config-pagesizezero.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <property name=\"pageSizeZero\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.h2.Driver\"/>\n                <property name=\"url\" value=\"jdbc:h2:~/pagesizezero\"/>\n                <property name=\"username\" value=\"sa\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/h2/mybatis-config-reasonable.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"reasonable\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.h2.Driver\"/>\n                <property name=\"url\" value=\"jdbc:h2:~/reasonable\"/>\n                <property name=\"username\" value=\"sa\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/h2/mybatis-config-rowbounds.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.h2.Driver\"/>\n                <property name=\"url\" value=\"jdbc:h2:~/rowbounds\"/>\n                <property name=\"username\" value=\"sa\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/h2/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <!-- 支持通过Mapper接口参数来传递分页参数 -->\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.h2.Driver\"/>\n                <property name=\"url\" value=\"jdbc:h2:~/basetest\"/>\n                <property name=\"username\" value=\"sa\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/hsqldb/hsqldb.sql",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2022 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\ndrop table user if exists;\n\ncreate table user\n(\n    id   integer,\n    name varchar(32),\n    py   varchar(5)\n);\n\ninsert into user(id, name, py)\nvalues ('1', '毕淑儒', 'BSR');\ninsert into user(id, name, py) values('2','蔡兴熙','CXX');\ninsert into user(id, name, py) values('3','曾三杰','ZSJ');\ninsert into user(id, name, py) values('4','常元琴','CYQ');\ninsert into user(id, name, py) values('5','陈栋芬','CDF');\ninsert into user(id, name, py) values('6','陈宁婷','CNZ');\ninsert into user(id, name, py) values('7','陈瑞','CR');\ninsert into user(id, name, py) values('8','陈武宵','CWX');\ninsert into user(id, name, py) values('9','陈晓丽','CXL');\ninsert into user(id, name, py) values('10','陈翼涛','CYT');\ninsert into user(id, name, py) values('11','陈宇然','CYR');\ninsert into user(id, name, py) values('12','陈震','CZ');\ninsert into user(id, name, py) values('13','程太君','CTJ');\ninsert into user(id, name, py) values('14','程玉娜','CYN');\ninsert into user(id, name, py) values('15','丛贺轩','CHX');\ninsert into user(id, name, py) values('16','戴国宇','DGY');\ninsert into user(id, name, py) values('17','戴杰亮','DJL');\ninsert into user(id, name, py) values('18','丁玉华','DYH');\ninsert into user(id, name, py) values('19','董秋明','DQM');\ninsert into user(id, name, py) values('20','董政厚','DZH');\ninsert into user(id, name, py) values('21','杜玉焱','DYZ');\ninsert into user(id, name, py) values('22','段瑜芝','DZZ');\ninsert into user(id, name, py) values('23','傅广友','FGY');\ninsert into user(id, name, py) values('24','傅井飞','FJF');\ninsert into user(id, name, py) values('25','高辉涛','GHT');\ninsert into user(id, name, py) values('26','高龙飞','GLF');\ninsert into user(id, name, py) values('27','高汝英','GRY');\ninsert into user(id, name, py) values('28','高云天','GYT');\ninsert into user(id, name, py) values('29','郭义民','GYM');\ninsert into user(id, name, py) values('30','郭永洪','GYH');\ninsert into user(id, name, py) values('31','韩国茜','HGZ');\ninsert into user(id, name, py) values('32','韩龙康','HLK');\ninsert into user(id, name, py) values('33','韩伟佳','HWJ');\ninsert into user(id, name, py) values('34','韩扬谦','HYQ');\ninsert into user(id, name, py) values('35','郝静生','HJS');\ninsert into user(id, name, py) values('36','何柏红','HBH');\ninsert into user(id, name, py) values('37','何彩智','HCZ');\ninsert into user(id, name, py) values('38','何陶增','HTZ');\ninsert into user(id, name, py) values('39','何薇','HZ');\ninsert into user(id, name, py) values('40','何小凡','HXF');\ninsert into user(id, name, py) values('41','何振平','HZP');\ninsert into user(id, name, py) values('42','洪彩辉','HCH');\ninsert into user(id, name, py) values('43','胡仕明','HSM');\ninsert into user(id, name, py) values('44','黄建朋','HJP');\ninsert into user(id, name, py) values('45','黄祥荣','HXR');\ninsert into user(id, name, py) values('46','黄璇平','HZP');\ninsert into user(id, name, py) values('47','贾茂飞','JMF');\ninsert into user(id, name, py) values('48','李迪茹','LDR');\ninsert into user(id, name, py) values('49','李桂博','LGB');\ninsert into user(id, name, py) values('50','李国祯','LGZ');\ninsert into user(id, name, py) values('51','李宏川','LHC');\ninsert into user(id, name, py) values('52','李梅','LM');\ninsert into user(id, name, py) values('53','李媚文','LMW');\ninsert into user(id, name, py) values('54','李孟惠','LMH');\ninsert into user(id, name, py) values('55','李南懋','LNZ');\ninsert into user(id, name, py) values('56','李鹏龙','LPL');\ninsert into user(id, name, py) values('57','李诗庸','LSY');\ninsert into user(id, name, py) values('58','李姝勇','LZY');\ninsert into user(id, name, py) values('59','李树鹏','LSP');\ninsert into user(id, name, py) values('60','李薇红','LZH');\ninsert into user(id, name, py) values('61','李文章','LWZ');\ninsert into user(id, name, py) values('62','李星佳','LXJ');\ninsert into user(id, name, py) values('63','李兴','LX');\ninsert into user(id, name, py) values('64','李秀倩','LXZ');\ninsert into user(id, name, py) values('65','李艳生','LYS');\ninsert into user(id, name, py) values('66','李燕金','LYJ');\ninsert into user(id, name, py) values('67','李玉彪','LYB');\ninsert into user(id, name, py) values('68','李振峰','LZF');\ninsert into user(id, name, py) values('69','梁斌芳','LBF');\ninsert into user(id, name, py) values('70','梁国云','LGY');\ninsert into user(id, name, py) values('71','梁巧爱','LQA');\ninsert into user(id, name, py) values('72','梁照金','LZJ');\ninsert into user(id, name, py) values('73','林婧美','LZM');\ninsert into user(id, name, py) values('74','林沛寿','LPS');\ninsert into user(id, name, py) values('75','林薇程','LZC');\ninsert into user(id, name, py) values('76','林伟玉','LWY');\ninsert into user(id, name, py) values('77','林艺玲','LYL');\ninsert into user(id, name, py) values('78','刘睿','LR');\ninsert into user(id, name, py) values('79','刘芊芊','LQQ');\ninsert into user(id, name, py) values('80','刘海波','LHB');\ninsert into user(id, name, py) values('81','刘斓琴','LZQ');\ninsert into user(id, name, py) values('82','刘磊东','LLD');\ninsert into user(id, name, py) values('83','刘明琪','LMZ');\ninsert into user(id, name, py) values('84','刘铭恩','LME');\ninsert into user(id, name, py) values('85','刘任恺','LRZ');\ninsert into user(id, name, py) values('86','刘水秋','LSQ');\ninsert into user(id, name, py) values('87','刘文萱','LWZ');\ninsert into user(id, name, py) values('88','刘祥瑶','LXY');\ninsert into user(id, name, py) values('89','刘薪坪','LXP');\ninsert into user(id, name, py) values('90','刘秀涛','LXT');\ninsert into user(id, name, py) values('91','刘彦利','LYL');\ninsert into user(id, name, py) values('92','刘益存','LYC');\ninsert into user(id, name, py) values('93','龙子苹','LZP');\ninsert into user(id, name, py) values('94','卢秀剑','LXJ');\ninsert into user(id, name, py) values('95','罗乔华','LQH');\ninsert into user(id, name, py) values('96','罗希清','LXQ');\ninsert into user(id, name, py) values('97','马家兰','MJL');\ninsert into user(id, name, py) values('98','马莲莹','MLY');\ninsert into user(id, name, py) values('99','马宁文','MNW');\ninsert into user(id, name, py) values('100','马水鹏','MSP');\ninsert into user(id, name, py) values('101','孟三云','MSY');\ninsert into user(id, name, py) values('102','孟寿云','MSY');\ninsert into user(id, name, py) values('103','聂伟元','NWY');\ninsert into user(id, name, py) values('104','潘永飞','PYF');\ninsert into user(id, name, py) values('105','彭健颖','PJY');\ninsert into user(id, name, py) values('106','钱文松','QWS');\ninsert into user(id, name, py) values('107','屈江珍','QJZ');\ninsert into user(id, name, py) values('108','邵建林','SJL');\ninsert into user(id, name, py) values('109','施家晖','SJZ');\ninsert into user(id, name, py) values('110','施艺英','SYY');\ninsert into user(id, name, py) values('111','孙常程','SCC');\ninsert into user(id, name, py) values('112','谭佳盈','TJY');\ninsert into user(id, name, py) values('113','唐春珊','TCS');\ninsert into user(id, name, py) values('114','唐军霞','TJX');\ninsert into user(id, name, py) values('115','唐里丽','TLL');\ninsert into user(id, name, py) values('116','陶姐华','TJH');\ninsert into user(id, name, py) values('117','万圻艳','WZY');\ninsert into user(id, name, py) values('118','王傲凤','WAF');\ninsert into user(id, name, py) values('119','王德英','WDY');\ninsert into user(id, name, py) values('120','王鼎华','WDH');\ninsert into user(id, name, py) values('121','王慧','WH');\ninsert into user(id, name, py) values('122','王佳光','WJG');\ninsert into user(id, name, py) values('123','王家胜','WJS');\ninsert into user(id, name, py) values('124','王竞飞','WJF');\ninsert into user(id, name, py) values('125','王科磊','WKL');\ninsert into user(id, name, py) values('126','王丽章','WLZ');\ninsert into user(id, name, py) values('127','王励苗','WLM');\ninsert into user(id, name, py) values('128','王美东','WMD');\ninsert into user(id, name, py) values('129','王美媛','WMZ');\ninsert into user(id, name, py) values('130','王蕊颖','WRY');\ninsert into user(id, name, py) values('131','王士成','WSC');\ninsert into user(id, name, py) values('132','王熙斌','WXB');\ninsert into user(id, name, py) values('133','王香军','WXJ');\ninsert into user(id, name, py) values('134','王休娜','WXN');\ninsert into user(id, name, py) values('135','王仪行','WYX');\ninsert into user(id, name, py) values('136','王赢基','WYJ');\ninsert into user(id, name, py) values('137','王云芯','WYX');\ninsert into user(id, name, py) values('138','王郑林','WZL');\ninsert into user(id, name, py) values('139','王治良','WZL');\ninsert into user(id, name, py) values('140','王忠宇','WZY');\ninsert into user(id, name, py) values('141','王子冰','WZB');\ninsert into user(id, name, py) values('142','韦新裕','WXY');\ninsert into user(id, name, py) values('143','魏复冉','WFR');\ninsert into user(id, name, py) values('144','吴翰志','WHZ');\ninsert into user(id, name, py) values('145','吴美森','WMS');\ninsert into user(id, name, py) values('146','吴翔良','WXL');\ninsert into user(id, name, py) values('147','吴艳伟','WYW');\ninsert into user(id, name, py) values('148','吴钲辉','WZH');\ninsert into user(id, name, py) values('149','向盼洛','XPL');\ninsert into user(id, name, py) values('150','萧恩','XE');\ninsert into user(id, name, py) values('151','萧军杰','XJJ');\ninsert into user(id, name, py) values('152','萧圣梅','XSM');\ninsert into user(id, name, py) values('153','谢辰吉','XCJ');\ninsert into user(id, name, py) values('154','徐郎求','XLQ');\ninsert into user(id, name, py) values('155','徐铭森','XMS');\ninsert into user(id, name, py) values('156','徐蓉伟','XRW');\ninsert into user(id, name, py) values('157','许为梧','XWW');\ninsert into user(id, name, py) values('158','阎皓河','YZH');\ninsert into user(id, name, py) values('159','阎思华','YSH');\ninsert into user(id, name, py) values('160','杨爱秀','YAX');\ninsert into user(id, name, py) values('161','杨昆飞','YKF');\ninsert into user(id, name, py) values('162','杨良林','YLL');\ninsert into user(id, name, py) values('163','杨少君','YSJ');\ninsert into user(id, name, py) values('164','杨玉丽','YYL');\ninsert into user(id, name, py) values('165','杨之安','YZA');\ninsert into user(id, name, py) values('166','尤榕锋','YZF');\ninsert into user(id, name, py) values('167','余俊珠','YJZ');\ninsert into user(id, name, py) values('168','袁江蔓','YJM');\ninsert into user(id, name, py) values('169','张必翰','ZBH');\ninsert into user(id, name, py) values('170','张昌颜','ZCY');\ninsert into user(id, name, py) values('171','张恩星','ZEX');\ninsert into user(id, name, py) values('172','张飞强','ZFQ');\ninsert into user(id, name, py) values('173','张凤焯','ZFZ');\ninsert into user(id, name, py) values('174','张国强','ZGQ');\ninsert into user(id, name, py) values('175','张计欣','ZJX');\ninsert into user(id, name, py) values('176','张家颖','ZJY');\ninsert into user(id, name, py) values('177','张金安','ZJA');\ninsert into user(id, name, py) values('178','张莉','ZL');\ninsert into user(id, name, py) values('179','张米龙','ZML');\ninsert into user(id, name, py) values('180','张善渊','ZSY');\ninsert into user(id, name, py) values('181','张万敏','ZWM');\ninsert into user(id, name, py) values('182','张晓林','ZXL');\ninsert into user(id, name, py) values('183','张秀高','ZXG');\n"
  },
  {
    "path": "src/test/resources/hsqldb/mybatis-config-autodialect.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <!-- dialect参数可以忽略不写 -->\n            <!-- 如果需要用自己的实现方法，可以将value写成类的全限定名称 -->\n            <!-- 如下所示，该类必须继承Parser接口 -->\n            <!--<property name=\"dialect\" value=\"hsqldb\"/>-->\n            <!-- 支持通过Mapper接口参数来传递分页参数 -->\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <!-- 运行时自动判断数据库类型，支持多数据源DataSource分页 -->\n            <property name=\"autoRuntimeDialect\" value=\"true\"/>\n            <property name=\"autoDialectClass\"\n                      value=\"com.github.pagehelper.test.features.autodialect.SimpleAutoDialect\"/>\n            <property name=\"closeConn\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <!-- 该参数可选，可以设置sql缓存实现类，默认为SimpleCache，当项目包含guava时，使用GuavaCache，\n                 也可以通过参数 sqlCacheClass 指定自己的实现类 -->\n            <property name=\"sqlCacheClass\" value=\"com.github.pagehelper.cache.SimpleCache\"/>\n            <property name=\"countColumn\" value=\"1\"/>\n            <property name=\"dialectAlias\" value=\"oracle=com.github.pagehelper.dialect.helper.OracleDialect\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.hsqldb.jdbcDriver\"/>\n                <property name=\"url\" value=\"jdbc:hsqldb:mem:basetest\"/>\n                <property name=\"username\" value=\"sa\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/hsqldb/mybatis-config-interceptor.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.test.basic.provider.SqlCacheInterceptor\">\n        </plugin>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <!-- 支持通过Mapper接口参数来传递分页参数 -->\n            <property name=\"helperDialect\" value=\"mysql\"/>\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <property name=\"boundSqlInterceptors\"\n                      value=\"com.github.pagehelper.test.basic.provider.TestBoundSqlInterceptor,com.github.pagehelper.test.basic.provider.TestBoundSqlInterceptor\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.hsqldb.jdbcDriver\"/>\n                <property name=\"url\" value=\"jdbc:hsqldb:mem:basetest\"/>\n                <property name=\"username\" value=\"sa\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/hsqldb/mybatis-config-pagesizezero.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <property name=\"pageSizeZero\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.hsqldb.jdbcDriver\"/>\n                <property name=\"url\" value=\"jdbc:hsqldb:mem:pagesizezero\"/>\n                <property name=\"username\" value=\"sa\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/hsqldb/mybatis-config-reasonable.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"reasonable\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.hsqldb.jdbcDriver\"/>\n                <property name=\"url\" value=\"jdbc:hsqldb:mem:reasonable\"/>\n                <property name=\"username\" value=\"sa\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/hsqldb/mybatis-config-rowbounds.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.hsqldb.jdbcDriver\"/>\n                <property name=\"url\" value=\"jdbc:hsqldb:mem:rowbounds\"/>\n                <property name=\"username\" value=\"sa\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/hsqldb/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"debug\" value=\"true\"/>\n            <!-- dialect参数可以忽略不写 -->\n            <!-- 如果需要用自己的实现方法，可以将value写成类的全限定名称 -->\n            <!-- 如下所示，该类必须继承Parser接口 -->\n            <!--<property name=\"dialect\" value=\"hsqldb\"/>-->\n            <!-- 支持通过Mapper接口参数来传递分页参数 -->\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <!-- 运行时自动判断数据库类型，支持多数据源DataSource分页 -->\n            <property name=\"autoRuntimeDialect\" value=\"true\"/>\n            <property name=\"closeConn\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <!-- 该参数可选，可以设置sql缓存实现类，默认为SimpleCache，当项目包含guava时，使用GuavaCache，\n                 也可以通过参数 sqlCacheClass 指定自己的实现类 -->\n            <property name=\"sqlCacheClass\" value=\"com.github.pagehelper.cache.SimpleCache\"/>\n            <property name=\"countColumn\" value=\"1\"/>\n            <property name=\"dialectAlias\" value=\"oracle=com.github.pagehelper.dialect.helper.OracleDialect\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.hsqldb.jdbcDriver\"/>\n                <property name=\"url\" value=\"jdbc:hsqldb:mem:basetest\"/>\n                <property name=\"username\" value=\"sa\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/logback.xml",
    "content": "<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<configuration>\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>\n        </encoder>\n    </appender>\n    <root level=\"trace\">\n        <appender-ref ref=\"STDOUT\"/>\n    </root>\n</configuration>\n"
  },
  {
    "path": "src/test/resources/mariadb/mariadb.sql",
    "content": "﻿/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2022 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\nCREATE\nDATABASE `pagehelper` DEFAULT CHARACTER\nSET utf8;\n\nCREATE USER pagehelper IDENTIFIED BY 'pagehelper';\nGRANT ALL PRIVILEGES ON `pagehelper`.* TO 'pagehelper'@'%' WITH GRANT OPTION;\nGRANT USAGE ON *.* TO 'pagehelper'@'%' IDENTIFIED BY 'pagehelper';\n\nDROP TABLE IF EXISTS `user`;\n\nCREATE TABLE `user`\n(\n  `id` int(11) NOT NULL AUTO_INCREMENT,\n  `name` varchar(50) DEFAULT NULL,\n  `py` varchar(50) DEFAULT NULL,\n  PRIMARY KEY (`Id`)\n) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;\n\ninsert into user(id, name, py) values('1','毕淑儒','BSR');\ninsert into user(id, name, py) values('2','蔡兴熙','CXX');\ninsert into user(id, name, py) values('3','曾三杰','ZSJ');\ninsert into user(id, name, py) values('4','常元琴','CYQ');\ninsert into user(id, name, py) values('5','陈栋芬','CDF');\ninsert into user(id, name, py) values('6','陈宁婷','CNZ');\ninsert into user(id, name, py) values('7','陈瑞','CR');\ninsert into user(id, name, py) values('8','陈武宵','CWX');\ninsert into user(id, name, py) values('9','陈晓丽','CXL');\ninsert into user(id, name, py) values('10','陈翼涛','CYT');\ninsert into user(id, name, py) values('11','陈宇然','CYR');\ninsert into user(id, name, py) values('12','陈震','CZ');\ninsert into user(id, name, py) values('13','程太君','CTJ');\ninsert into user(id, name, py) values('14','程玉娜','CYN');\ninsert into user(id, name, py) values('15','丛贺轩','CHX');\ninsert into user(id, name, py) values('16','戴国宇','DGY');\ninsert into user(id, name, py) values('17','戴杰亮','DJL');\ninsert into user(id, name, py) values('18','丁玉华','DYH');\ninsert into user(id, name, py) values('19','董秋明','DQM');\ninsert into user(id, name, py) values('20','董政厚','DZH');\ninsert into user(id, name, py) values('21','杜玉焱','DYZ');\ninsert into user(id, name, py) values('22','段瑜芝','DZZ');\ninsert into user(id, name, py) values('23','傅广友','FGY');\ninsert into user(id, name, py) values('24','傅井飞','FJF');\ninsert into user(id, name, py) values('25','高辉涛','GHT');\ninsert into user(id, name, py) values('26','高龙飞','GLF');\ninsert into user(id, name, py) values('27','高汝英','GRY');\ninsert into user(id, name, py) values('28','高云天','GYT');\ninsert into user(id, name, py) values('29','郭义民','GYM');\ninsert into user(id, name, py) values('30','郭永洪','GYH');\ninsert into user(id, name, py) values('31','韩国茜','HGZ');\ninsert into user(id, name, py) values('32','韩龙康','HLK');\ninsert into user(id, name, py) values('33','韩伟佳','HWJ');\ninsert into user(id, name, py) values('34','韩扬谦','HYQ');\ninsert into user(id, name, py) values('35','郝静生','HJS');\ninsert into user(id, name, py) values('36','何柏红','HBH');\ninsert into user(id, name, py) values('37','何彩智','HCZ');\ninsert into user(id, name, py) values('38','何陶增','HTZ');\ninsert into user(id, name, py) values('39','何薇','HZ');\ninsert into user(id, name, py) values('40','何小凡','HXF');\ninsert into user(id, name, py) values('41','何振平','HZP');\ninsert into user(id, name, py) values('42','洪彩辉','HCH');\ninsert into user(id, name, py) values('43','胡仕明','HSM');\ninsert into user(id, name, py) values('44','黄建朋','HJP');\ninsert into user(id, name, py) values('45','黄祥荣','HXR');\ninsert into user(id, name, py) values('46','黄璇平','HZP');\ninsert into user(id, name, py) values('47','贾茂飞','JMF');\ninsert into user(id, name, py) values('48','李迪茹','LDR');\ninsert into user(id, name, py) values('49','李桂博','LGB');\ninsert into user(id, name, py) values('50','李国祯','LGZ');\ninsert into user(id, name, py) values('51','李宏川','LHC');\ninsert into user(id, name, py) values('52','李梅','LM');\ninsert into user(id, name, py) values('53','李媚文','LMW');\ninsert into user(id, name, py) values('54','李孟惠','LMH');\ninsert into user(id, name, py) values('55','李南懋','LNZ');\ninsert into user(id, name, py) values('56','李鹏龙','LPL');\ninsert into user(id, name, py) values('57','李诗庸','LSY');\ninsert into user(id, name, py) values('58','李姝勇','LZY');\ninsert into user(id, name, py) values('59','李树鹏','LSP');\ninsert into user(id, name, py) values('60','李薇红','LZH');\ninsert into user(id, name, py) values('61','李文章','LWZ');\ninsert into user(id, name, py) values('62','李星佳','LXJ');\ninsert into user(id, name, py) values('63','李兴','LX');\ninsert into user(id, name, py) values('64','李秀倩','LXZ');\ninsert into user(id, name, py) values('65','李艳生','LYS');\ninsert into user(id, name, py) values('66','李燕金','LYJ');\ninsert into user(id, name, py) values('67','李玉彪','LYB');\ninsert into user(id, name, py) values('68','李振峰','LZF');\ninsert into user(id, name, py) values('69','梁斌芳','LBF');\ninsert into user(id, name, py) values('70','梁国云','LGY');\ninsert into user(id, name, py) values('71','梁巧爱','LQA');\ninsert into user(id, name, py) values('72','梁照金','LZJ');\ninsert into user(id, name, py) values('73','林婧美','LZM');\ninsert into user(id, name, py) values('74','林沛寿','LPS');\ninsert into user(id, name, py) values('75','林薇程','LZC');\ninsert into user(id, name, py) values('76','林伟玉','LWY');\ninsert into user(id, name, py) values('77','林艺玲','LYL');\ninsert into user(id, name, py) values('78','刘睿','LR');\ninsert into user(id, name, py) values('79','刘芊芊','LQQ');\ninsert into user(id, name, py) values('80','刘海波','LHB');\ninsert into user(id, name, py) values('81','刘斓琴','LZQ');\ninsert into user(id, name, py) values('82','刘磊东','LLD');\ninsert into user(id, name, py) values('83','刘明琪','LMZ');\ninsert into user(id, name, py) values('84','刘铭恩','LME');\ninsert into user(id, name, py) values('85','刘任恺','LRZ');\ninsert into user(id, name, py) values('86','刘水秋','LSQ');\ninsert into user(id, name, py) values('87','刘文萱','LWZ');\ninsert into user(id, name, py) values('88','刘祥瑶','LXY');\ninsert into user(id, name, py) values('89','刘薪坪','LXP');\ninsert into user(id, name, py) values('90','刘秀涛','LXT');\ninsert into user(id, name, py) values('91','刘彦利','LYL');\ninsert into user(id, name, py) values('92','刘益存','LYC');\ninsert into user(id, name, py) values('93','龙子苹','LZP');\ninsert into user(id, name, py) values('94','卢秀剑','LXJ');\ninsert into user(id, name, py) values('95','罗乔华','LQH');\ninsert into user(id, name, py) values('96','罗希清','LXQ');\ninsert into user(id, name, py) values('97','马家兰','MJL');\ninsert into user(id, name, py) values('98','马莲莹','MLY');\ninsert into user(id, name, py) values('99','马宁文','MNW');\ninsert into user(id, name, py) values('100','马水鹏','MSP');\ninsert into user(id, name, py) values('101','孟三云','MSY');\ninsert into user(id, name, py) values('102','孟寿云','MSY');\ninsert into user(id, name, py) values('103','聂伟元','NWY');\ninsert into user(id, name, py) values('104','潘永飞','PYF');\ninsert into user(id, name, py) values('105','彭健颖','PJY');\ninsert into user(id, name, py) values('106','钱文松','QWS');\ninsert into user(id, name, py) values('107','屈江珍','QJZ');\ninsert into user(id, name, py) values('108','邵建林','SJL');\ninsert into user(id, name, py) values('109','施家晖','SJZ');\ninsert into user(id, name, py) values('110','施艺英','SYY');\ninsert into user(id, name, py) values('111','孙常程','SCC');\ninsert into user(id, name, py) values('112','谭佳盈','TJY');\ninsert into user(id, name, py) values('113','唐春珊','TCS');\ninsert into user(id, name, py) values('114','唐军霞','TJX');\ninsert into user(id, name, py) values('115','唐里丽','TLL');\ninsert into user(id, name, py) values('116','陶姐华','TJH');\ninsert into user(id, name, py) values('117','万圻艳','WZY');\ninsert into user(id, name, py) values('118','王傲凤','WAF');\ninsert into user(id, name, py) values('119','王德英','WDY');\ninsert into user(id, name, py) values('120','王鼎华','WDH');\ninsert into user(id, name, py) values('121','王慧','WH');\ninsert into user(id, name, py) values('122','王佳光','WJG');\ninsert into user(id, name, py) values('123','王家胜','WJS');\ninsert into user(id, name, py) values('124','王竞飞','WJF');\ninsert into user(id, name, py) values('125','王科磊','WKL');\ninsert into user(id, name, py) values('126','王丽章','WLZ');\ninsert into user(id, name, py) values('127','王励苗','WLM');\ninsert into user(id, name, py) values('128','王美东','WMD');\ninsert into user(id, name, py) values('129','王美媛','WMZ');\ninsert into user(id, name, py) values('130','王蕊颖','WRY');\ninsert into user(id, name, py) values('131','王士成','WSC');\ninsert into user(id, name, py) values('132','王熙斌','WXB');\ninsert into user(id, name, py) values('133','王香军','WXJ');\ninsert into user(id, name, py) values('134','王休娜','WXN');\ninsert into user(id, name, py) values('135','王仪行','WYX');\ninsert into user(id, name, py) values('136','王赢基','WYJ');\ninsert into user(id, name, py) values('137','王云芯','WYX');\ninsert into user(id, name, py) values('138','王郑林','WZL');\ninsert into user(id, name, py) values('139','王治良','WZL');\ninsert into user(id, name, py) values('140','王忠宇','WZY');\ninsert into user(id, name, py) values('141','王子冰','WZB');\ninsert into user(id, name, py) values('142','韦新裕','WXY');\ninsert into user(id, name, py) values('143','魏复冉','WFR');\ninsert into user(id, name, py) values('144','吴翰志','WHZ');\ninsert into user(id, name, py) values('145','吴美森','WMS');\ninsert into user(id, name, py) values('146','吴翔良','WXL');\ninsert into user(id, name, py) values('147','吴艳伟','WYW');\ninsert into user(id, name, py) values('148','吴钲辉','WZH');\ninsert into user(id, name, py) values('149','向盼洛','XPL');\ninsert into user(id, name, py) values('150','萧恩','XE');\ninsert into user(id, name, py) values('151','萧军杰','XJJ');\ninsert into user(id, name, py) values('152','萧圣梅','XSM');\ninsert into user(id, name, py) values('153','谢辰吉','XCJ');\ninsert into user(id, name, py) values('154','徐郎求','XLQ');\ninsert into user(id, name, py) values('155','徐铭森','XMS');\ninsert into user(id, name, py) values('156','徐蓉伟','XRW');\ninsert into user(id, name, py) values('157','许为梧','XWW');\ninsert into user(id, name, py) values('158','阎皓河','YZH');\ninsert into user(id, name, py) values('159','阎思华','YSH');\ninsert into user(id, name, py) values('160','杨爱秀','YAX');\ninsert into user(id, name, py) values('161','杨昆飞','YKF');\ninsert into user(id, name, py) values('162','杨良林','YLL');\ninsert into user(id, name, py) values('163','杨少君','YSJ');\ninsert into user(id, name, py) values('164','杨玉丽','YYL');\ninsert into user(id, name, py) values('165','杨之安','YZA');\ninsert into user(id, name, py) values('166','尤榕锋','YZF');\ninsert into user(id, name, py) values('167','余俊珠','YJZ');\ninsert into user(id, name, py) values('168','袁江蔓','YJM');\ninsert into user(id, name, py) values('169','张必翰','ZBH');\ninsert into user(id, name, py) values('170','张昌颜','ZCY');\ninsert into user(id, name, py) values('171','张恩星','ZEX');\ninsert into user(id, name, py) values('172','张飞强','ZFQ');\ninsert into user(id, name, py) values('173','张凤焯','ZFZ');\ninsert into user(id, name, py) values('174','张国强','ZGQ');\ninsert into user(id, name, py) values('175','张计欣','ZJX');\ninsert into user(id, name, py) values('176','张家颖','ZJY');\ninsert into user(id, name, py) values('177','张金安','ZJA');\ninsert into user(id, name, py) values('178','张莉','ZL');\ninsert into user(id, name, py) values('179','张米龙','ZML');\ninsert into user(id, name, py) values('180','张善渊','ZSY');\ninsert into user(id, name, py) values('181','张万敏','ZWM');\ninsert into user(id, name, py) values('182','张晓林','ZXL');\ninsert into user(id, name, py) values('183','张秀高','ZXG');\n"
  },
  {
    "path": "src/test/resources/mariadb/mybatis-config-pagesizezero.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <property name=\"pageSizeZero\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.mariadb.jdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:mysql://localhost:3309/pagehelper\"/>\n                <property name=\"username\" value=\"pagehelper\"/>\n                <property name=\"password\" value=\"pagehelper\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/mariadb/mybatis-config-reasonable.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"reasonable\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.mariadb.jdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:mysql://localhost:3309/pagehelper\"/>\n                <property name=\"username\" value=\"pagehelper\"/>\n                <property name=\"password\" value=\"pagehelper\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/mariadb/mybatis-config-rowbounds.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.mariadb.jdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:mysql://localhost:3309/pagehelper\"/>\n                <property name=\"username\" value=\"pagehelper\"/>\n                <property name=\"password\" value=\"pagehelper\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/mariadb/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <!-- 支持通过Mapper接口参数来传递分页参数 -->\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.mariadb.jdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:mariadb://localhost:3309/pagehelper\"/>\n                <property name=\"username\" value=\"pagehelper\"/>\n                <property name=\"password\" value=\"pagehelper\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/mybatis-config-async-count.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"debug\" value=\"true\"/>\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <!-- 运行时自动判断数据库类型，支持多数据源DataSource分页 -->\n            <property name=\"autoRuntimeDialect\" value=\"true\"/>\n            <property name=\"closeConn\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <!-- 该参数可选，可以设置sql缓存实现类，默认为SimpleCache，当项目包含guava时，使用GuavaCache，\n                 也可以通过参数 sqlCacheClass 指定自己的实现类 -->\n            <property name=\"sqlCacheClass\" value=\"com.github.pagehelper.cache.SimpleCache\"/>\n            <property name=\"countColumn\" value=\"1\"/>\n            <property name=\"dialectAlias\" value=\"oracle=com.github.pagehelper.dialect.helper.OracleDialect\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.mysql.jdbc.Driver\"/>\n                <!-- 数据来源：https://github.com/datacharmer/test_db -->\n                <property name=\"url\" value=\"jdbc:mysql://localhost:3306/employees\"/>\n                <property name=\"username\" value=\"root\"/>\n                <property name=\"password\" value=\"root\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/mysql/mybatis-config-autodialect.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <!-- dialect参数可以忽略不写 -->\n            <!-- 如果需要用自己的实现方法，可以将value写成类的全限定名称 -->\n            <!-- 如下所示，该类必须继承Parser接口 -->\n            <!--<property name=\"dialect\" value=\"hsqldb\"/>-->\n            <!-- 支持通过Mapper接口参数来传递分页参数 -->\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <!-- 运行时自动判断数据库类型，支持多数据源DataSource分页 -->\n            <property name=\"autoRuntimeDialect\" value=\"true\"/>\n            <property name=\"autoDialectClass\"\n                      value=\"com.github.pagehelper.test.features.autodialect.SimpleAutoDialect\"/>\n            <property name=\"closeConn\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <!-- 该参数可选，可以设置sql缓存实现类，默认为SimpleCache，当项目包含guava时，使用GuavaCache，\n                 也可以通过参数 sqlCacheClass 指定自己的实现类 -->\n            <property name=\"sqlCacheClass\" value=\"com.github.pagehelper.cache.SimpleCache\"/>\n            <property name=\"countColumn\" value=\"1\"/>\n            <property name=\"dialectAlias\" value=\"oracle=com.github.pagehelper.dialect.helper.OracleDialect\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.mysql.jdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:mysql://localhost:3306/pagehelper\"/>\n                <property name=\"username\" value=\"root\"/>\n                <property name=\"password\" value=\"root\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/mysql/mybatis-config-interceptor.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.test.basic.provider.SqlCacheInterceptor\">\n        </plugin>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <!-- 支持通过Mapper接口参数来传递分页参数 -->\n            <property name=\"helperDialect\" value=\"mysql\"/>\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <property name=\"boundSqlInterceptors\"\n                      value=\"com.github.pagehelper.test.basic.provider.TestBoundSqlInterceptor,com.github.pagehelper.test.basic.provider.TestBoundSqlInterceptor\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.mysql.jdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:mysql://localhost:3306/pagehelper\"/>\n                <property name=\"username\" value=\"root\"/>\n                <property name=\"password\" value=\"root\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/mysql/mybatis-config-pagesizezero.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"helperDialect\" value=\"mysql\"/>\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <property name=\"pageSizeZero\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.mysql.jdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:mysql://localhost:3306/pagehelper\"/>\n                <property name=\"username\" value=\"root\"/>\n                <property name=\"password\" value=\"root\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/mysql/mybatis-config-reasonable.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"helperDialect\" value=\"mysql\"/>\n            <property name=\"reasonable\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.mysql.jdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:mysql://localhost:3306/pagehelper\"/>\n                <property name=\"username\" value=\"root\"/>\n                <property name=\"password\" value=\"root\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/mysql/mybatis-config-rowbounds.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"helperDialect\" value=\"mysql\"/>\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.mysql.jdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:mysql://localhost:3306/pagehelper\"/>\n                <property name=\"username\" value=\"root\"/>\n                <property name=\"password\" value=\"root\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/mysql/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"debug\" value=\"true\"/>\n            <property name=\"helperDialect\" value=\"mysql\"/>\n            <!-- 支持通过Mapper接口参数来传递分页参数 -->\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <!-- 运行时自动判断数据库类型，支持多数据源DataSource分页 -->\n            <property name=\"autoRuntimeDialect\" value=\"true\"/>\n            <property name=\"closeConn\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <!-- 该参数可选，可以设置sql缓存实现类，默认为SimpleCache，当项目包含guava时，使用GuavaCache，\n                     也可以通过参数 sqlCacheClass 指定自己的实现类 -->\n            <property name=\"sqlCacheClass\" value=\"com.github.pagehelper.cache.SimpleCache\"/>\n            <property name=\"countColumn\" value=\"1\"/>\n            <property name=\"dialectAlias\" value=\"oracle=com.github.pagehelper.dialect.helper.OracleDialect\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.mysql.jdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:mysql://localhost:3306/pagehelper\"/>\n                <property name=\"username\" value=\"root\"/>\n                <property name=\"password\" value=\"root\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/mysql/mysql.sql",
    "content": "﻿/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2022 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\nCREATE\nDATABASE `pagehelper` DEFAULT CHARACTER\nSET utf8;\n\nUSE `pagehelper`;\nDROP TABLE IF EXISTS `user`;\n\nCREATE TABLE `user`\n(\n    `id`   int(11) NOT NULL AUTO_INCREMENT,\n    `name` varchar(50) DEFAULT NULL,\n    `py`   varchar(50) DEFAULT NULL,\n  PRIMARY KEY (`Id`)\n) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;\n\ninsert into user(id, name, py) values('1','毕淑儒','BSR');\ninsert into user(id, name, py) values('2','蔡兴熙','CXX');\ninsert into user(id, name, py) values('3','曾三杰','ZSJ');\ninsert into user(id, name, py) values('4','常元琴','CYQ');\ninsert into user(id, name, py) values('5','陈栋芬','CDF');\ninsert into user(id, name, py) values('6','陈宁婷','CNZ');\ninsert into user(id, name, py) values('7','陈瑞','CR');\ninsert into user(id, name, py) values('8','陈武宵','CWX');\ninsert into user(id, name, py) values('9','陈晓丽','CXL');\ninsert into user(id, name, py) values('10','陈翼涛','CYT');\ninsert into user(id, name, py) values('11','陈宇然','CYR');\ninsert into user(id, name, py) values('12','陈震','CZ');\ninsert into user(id, name, py) values('13','程太君','CTJ');\ninsert into user(id, name, py) values('14','程玉娜','CYN');\ninsert into user(id, name, py) values('15','丛贺轩','CHX');\ninsert into user(id, name, py) values('16','戴国宇','DGY');\ninsert into user(id, name, py) values('17','戴杰亮','DJL');\ninsert into user(id, name, py) values('18','丁玉华','DYH');\ninsert into user(id, name, py) values('19','董秋明','DQM');\ninsert into user(id, name, py) values('20','董政厚','DZH');\ninsert into user(id, name, py) values('21','杜玉焱','DYZ');\ninsert into user(id, name, py) values('22','段瑜芝','DZZ');\ninsert into user(id, name, py) values('23','傅广友','FGY');\ninsert into user(id, name, py) values('24','傅井飞','FJF');\ninsert into user(id, name, py) values('25','高辉涛','GHT');\ninsert into user(id, name, py) values('26','高龙飞','GLF');\ninsert into user(id, name, py) values('27','高汝英','GRY');\ninsert into user(id, name, py) values('28','高云天','GYT');\ninsert into user(id, name, py) values('29','郭义民','GYM');\ninsert into user(id, name, py) values('30','郭永洪','GYH');\ninsert into user(id, name, py) values('31','韩国茜','HGZ');\ninsert into user(id, name, py) values('32','韩龙康','HLK');\ninsert into user(id, name, py) values('33','韩伟佳','HWJ');\ninsert into user(id, name, py) values('34','韩扬谦','HYQ');\ninsert into user(id, name, py) values('35','郝静生','HJS');\ninsert into user(id, name, py) values('36','何柏红','HBH');\ninsert into user(id, name, py) values('37','何彩智','HCZ');\ninsert into user(id, name, py) values('38','何陶增','HTZ');\ninsert into user(id, name, py) values('39','何薇','HZ');\ninsert into user(id, name, py) values('40','何小凡','HXF');\ninsert into user(id, name, py) values('41','何振平','HZP');\ninsert into user(id, name, py) values('42','洪彩辉','HCH');\ninsert into user(id, name, py) values('43','胡仕明','HSM');\ninsert into user(id, name, py) values('44','黄建朋','HJP');\ninsert into user(id, name, py) values('45','黄祥荣','HXR');\ninsert into user(id, name, py) values('46','黄璇平','HZP');\ninsert into user(id, name, py) values('47','贾茂飞','JMF');\ninsert into user(id, name, py) values('48','李迪茹','LDR');\ninsert into user(id, name, py) values('49','李桂博','LGB');\ninsert into user(id, name, py) values('50','李国祯','LGZ');\ninsert into user(id, name, py) values('51','李宏川','LHC');\ninsert into user(id, name, py) values('52','李梅','LM');\ninsert into user(id, name, py) values('53','李媚文','LMW');\ninsert into user(id, name, py) values('54','李孟惠','LMH');\ninsert into user(id, name, py) values('55','李南懋','LNZ');\ninsert into user(id, name, py) values('56','李鹏龙','LPL');\ninsert into user(id, name, py) values('57','李诗庸','LSY');\ninsert into user(id, name, py) values('58','李姝勇','LZY');\ninsert into user(id, name, py) values('59','李树鹏','LSP');\ninsert into user(id, name, py) values('60','李薇红','LZH');\ninsert into user(id, name, py) values('61','李文章','LWZ');\ninsert into user(id, name, py) values('62','李星佳','LXJ');\ninsert into user(id, name, py) values('63','李兴','LX');\ninsert into user(id, name, py) values('64','李秀倩','LXZ');\ninsert into user(id, name, py) values('65','李艳生','LYS');\ninsert into user(id, name, py) values('66','李燕金','LYJ');\ninsert into user(id, name, py) values('67','李玉彪','LYB');\ninsert into user(id, name, py) values('68','李振峰','LZF');\ninsert into user(id, name, py) values('69','梁斌芳','LBF');\ninsert into user(id, name, py) values('70','梁国云','LGY');\ninsert into user(id, name, py) values('71','梁巧爱','LQA');\ninsert into user(id, name, py) values('72','梁照金','LZJ');\ninsert into user(id, name, py) values('73','林婧美','LZM');\ninsert into user(id, name, py) values('74','林沛寿','LPS');\ninsert into user(id, name, py) values('75','林薇程','LZC');\ninsert into user(id, name, py) values('76','林伟玉','LWY');\ninsert into user(id, name, py) values('77','林艺玲','LYL');\ninsert into user(id, name, py) values('78','刘睿','LR');\ninsert into user(id, name, py) values('79','刘芊芊','LQQ');\ninsert into user(id, name, py) values('80','刘海波','LHB');\ninsert into user(id, name, py) values('81','刘斓琴','LZQ');\ninsert into user(id, name, py) values('82','刘磊东','LLD');\ninsert into user(id, name, py) values('83','刘明琪','LMZ');\ninsert into user(id, name, py) values('84','刘铭恩','LME');\ninsert into user(id, name, py) values('85','刘任恺','LRZ');\ninsert into user(id, name, py) values('86','刘水秋','LSQ');\ninsert into user(id, name, py) values('87','刘文萱','LWZ');\ninsert into user(id, name, py) values('88','刘祥瑶','LXY');\ninsert into user(id, name, py) values('89','刘薪坪','LXP');\ninsert into user(id, name, py) values('90','刘秀涛','LXT');\ninsert into user(id, name, py) values('91','刘彦利','LYL');\ninsert into user(id, name, py) values('92','刘益存','LYC');\ninsert into user(id, name, py) values('93','龙子苹','LZP');\ninsert into user(id, name, py) values('94','卢秀剑','LXJ');\ninsert into user(id, name, py) values('95','罗乔华','LQH');\ninsert into user(id, name, py) values('96','罗希清','LXQ');\ninsert into user(id, name, py) values('97','马家兰','MJL');\ninsert into user(id, name, py) values('98','马莲莹','MLY');\ninsert into user(id, name, py) values('99','马宁文','MNW');\ninsert into user(id, name, py) values('100','马水鹏','MSP');\ninsert into user(id, name, py) values('101','孟三云','MSY');\ninsert into user(id, name, py) values('102','孟寿云','MSY');\ninsert into user(id, name, py) values('103','聂伟元','NWY');\ninsert into user(id, name, py) values('104','潘永飞','PYF');\ninsert into user(id, name, py) values('105','彭健颖','PJY');\ninsert into user(id, name, py) values('106','钱文松','QWS');\ninsert into user(id, name, py) values('107','屈江珍','QJZ');\ninsert into user(id, name, py) values('108','邵建林','SJL');\ninsert into user(id, name, py) values('109','施家晖','SJZ');\ninsert into user(id, name, py) values('110','施艺英','SYY');\ninsert into user(id, name, py) values('111','孙常程','SCC');\ninsert into user(id, name, py) values('112','谭佳盈','TJY');\ninsert into user(id, name, py) values('113','唐春珊','TCS');\ninsert into user(id, name, py) values('114','唐军霞','TJX');\ninsert into user(id, name, py) values('115','唐里丽','TLL');\ninsert into user(id, name, py) values('116','陶姐华','TJH');\ninsert into user(id, name, py) values('117','万圻艳','WZY');\ninsert into user(id, name, py) values('118','王傲凤','WAF');\ninsert into user(id, name, py) values('119','王德英','WDY');\ninsert into user(id, name, py) values('120','王鼎华','WDH');\ninsert into user(id, name, py) values('121','王慧','WH');\ninsert into user(id, name, py) values('122','王佳光','WJG');\ninsert into user(id, name, py) values('123','王家胜','WJS');\ninsert into user(id, name, py) values('124','王竞飞','WJF');\ninsert into user(id, name, py) values('125','王科磊','WKL');\ninsert into user(id, name, py) values('126','王丽章','WLZ');\ninsert into user(id, name, py) values('127','王励苗','WLM');\ninsert into user(id, name, py) values('128','王美东','WMD');\ninsert into user(id, name, py) values('129','王美媛','WMZ');\ninsert into user(id, name, py) values('130','王蕊颖','WRY');\ninsert into user(id, name, py) values('131','王士成','WSC');\ninsert into user(id, name, py) values('132','王熙斌','WXB');\ninsert into user(id, name, py) values('133','王香军','WXJ');\ninsert into user(id, name, py) values('134','王休娜','WXN');\ninsert into user(id, name, py) values('135','王仪行','WYX');\ninsert into user(id, name, py) values('136','王赢基','WYJ');\ninsert into user(id, name, py) values('137','王云芯','WYX');\ninsert into user(id, name, py) values('138','王郑林','WZL');\ninsert into user(id, name, py) values('139','王治良','WZL');\ninsert into user(id, name, py) values('140','王忠宇','WZY');\ninsert into user(id, name, py) values('141','王子冰','WZB');\ninsert into user(id, name, py) values('142','韦新裕','WXY');\ninsert into user(id, name, py) values('143','魏复冉','WFR');\ninsert into user(id, name, py) values('144','吴翰志','WHZ');\ninsert into user(id, name, py) values('145','吴美森','WMS');\ninsert into user(id, name, py) values('146','吴翔良','WXL');\ninsert into user(id, name, py) values('147','吴艳伟','WYW');\ninsert into user(id, name, py) values('148','吴钲辉','WZH');\ninsert into user(id, name, py) values('149','向盼洛','XPL');\ninsert into user(id, name, py) values('150','萧恩','XE');\ninsert into user(id, name, py) values('151','萧军杰','XJJ');\ninsert into user(id, name, py) values('152','萧圣梅','XSM');\ninsert into user(id, name, py) values('153','谢辰吉','XCJ');\ninsert into user(id, name, py) values('154','徐郎求','XLQ');\ninsert into user(id, name, py) values('155','徐铭森','XMS');\ninsert into user(id, name, py) values('156','徐蓉伟','XRW');\ninsert into user(id, name, py) values('157','许为梧','XWW');\ninsert into user(id, name, py) values('158','阎皓河','YZH');\ninsert into user(id, name, py) values('159','阎思华','YSH');\ninsert into user(id, name, py) values('160','杨爱秀','YAX');\ninsert into user(id, name, py) values('161','杨昆飞','YKF');\ninsert into user(id, name, py) values('162','杨良林','YLL');\ninsert into user(id, name, py) values('163','杨少君','YSJ');\ninsert into user(id, name, py) values('164','杨玉丽','YYL');\ninsert into user(id, name, py) values('165','杨之安','YZA');\ninsert into user(id, name, py) values('166','尤榕锋','YZF');\ninsert into user(id, name, py) values('167','余俊珠','YJZ');\ninsert into user(id, name, py) values('168','袁江蔓','YJM');\ninsert into user(id, name, py) values('169','张必翰','ZBH');\ninsert into user(id, name, py) values('170','张昌颜','ZCY');\ninsert into user(id, name, py) values('171','张恩星','ZEX');\ninsert into user(id, name, py) values('172','张飞强','ZFQ');\ninsert into user(id, name, py) values('173','张凤焯','ZFZ');\ninsert into user(id, name, py) values('174','张国强','ZGQ');\ninsert into user(id, name, py) values('175','张计欣','ZJX');\ninsert into user(id, name, py) values('176','张家颖','ZJY');\ninsert into user(id, name, py) values('177','张金安','ZJA');\ninsert into user(id, name, py) values('178','张莉','ZL');\ninsert into user(id, name, py) values('179','张米龙','ZML');\ninsert into user(id, name, py) values('180','张善渊','ZSY');\ninsert into user(id, name, py) values('181','张万敏','ZWM');\ninsert into user(id, name, py) values('182','张晓林','ZXL');\ninsert into user(id, name, py) values('183','张秀高','ZXG');\n"
  },
  {
    "path": "src/test/resources/oracle/mybatis-config-pagesizezero.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"helperDialect\" value=\"oracle\"/>\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <property name=\"pageSizeZero\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"oracle.jdbc.driver.OracleDriver\"/>\n                <property name=\"url\" value=\"jdbc:oracle:thin:@//192.168.16.137:1521/orcl\"/>\n                <property name=\"username\" value=\"mybatis\"/>\n                <property name=\"password\" value=\"mybatis\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/oracle/mybatis-config-reasonable.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"reasonable\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"oracle.jdbc.driver.OracleDriver\"/>\n                <property name=\"url\" value=\"jdbc:oracle:thin:@//192.168.16.137:1521/orcl\"/>\n                <property name=\"username\" value=\"mybatis\"/>\n                <property name=\"password\" value=\"mybatis\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/oracle/mybatis-config-rowbounds.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"oracle.jdbc.driver.OracleDriver\"/>\n                <property name=\"url\" value=\"jdbc:oracle:thin:@//192.168.16.137:1521/orcl\"/>\n                <property name=\"username\" value=\"mybatis\"/>\n                <property name=\"password\" value=\"mybatis\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/oracle/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <!-- 支持通过Mapper接口参数来传递分页参数 -->\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"oracle.jdbc.driver.OracleDriver\"/>\n                <property name=\"url\" value=\"jdbc:oracle:thin:@//192.168.16.137:1521/orcl\"/>\n                <property name=\"username\" value=\"mybatis\"/>\n                <property name=\"password\" value=\"mybatis\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <databaseIdProvider type=\"DB_VENDOR\">\n        <property name=\"Oracle\" value=\"oracle\"/>\n    </databaseIdProvider>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n</configuration>\n"
  },
  {
    "path": "src/test/resources/oracle/oracle.sql",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2022 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n-- 启用scott/tiger用户的方法\n-- 解锁\nalter user scott account unlock;\n-- 重设密码\nalter user scott identified by tiger;\n-- 查看用户状态\n-- select username,account_status from dba_users;\n\n\n-- 创建表\ncreate table user\n(\n  id          number(6),\n  name varchar2(50),\n  py varchar2(50)\n);\n\nalter table user\n  add constraint PK_USER_ID primary key (ID);\n\n-- 插入测试数据\ninsert into user(id, name, py) values('1','毕淑儒','BSR');\ninsert into user(id, name, py) values('2','蔡兴熙','CXX');\ninsert into user(id, name, py) values('3','曾三杰','ZSJ');\ninsert into user(id, name, py) values('4','常元琴','CYQ');\ninsert into user(id, name, py) values('5','陈栋芬','CDF');\ninsert into user(id, name, py) values('6','陈宁婷','CNZ');\ninsert into user(id, name, py) values('7','陈瑞','CR');\ninsert into user(id, name, py) values('8','陈武宵','CWX');\ninsert into user(id, name, py) values('9','陈晓丽','CXL');\ninsert into user(id, name, py) values('10','陈翼涛','CYT');\ninsert into user(id, name, py) values('11','陈宇然','CYR');\ninsert into user(id, name, py) values('12','陈震','CZ');\ninsert into user(id, name, py) values('13','程太君','CTJ');\ninsert into user(id, name, py) values('14','程玉娜','CYN');\ninsert into user(id, name, py) values('15','丛贺轩','CHX');\ninsert into user(id, name, py) values('16','戴国宇','DGY');\ninsert into user(id, name, py) values('17','戴杰亮','DJL');\ninsert into user(id, name, py) values('18','丁玉华','DYH');\ninsert into user(id, name, py) values('19','董秋明','DQM');\ninsert into user(id, name, py) values('20','董政厚','DZH');\ninsert into user(id, name, py) values('21','杜玉焱','DYZ');\ninsert into user(id, name, py) values('22','段瑜芝','DZZ');\ninsert into user(id, name, py) values('23','傅广友','FGY');\ninsert into user(id, name, py) values('24','傅井飞','FJF');\ninsert into user(id, name, py) values('25','高辉涛','GHT');\ninsert into user(id, name, py) values('26','高龙飞','GLF');\ninsert into user(id, name, py) values('27','高汝英','GRY');\ninsert into user(id, name, py) values('28','高云天','GYT');\ninsert into user(id, name, py) values('29','郭义民','GYM');\ninsert into user(id, name, py) values('30','郭永洪','GYH');\ninsert into user(id, name, py) values('31','韩国茜','HGZ');\ninsert into user(id, name, py) values('32','韩龙康','HLK');\ninsert into user(id, name, py) values('33','韩伟佳','HWJ');\ninsert into user(id, name, py) values('34','韩扬谦','HYQ');\ninsert into user(id, name, py) values('35','郝静生','HJS');\ninsert into user(id, name, py) values('36','何柏红','HBH');\ninsert into user(id, name, py) values('37','何彩智','HCZ');\ninsert into user(id, name, py) values('38','何陶增','HTZ');\ninsert into user(id, name, py) values('39','何薇','HZ');\ninsert into user(id, name, py) values('40','何小凡','HXF');\ninsert into user(id, name, py) values('41','何振平','HZP');\ninsert into user(id, name, py) values('42','洪彩辉','HCH');\ninsert into user(id, name, py) values('43','胡仕明','HSM');\ninsert into user(id, name, py) values('44','黄建朋','HJP');\ninsert into user(id, name, py) values('45','黄祥荣','HXR');\ninsert into user(id, name, py) values('46','黄璇平','HZP');\ninsert into user(id, name, py) values('47','贾茂飞','JMF');\ninsert into user(id, name, py) values('48','李迪茹','LDR');\ninsert into user(id, name, py) values('49','李桂博','LGB');\ninsert into user(id, name, py) values('50','李国祯','LGZ');\ninsert into user(id, name, py) values('51','李宏川','LHC');\ninsert into user(id, name, py) values('52','李梅','LM');\ninsert into user(id, name, py) values('53','李媚文','LMW');\ninsert into user(id, name, py) values('54','李孟惠','LMH');\ninsert into user(id, name, py) values('55','李南懋','LNZ');\ninsert into user(id, name, py) values('56','李鹏龙','LPL');\ninsert into user(id, name, py) values('57','李诗庸','LSY');\ninsert into user(id, name, py) values('58','李姝勇','LZY');\ninsert into user(id, name, py) values('59','李树鹏','LSP');\ninsert into user(id, name, py) values('60','李薇红','LZH');\ninsert into user(id, name, py) values('61','李文章','LWZ');\ninsert into user(id, name, py) values('62','李星佳','LXJ');\ninsert into user(id, name, py) values('63','李兴','LX');\ninsert into user(id, name, py) values('64','李秀倩','LXZ');\ninsert into user(id, name, py) values('65','李艳生','LYS');\ninsert into user(id, name, py) values('66','李燕金','LYJ');\ninsert into user(id, name, py) values('67','李玉彪','LYB');\ninsert into user(id, name, py) values('68','李振峰','LZF');\ninsert into user(id, name, py) values('69','梁斌芳','LBF');\ninsert into user(id, name, py) values('70','梁国云','LGY');\ninsert into user(id, name, py) values('71','梁巧爱','LQA');\ninsert into user(id, name, py) values('72','梁照金','LZJ');\ninsert into user(id, name, py) values('73','林婧美','LZM');\ninsert into user(id, name, py) values('74','林沛寿','LPS');\ninsert into user(id, name, py) values('75','林薇程','LZC');\ninsert into user(id, name, py) values('76','林伟玉','LWY');\ninsert into user(id, name, py) values('77','林艺玲','LYL');\ninsert into user(id, name, py) values('78','刘睿','LR');\ninsert into user(id, name, py) values('79','刘芊芊','LQQ');\ninsert into user(id, name, py) values('80','刘海波','LHB');\ninsert into user(id, name, py) values('81','刘斓琴','LZQ');\ninsert into user(id, name, py) values('82','刘磊东','LLD');\ninsert into user(id, name, py) values('83','刘明琪','LMZ');\ninsert into user(id, name, py) values('84','刘铭恩','LME');\ninsert into user(id, name, py) values('85','刘任恺','LRZ');\ninsert into user(id, name, py) values('86','刘水秋','LSQ');\ninsert into user(id, name, py) values('87','刘文萱','LWZ');\ninsert into user(id, name, py) values('88','刘祥瑶','LXY');\ninsert into user(id, name, py) values('89','刘薪坪','LXP');\ninsert into user(id, name, py) values('90','刘秀涛','LXT');\ninsert into user(id, name, py) values('91','刘彦利','LYL');\ninsert into user(id, name, py) values('92','刘益存','LYC');\ninsert into user(id, name, py) values('93','龙子苹','LZP');\ninsert into user(id, name, py) values('94','卢秀剑','LXJ');\ninsert into user(id, name, py) values('95','罗乔华','LQH');\ninsert into user(id, name, py) values('96','罗希清','LXQ');\ninsert into user(id, name, py) values('97','马家兰','MJL');\ninsert into user(id, name, py) values('98','马莲莹','MLY');\ninsert into user(id, name, py) values('99','马宁文','MNW');\ninsert into user(id, name, py) values('100','马水鹏','MSP');\ninsert into user(id, name, py) values('101','孟三云','MSY');\ninsert into user(id, name, py) values('102','孟寿云','MSY');\ninsert into user(id, name, py) values('103','聂伟元','NWY');\ninsert into user(id, name, py) values('104','潘永飞','PYF');\ninsert into user(id, name, py) values('105','彭健颖','PJY');\ninsert into user(id, name, py) values('106','钱文松','QWS');\ninsert into user(id, name, py) values('107','屈江珍','QJZ');\ninsert into user(id, name, py) values('108','邵建林','SJL');\ninsert into user(id, name, py) values('109','施家晖','SJZ');\ninsert into user(id, name, py) values('110','施艺英','SYY');\ninsert into user(id, name, py) values('111','孙常程','SCC');\ninsert into user(id, name, py) values('112','谭佳盈','TJY');\ninsert into user(id, name, py) values('113','唐春珊','TCS');\ninsert into user(id, name, py) values('114','唐军霞','TJX');\ninsert into user(id, name, py) values('115','唐里丽','TLL');\ninsert into user(id, name, py) values('116','陶姐华','TJH');\ninsert into user(id, name, py) values('117','万圻艳','WZY');\ninsert into user(id, name, py) values('118','王傲凤','WAF');\ninsert into user(id, name, py) values('119','王德英','WDY');\ninsert into user(id, name, py) values('120','王鼎华','WDH');\ninsert into user(id, name, py) values('121','王慧','WH');\ninsert into user(id, name, py) values('122','王佳光','WJG');\ninsert into user(id, name, py) values('123','王家胜','WJS');\ninsert into user(id, name, py) values('124','王竞飞','WJF');\ninsert into user(id, name, py) values('125','王科磊','WKL');\ninsert into user(id, name, py) values('126','王丽章','WLZ');\ninsert into user(id, name, py) values('127','王励苗','WLM');\ninsert into user(id, name, py) values('128','王美东','WMD');\ninsert into user(id, name, py) values('129','王美媛','WMZ');\ninsert into user(id, name, py) values('130','王蕊颖','WRY');\ninsert into user(id, name, py) values('131','王士成','WSC');\ninsert into user(id, name, py) values('132','王熙斌','WXB');\ninsert into user(id, name, py) values('133','王香军','WXJ');\ninsert into user(id, name, py) values('134','王休娜','WXN');\ninsert into user(id, name, py) values('135','王仪行','WYX');\ninsert into user(id, name, py) values('136','王赢基','WYJ');\ninsert into user(id, name, py) values('137','王云芯','WYX');\ninsert into user(id, name, py) values('138','王郑林','WZL');\ninsert into user(id, name, py) values('139','王治良','WZL');\ninsert into user(id, name, py) values('140','王忠宇','WZY');\ninsert into user(id, name, py) values('141','王子冰','WZB');\ninsert into user(id, name, py) values('142','韦新裕','WXY');\ninsert into user(id, name, py) values('143','魏复冉','WFR');\ninsert into user(id, name, py) values('144','吴翰志','WHZ');\ninsert into user(id, name, py) values('145','吴美森','WMS');\ninsert into user(id, name, py) values('146','吴翔良','WXL');\ninsert into user(id, name, py) values('147','吴艳伟','WYW');\ninsert into user(id, name, py) values('148','吴钲辉','WZH');\ninsert into user(id, name, py) values('149','向盼洛','XPL');\ninsert into user(id, name, py) values('150','萧恩','XE');\ninsert into user(id, name, py) values('151','萧军杰','XJJ');\ninsert into user(id, name, py) values('152','萧圣梅','XSM');\ninsert into user(id, name, py) values('153','谢辰吉','XCJ');\ninsert into user(id, name, py) values('154','徐郎求','XLQ');\ninsert into user(id, name, py) values('155','徐铭森','XMS');\ninsert into user(id, name, py) values('156','徐蓉伟','XRW');\ninsert into user(id, name, py) values('157','许为梧','XWW');\ninsert into user(id, name, py) values('158','阎皓河','YZH');\ninsert into user(id, name, py) values('159','阎思华','YSH');\ninsert into user(id, name, py) values('160','杨爱秀','YAX');\ninsert into user(id, name, py) values('161','杨昆飞','YKF');\ninsert into user(id, name, py) values('162','杨良林','YLL');\ninsert into user(id, name, py) values('163','杨少君','YSJ');\ninsert into user(id, name, py) values('164','杨玉丽','YYL');\ninsert into user(id, name, py) values('165','杨之安','YZA');\ninsert into user(id, name, py) values('166','尤榕锋','YZF');\ninsert into user(id, name, py) values('167','余俊珠','YJZ');\ninsert into user(id, name, py) values('168','袁江蔓','YJM');\ninsert into user(id, name, py) values('169','张必翰','ZBH');\ninsert into user(id, name, py) values('170','张昌颜','ZCY');\ninsert into user(id, name, py) values('171','张恩星','ZEX');\ninsert into user(id, name, py) values('172','张飞强','ZFQ');\ninsert into user(id, name, py) values('173','张凤焯','ZFZ');\ninsert into user(id, name, py) values('174','张国强','ZGQ');\ninsert into user(id, name, py) values('175','张计欣','ZJX');\ninsert into user(id, name, py) values('176','张家颖','ZJY');\ninsert into user(id, name, py) values('177','张金安','ZJA');\ninsert into user(id, name, py) values('178','张莉','ZL');\ninsert into user(id, name, py) values('179','张米龙','ZML');\ninsert into user(id, name, py) values('180','张善渊','ZSY');\ninsert into user(id, name, py) values('181','张万敏','ZWM');\ninsert into user(id, name, py) values('182','张晓林','ZXL');\ninsert into user(id, name, py) values('183','张秀高','ZXG');\n"
  },
  {
    "path": "src/test/resources/postgresql/mybatis-config-pagesizezero.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <property name=\"pageSizeZero\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.postgresql.Driver\"/>\n                <property name=\"url\" value=\"jdbc:postgresql://192.168.16.137:5432/pagehelper\"/>\n                <property name=\"username\" value=\"pagehelper\"/>\n                <property name=\"password\" value=\"pagehelper\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/postgresql/mybatis-config-reasonable.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"reasonable\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.postgresql.Driver\"/>\n                <property name=\"url\" value=\"jdbc:postgresql://192.168.16.137:5432/pagehelper\"/>\n                <property name=\"username\" value=\"pagehelper\"/>\n                <property name=\"password\" value=\"pagehelper\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/postgresql/mybatis-config-rowbounds.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.postgresql.Driver\"/>\n                <property name=\"url\" value=\"jdbc:postgresql://192.168.16.137:5432/pagehelper\"/>\n                <property name=\"username\" value=\"pagehelper\"/>\n                <property name=\"password\" value=\"pagehelper\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/postgresql/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <!-- 支持通过Mapper接口参数来传递分页参数 -->\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.postgresql.Driver\"/>\n                <property name=\"url\" value=\"jdbc:postgresql://192.168.16.137:5432/pagehelper\"/>\n                <property name=\"username\" value=\"pagehelper\"/>\n                <property name=\"password\" value=\"pagehelper\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/postgresql/postgresql.sql",
    "content": "﻿/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2022 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\ncreate USER pagehelper WITH PASSWORD 'pagehelper';\n\ncreate\nDATABASE pagehelper OWNER pagehelper;\n\nGRANT ALL PRIVILEGES ON DATABASE pagehelper to pagehelper;\n\nCREATE TABLE user\n(\n    id   SERIAL,\n    name varchar(50) DEFAULT NULL,\n    py   varchar(50) DEFAULT NULL,\n    PRIMARY KEY (Id)\n);\n\nALTER TABLE user OWNER TO pagehelper;\n\ninsert into user(id, name, py) values('1','毕淑儒','BSR');\ninsert into user(id, name, py) values('2','蔡兴熙','CXX');\ninsert into user(id, name, py) values('3','曾三杰','ZSJ');\ninsert into user(id, name, py) values('4','常元琴','CYQ');\ninsert into user(id, name, py) values('5','陈栋芬','CDF');\ninsert into user(id, name, py) values('6','陈宁婷','CNZ');\ninsert into user(id, name, py) values('7','陈瑞','CR');\ninsert into user(id, name, py) values('8','陈武宵','CWX');\ninsert into user(id, name, py) values('9','陈晓丽','CXL');\ninsert into user(id, name, py) values('10','陈翼涛','CYT');\ninsert into user(id, name, py) values('11','陈宇然','CYR');\ninsert into user(id, name, py) values('12','陈震','CZ');\ninsert into user(id, name, py) values('13','程太君','CTJ');\ninsert into user(id, name, py) values('14','程玉娜','CYN');\ninsert into user(id, name, py) values('15','丛贺轩','CHX');\ninsert into user(id, name, py) values('16','戴国宇','DGY');\ninsert into user(id, name, py) values('17','戴杰亮','DJL');\ninsert into user(id, name, py) values('18','丁玉华','DYH');\ninsert into user(id, name, py) values('19','董秋明','DQM');\ninsert into user(id, name, py) values('20','董政厚','DZH');\ninsert into user(id, name, py) values('21','杜玉焱','DYZ');\ninsert into user(id, name, py) values('22','段瑜芝','DZZ');\ninsert into user(id, name, py) values('23','傅广友','FGY');\ninsert into user(id, name, py) values('24','傅井飞','FJF');\ninsert into user(id, name, py) values('25','高辉涛','GHT');\ninsert into user(id, name, py) values('26','高龙飞','GLF');\ninsert into user(id, name, py) values('27','高汝英','GRY');\ninsert into user(id, name, py) values('28','高云天','GYT');\ninsert into user(id, name, py) values('29','郭义民','GYM');\ninsert into user(id, name, py) values('30','郭永洪','GYH');\ninsert into user(id, name, py) values('31','韩国茜','HGZ');\ninsert into user(id, name, py) values('32','韩龙康','HLK');\ninsert into user(id, name, py) values('33','韩伟佳','HWJ');\ninsert into user(id, name, py) values('34','韩扬谦','HYQ');\ninsert into user(id, name, py) values('35','郝静生','HJS');\ninsert into user(id, name, py) values('36','何柏红','HBH');\ninsert into user(id, name, py) values('37','何彩智','HCZ');\ninsert into user(id, name, py) values('38','何陶增','HTZ');\ninsert into user(id, name, py) values('39','何薇','HZ');\ninsert into user(id, name, py) values('40','何小凡','HXF');\ninsert into user(id, name, py) values('41','何振平','HZP');\ninsert into user(id, name, py) values('42','洪彩辉','HCH');\ninsert into user(id, name, py) values('43','胡仕明','HSM');\ninsert into user(id, name, py) values('44','黄建朋','HJP');\ninsert into user(id, name, py) values('45','黄祥荣','HXR');\ninsert into user(id, name, py) values('46','黄璇平','HZP');\ninsert into user(id, name, py) values('47','贾茂飞','JMF');\ninsert into user(id, name, py) values('48','李迪茹','LDR');\ninsert into user(id, name, py) values('49','李桂博','LGB');\ninsert into user(id, name, py) values('50','李国祯','LGZ');\ninsert into user(id, name, py) values('51','李宏川','LHC');\ninsert into user(id, name, py) values('52','李梅','LM');\ninsert into user(id, name, py) values('53','李媚文','LMW');\ninsert into user(id, name, py) values('54','李孟惠','LMH');\ninsert into user(id, name, py) values('55','李南懋','LNZ');\ninsert into user(id, name, py) values('56','李鹏龙','LPL');\ninsert into user(id, name, py) values('57','李诗庸','LSY');\ninsert into user(id, name, py) values('58','李姝勇','LZY');\ninsert into user(id, name, py) values('59','李树鹏','LSP');\ninsert into user(id, name, py) values('60','李薇红','LZH');\ninsert into user(id, name, py) values('61','李文章','LWZ');\ninsert into user(id, name, py) values('62','李星佳','LXJ');\ninsert into user(id, name, py) values('63','李兴','LX');\ninsert into user(id, name, py) values('64','李秀倩','LXZ');\ninsert into user(id, name, py) values('65','李艳生','LYS');\ninsert into user(id, name, py) values('66','李燕金','LYJ');\ninsert into user(id, name, py) values('67','李玉彪','LYB');\ninsert into user(id, name, py) values('68','李振峰','LZF');\ninsert into user(id, name, py) values('69','梁斌芳','LBF');\ninsert into user(id, name, py) values('70','梁国云','LGY');\ninsert into user(id, name, py) values('71','梁巧爱','LQA');\ninsert into user(id, name, py) values('72','梁照金','LZJ');\ninsert into user(id, name, py) values('73','林婧美','LZM');\ninsert into user(id, name, py) values('74','林沛寿','LPS');\ninsert into user(id, name, py) values('75','林薇程','LZC');\ninsert into user(id, name, py) values('76','林伟玉','LWY');\ninsert into user(id, name, py) values('77','林艺玲','LYL');\ninsert into user(id, name, py) values('78','刘睿','LR');\ninsert into user(id, name, py) values('79','刘芊芊','LQQ');\ninsert into user(id, name, py) values('80','刘海波','LHB');\ninsert into user(id, name, py) values('81','刘斓琴','LZQ');\ninsert into user(id, name, py) values('82','刘磊东','LLD');\ninsert into user(id, name, py) values('83','刘明琪','LMZ');\ninsert into user(id, name, py) values('84','刘铭恩','LME');\ninsert into user(id, name, py) values('85','刘任恺','LRZ');\ninsert into user(id, name, py) values('86','刘水秋','LSQ');\ninsert into user(id, name, py) values('87','刘文萱','LWZ');\ninsert into user(id, name, py) values('88','刘祥瑶','LXY');\ninsert into user(id, name, py) values('89','刘薪坪','LXP');\ninsert into user(id, name, py) values('90','刘秀涛','LXT');\ninsert into user(id, name, py) values('91','刘彦利','LYL');\ninsert into user(id, name, py) values('92','刘益存','LYC');\ninsert into user(id, name, py) values('93','龙子苹','LZP');\ninsert into user(id, name, py) values('94','卢秀剑','LXJ');\ninsert into user(id, name, py) values('95','罗乔华','LQH');\ninsert into user(id, name, py) values('96','罗希清','LXQ');\ninsert into user(id, name, py) values('97','马家兰','MJL');\ninsert into user(id, name, py) values('98','马莲莹','MLY');\ninsert into user(id, name, py) values('99','马宁文','MNW');\ninsert into user(id, name, py) values('100','马水鹏','MSP');\ninsert into user(id, name, py) values('101','孟三云','MSY');\ninsert into user(id, name, py) values('102','孟寿云','MSY');\ninsert into user(id, name, py) values('103','聂伟元','NWY');\ninsert into user(id, name, py) values('104','潘永飞','PYF');\ninsert into user(id, name, py) values('105','彭健颖','PJY');\ninsert into user(id, name, py) values('106','钱文松','QWS');\ninsert into user(id, name, py) values('107','屈江珍','QJZ');\ninsert into user(id, name, py) values('108','邵建林','SJL');\ninsert into user(id, name, py) values('109','施家晖','SJZ');\ninsert into user(id, name, py) values('110','施艺英','SYY');\ninsert into user(id, name, py) values('111','孙常程','SCC');\ninsert into user(id, name, py) values('112','谭佳盈','TJY');\ninsert into user(id, name, py) values('113','唐春珊','TCS');\ninsert into user(id, name, py) values('114','唐军霞','TJX');\ninsert into user(id, name, py) values('115','唐里丽','TLL');\ninsert into user(id, name, py) values('116','陶姐华','TJH');\ninsert into user(id, name, py) values('117','万圻艳','WZY');\ninsert into user(id, name, py) values('118','王傲凤','WAF');\ninsert into user(id, name, py) values('119','王德英','WDY');\ninsert into user(id, name, py) values('120','王鼎华','WDH');\ninsert into user(id, name, py) values('121','王慧','WH');\ninsert into user(id, name, py) values('122','王佳光','WJG');\ninsert into user(id, name, py) values('123','王家胜','WJS');\ninsert into user(id, name, py) values('124','王竞飞','WJF');\ninsert into user(id, name, py) values('125','王科磊','WKL');\ninsert into user(id, name, py) values('126','王丽章','WLZ');\ninsert into user(id, name, py) values('127','王励苗','WLM');\ninsert into user(id, name, py) values('128','王美东','WMD');\ninsert into user(id, name, py) values('129','王美媛','WMZ');\ninsert into user(id, name, py) values('130','王蕊颖','WRY');\ninsert into user(id, name, py) values('131','王士成','WSC');\ninsert into user(id, name, py) values('132','王熙斌','WXB');\ninsert into user(id, name, py) values('133','王香军','WXJ');\ninsert into user(id, name, py) values('134','王休娜','WXN');\ninsert into user(id, name, py) values('135','王仪行','WYX');\ninsert into user(id, name, py) values('136','王赢基','WYJ');\ninsert into user(id, name, py) values('137','王云芯','WYX');\ninsert into user(id, name, py) values('138','王郑林','WZL');\ninsert into user(id, name, py) values('139','王治良','WZL');\ninsert into user(id, name, py) values('140','王忠宇','WZY');\ninsert into user(id, name, py) values('141','王子冰','WZB');\ninsert into user(id, name, py) values('142','韦新裕','WXY');\ninsert into user(id, name, py) values('143','魏复冉','WFR');\ninsert into user(id, name, py) values('144','吴翰志','WHZ');\ninsert into user(id, name, py) values('145','吴美森','WMS');\ninsert into user(id, name, py) values('146','吴翔良','WXL');\ninsert into user(id, name, py) values('147','吴艳伟','WYW');\ninsert into user(id, name, py) values('148','吴钲辉','WZH');\ninsert into user(id, name, py) values('149','向盼洛','XPL');\ninsert into user(id, name, py) values('150','萧恩','XE');\ninsert into user(id, name, py) values('151','萧军杰','XJJ');\ninsert into user(id, name, py) values('152','萧圣梅','XSM');\ninsert into user(id, name, py) values('153','谢辰吉','XCJ');\ninsert into user(id, name, py) values('154','徐郎求','XLQ');\ninsert into user(id, name, py) values('155','徐铭森','XMS');\ninsert into user(id, name, py) values('156','徐蓉伟','XRW');\ninsert into user(id, name, py) values('157','许为梧','XWW');\ninsert into user(id, name, py) values('158','阎皓河','YZH');\ninsert into user(id, name, py) values('159','阎思华','YSH');\ninsert into user(id, name, py) values('160','杨爱秀','YAX');\ninsert into user(id, name, py) values('161','杨昆飞','YKF');\ninsert into user(id, name, py) values('162','杨良林','YLL');\ninsert into user(id, name, py) values('163','杨少君','YSJ');\ninsert into user(id, name, py) values('164','杨玉丽','YYL');\ninsert into user(id, name, py) values('165','杨之安','YZA');\ninsert into user(id, name, py) values('166','尤榕锋','YZF');\ninsert into user(id, name, py) values('167','余俊珠','YJZ');\ninsert into user(id, name, py) values('168','袁江蔓','YJM');\ninsert into user(id, name, py) values('169','张必翰','ZBH');\ninsert into user(id, name, py) values('170','张昌颜','ZCY');\ninsert into user(id, name, py) values('171','张恩星','ZEX');\ninsert into user(id, name, py) values('172','张飞强','ZFQ');\ninsert into user(id, name, py) values('173','张凤焯','ZFZ');\ninsert into user(id, name, py) values('174','张国强','ZGQ');\ninsert into user(id, name, py) values('175','张计欣','ZJX');\ninsert into user(id, name, py) values('176','张家颖','ZJY');\ninsert into user(id, name, py) values('177','张金安','ZJA');\ninsert into user(id, name, py) values('178','张莉','ZL');\ninsert into user(id, name, py) values('179','张米龙','ZML');\ninsert into user(id, name, py) values('180','张善渊','ZSY');\ninsert into user(id, name, py) values('181','张万敏','ZWM');\ninsert into user(id, name, py) values('182','张晓林','ZXL');\ninsert into user(id, name, py) values('183','张秀高','ZXG');\n\n"
  },
  {
    "path": "src/test/resources/rowbounds/hsqldb.sql",
    "content": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2014-2022 abel533@gmail.com\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\ndrop table user if exists;\n\ncreate table user\n(\n    id   integer,\n    name varchar(32),\n    py   varchar(5)\n);\n\ninsert into user(id, name, py)\nvalues ('1', '毕淑儒', 'BSR');\ninsert into user(id, name, py) values('2','蔡兴熙','CXX');\ninsert into user(id, name, py) values('3','曾三杰','ZSJ');\ninsert into user(id, name, py) values('4','常元琴','CYQ');\ninsert into user(id, name, py) values('5','陈栋芬','CDF');\ninsert into user(id, name, py) values('6','陈宁婷','CNZ');\ninsert into user(id, name, py) values('7','陈瑞','CR');\ninsert into user(id, name, py) values('8','陈武宵','CWX');\ninsert into user(id, name, py) values('9','陈晓丽','CXL');\ninsert into user(id, name, py) values('10','陈翼涛','CYT');\ninsert into user(id, name, py) values('11','陈宇然','CYR');\ninsert into user(id, name, py) values('12','陈震','CZ');\ninsert into user(id, name, py) values('13','程太君','CTJ');\ninsert into user(id, name, py) values('14','程玉娜','CYN');\ninsert into user(id, name, py) values('15','丛贺轩','CHX');\ninsert into user(id, name, py) values('16','戴国宇','DGY');\ninsert into user(id, name, py) values('17','戴杰亮','DJL');\ninsert into user(id, name, py) values('18','丁玉华','DYH');\ninsert into user(id, name, py) values('19','董秋明','DQM');\ninsert into user(id, name, py) values('20','董政厚','DZH');\ninsert into user(id, name, py) values('21','杜玉焱','DYZ');\ninsert into user(id, name, py) values('22','段瑜芝','DZZ');\ninsert into user(id, name, py) values('23','傅广友','FGY');\ninsert into user(id, name, py) values('24','傅井飞','FJF');\ninsert into user(id, name, py) values('25','高辉涛','GHT');\ninsert into user(id, name, py) values('26','高龙飞','GLF');\ninsert into user(id, name, py) values('27','高汝英','GRY');\ninsert into user(id, name, py) values('28','高云天','GYT');\ninsert into user(id, name, py) values('29','郭义民','GYM');\ninsert into user(id, name, py) values('30','郭永洪','GYH');\ninsert into user(id, name, py) values('31','韩国茜','HGZ');\ninsert into user(id, name, py) values('32','韩龙康','HLK');\ninsert into user(id, name, py) values('33','韩伟佳','HWJ');\ninsert into user(id, name, py) values('34','韩扬谦','HYQ');\ninsert into user(id, name, py) values('35','郝静生','HJS');\ninsert into user(id, name, py) values('36','何柏红','HBH');\ninsert into user(id, name, py) values('37','何彩智','HCZ');\ninsert into user(id, name, py) values('38','何陶增','HTZ');\ninsert into user(id, name, py) values('39','何薇','HZ');\ninsert into user(id, name, py) values('40','何小凡','HXF');\ninsert into user(id, name, py) values('41','何振平','HZP');\ninsert into user(id, name, py) values('42','洪彩辉','HCH');\ninsert into user(id, name, py) values('43','胡仕明','HSM');\ninsert into user(id, name, py) values('44','黄建朋','HJP');\ninsert into user(id, name, py) values('45','黄祥荣','HXR');\ninsert into user(id, name, py) values('46','黄璇平','HZP');\ninsert into user(id, name, py) values('47','贾茂飞','JMF');\ninsert into user(id, name, py) values('48','李迪茹','LDR');\ninsert into user(id, name, py) values('49','李桂博','LGB');\ninsert into user(id, name, py) values('50','李国祯','LGZ');\ninsert into user(id, name, py) values('51','李宏川','LHC');\ninsert into user(id, name, py) values('52','李梅','LM');\ninsert into user(id, name, py) values('53','李媚文','LMW');\ninsert into user(id, name, py) values('54','李孟惠','LMH');\ninsert into user(id, name, py) values('55','李南懋','LNZ');\ninsert into user(id, name, py) values('56','李鹏龙','LPL');\ninsert into user(id, name, py) values('57','李诗庸','LSY');\ninsert into user(id, name, py) values('58','李姝勇','LZY');\ninsert into user(id, name, py) values('59','李树鹏','LSP');\ninsert into user(id, name, py) values('60','李薇红','LZH');\ninsert into user(id, name, py) values('61','李文章','LWZ');\ninsert into user(id, name, py) values('62','李星佳','LXJ');\ninsert into user(id, name, py) values('63','李兴','LX');\ninsert into user(id, name, py) values('64','李秀倩','LXZ');\ninsert into user(id, name, py) values('65','李艳生','LYS');\ninsert into user(id, name, py) values('66','李燕金','LYJ');\ninsert into user(id, name, py) values('67','李玉彪','LYB');\ninsert into user(id, name, py) values('68','李振峰','LZF');\ninsert into user(id, name, py) values('69','梁斌芳','LBF');\ninsert into user(id, name, py) values('70','梁国云','LGY');\ninsert into user(id, name, py) values('71','梁巧爱','LQA');\ninsert into user(id, name, py) values('72','梁照金','LZJ');\ninsert into user(id, name, py) values('73','林婧美','LZM');\ninsert into user(id, name, py) values('74','林沛寿','LPS');\ninsert into user(id, name, py) values('75','林薇程','LZC');\ninsert into user(id, name, py) values('76','林伟玉','LWY');\ninsert into user(id, name, py) values('77','林艺玲','LYL');\ninsert into user(id, name, py) values('78','刘睿','LR');\ninsert into user(id, name, py) values('79','刘芊芊','LQQ');\ninsert into user(id, name, py) values('80','刘海波','LHB');\ninsert into user(id, name, py) values('81','刘斓琴','LZQ');\ninsert into user(id, name, py) values('82','刘磊东','LLD');\ninsert into user(id, name, py) values('83','刘明琪','LMZ');\ninsert into user(id, name, py) values('84','刘铭恩','LME');\ninsert into user(id, name, py) values('85','刘任恺','LRZ');\ninsert into user(id, name, py) values('86','刘水秋','LSQ');\ninsert into user(id, name, py) values('87','刘文萱','LWZ');\ninsert into user(id, name, py) values('88','刘祥瑶','LXY');\ninsert into user(id, name, py) values('89','刘薪坪','LXP');\ninsert into user(id, name, py) values('90','刘秀涛','LXT');\ninsert into user(id, name, py) values('91','刘彦利','LYL');\ninsert into user(id, name, py) values('92','刘益存','LYC');\ninsert into user(id, name, py) values('93','龙子苹','LZP');\ninsert into user(id, name, py) values('94','卢秀剑','LXJ');\ninsert into user(id, name, py) values('95','罗乔华','LQH');\ninsert into user(id, name, py) values('96','罗希清','LXQ');\ninsert into user(id, name, py) values('97','马家兰','MJL');\ninsert into user(id, name, py) values('98','马莲莹','MLY');\ninsert into user(id, name, py) values('99','马宁文','MNW');\ninsert into user(id, name, py) values('100','马水鹏','MSP');\ninsert into user(id, name, py) values('101','孟三云','MSY');\ninsert into user(id, name, py) values('102','孟寿云','MSY');\ninsert into user(id, name, py) values('103','聂伟元','NWY');\ninsert into user(id, name, py) values('104','潘永飞','PYF');\ninsert into user(id, name, py) values('105','彭健颖','PJY');\ninsert into user(id, name, py) values('106','钱文松','QWS');\ninsert into user(id, name, py) values('107','屈江珍','QJZ');\ninsert into user(id, name, py) values('108','邵建林','SJL');\ninsert into user(id, name, py) values('109','施家晖','SJZ');\ninsert into user(id, name, py) values('110','施艺英','SYY');\ninsert into user(id, name, py) values('111','孙常程','SCC');\ninsert into user(id, name, py) values('112','谭佳盈','TJY');\ninsert into user(id, name, py) values('113','唐春珊','TCS');\ninsert into user(id, name, py) values('114','唐军霞','TJX');\ninsert into user(id, name, py) values('115','唐里丽','TLL');\ninsert into user(id, name, py) values('116','陶姐华','TJH');\ninsert into user(id, name, py) values('117','万圻艳','WZY');\ninsert into user(id, name, py) values('118','王傲凤','WAF');\ninsert into user(id, name, py) values('119','王德英','WDY');\ninsert into user(id, name, py) values('120','王鼎华','WDH');\ninsert into user(id, name, py) values('121','王慧','WH');\ninsert into user(id, name, py) values('122','王佳光','WJG');\ninsert into user(id, name, py) values('123','王家胜','WJS');\ninsert into user(id, name, py) values('124','王竞飞','WJF');\ninsert into user(id, name, py) values('125','王科磊','WKL');\ninsert into user(id, name, py) values('126','王丽章','WLZ');\ninsert into user(id, name, py) values('127','王励苗','WLM');\ninsert into user(id, name, py) values('128','王美东','WMD');\ninsert into user(id, name, py) values('129','王美媛','WMZ');\ninsert into user(id, name, py) values('130','王蕊颖','WRY');\ninsert into user(id, name, py) values('131','王士成','WSC');\ninsert into user(id, name, py) values('132','王熙斌','WXB');\ninsert into user(id, name, py) values('133','王香军','WXJ');\ninsert into user(id, name, py) values('134','王休娜','WXN');\ninsert into user(id, name, py) values('135','王仪行','WYX');\ninsert into user(id, name, py) values('136','王赢基','WYJ');\ninsert into user(id, name, py) values('137','王云芯','WYX');\ninsert into user(id, name, py) values('138','王郑林','WZL');\ninsert into user(id, name, py) values('139','王治良','WZL');\ninsert into user(id, name, py) values('140','王忠宇','WZY');\ninsert into user(id, name, py) values('141','王子冰','WZB');\ninsert into user(id, name, py) values('142','韦新裕','WXY');\ninsert into user(id, name, py) values('143','魏复冉','WFR');\ninsert into user(id, name, py) values('144','吴翰志','WHZ');\ninsert into user(id, name, py) values('145','吴美森','WMS');\ninsert into user(id, name, py) values('146','吴翔良','WXL');\ninsert into user(id, name, py) values('147','吴艳伟','WYW');\ninsert into user(id, name, py) values('148','吴钲辉','WZH');\ninsert into user(id, name, py) values('149','向盼洛','XPL');\ninsert into user(id, name, py) values('150','萧恩','XE');\ninsert into user(id, name, py) values('151','萧军杰','XJJ');\ninsert into user(id, name, py) values('152','萧圣梅','XSM');\ninsert into user(id, name, py) values('153','谢辰吉','XCJ');\ninsert into user(id, name, py) values('154','徐郎求','XLQ');\ninsert into user(id, name, py) values('155','徐铭森','XMS');\ninsert into user(id, name, py) values('156','徐蓉伟','XRW');\ninsert into user(id, name, py) values('157','许为梧','XWW');\ninsert into user(id, name, py) values('158','阎皓河','YZH');\ninsert into user(id, name, py) values('159','阎思华','YSH');\ninsert into user(id, name, py) values('160','杨爱秀','YAX');\ninsert into user(id, name, py) values('161','杨昆飞','YKF');\ninsert into user(id, name, py) values('162','杨良林','YLL');\ninsert into user(id, name, py) values('163','杨少君','YSJ');\ninsert into user(id, name, py) values('164','杨玉丽','YYL');\ninsert into user(id, name, py) values('165','杨之安','YZA');\ninsert into user(id, name, py) values('166','尤榕锋','YZF');\ninsert into user(id, name, py) values('167','余俊珠','YJZ');\ninsert into user(id, name, py) values('168','袁江蔓','YJM');\ninsert into user(id, name, py) values('169','张必翰','ZBH');\ninsert into user(id, name, py) values('170','张昌颜','ZCY');\ninsert into user(id, name, py) values('171','张恩星','ZEX');\ninsert into user(id, name, py) values('172','张飞强','ZFQ');\ninsert into user(id, name, py) values('173','张凤焯','ZFZ');\ninsert into user(id, name, py) values('174','张国强','ZGQ');\ninsert into user(id, name, py) values('175','张计欣','ZJX');\ninsert into user(id, name, py) values('176','张家颖','ZJY');\ninsert into user(id, name, py) values('177','张金安','ZJA');\ninsert into user(id, name, py) values('178','张莉','ZL');\ninsert into user(id, name, py) values('179','张米龙','ZML');\ninsert into user(id, name, py) values('180','张善渊','ZSY');\ninsert into user(id, name, py) values('181','张万敏','ZWM');\ninsert into user(id, name, py) values('182','张晓林','ZXL');\ninsert into user(id, name, py) values('183','张秀高','ZXG');\n\n"
  },
  {
    "path": "src/test/resources/rowbounds/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"dialect\" value=\"com.github.pagehelper.dialect.rowbounds.HsqldbRowBoundsDialect\"/>\n            <!-- 支持通过Mapper接口参数来传递分页参数 -->\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <!-- 运行时自动判断数据库类型，支持多数据源DataSource分页 -->\n            <property name=\"autoRuntimeDialect\" value=\"true\"/>\n            <property name=\"closeConn\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <property name=\"sqlCacheClass\" value=\"com.github.pagehelper.cache.SimpleCache\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"org.hsqldb.jdbcDriver\"/>\n                <property name=\"url\" value=\"jdbc:hsqldb:mem:rowbounds\"/>\n                <property name=\"username\" value=\"sa\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/sqlserver/mybatis-config-pagesizezero.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <property name=\"pageSizeZero\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"net.sourceforge.jtds.jdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:jtds:sqlserver://192.168.16.137:1433/master\"/>\n                <property name=\"username\" value=\"sa\"/>\n                <property name=\"password\" value=\"jj\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/sqlserver/mybatis-config-reasonable.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"reasonable\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"net.sourceforge.jtds.jdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:jtds:sqlserver://192.168.16.137:1433/master\"/>\n                <property name=\"username\" value=\"sa\"/>\n                <property name=\"password\" value=\"jj\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/sqlserver/mybatis-config-rowbounds.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"net.sourceforge.jtds.jdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:jtds:sqlserver://192.168.16.137:1433/master\"/>\n                <property name=\"username\" value=\"sa\"/>\n                <property name=\"password\" value=\"jj\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/sqlserver/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2023 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"net.sourceforge.jtds.jdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:jtds:sqlserver://192.168.16.137:1433/master\"/>\n                <property name=\"username\" value=\"sa\"/>\n                <property name=\"password\" value=\"jj\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/test.properties",
    "content": "#\n# The MIT License (MIT)\n#\n# Copyright (c) 2014-2023 abel533@gmail.com\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n#\n\n#\\u9996\\u5148\\u9700\\u8981\\u5728\\u672C\\u673A\\u914D\\u7F6E\\u5BF9\\u5E94\\u7684\\u6570\\u636E\\u5E93\n\n#\\u60F3\\u8981\\u6D4B\\u8BD5\\u90A3\\u4E2A\\u6570\\u636E\\u5E93\\uFF0C\\u8FD9\\u91CC\\u5C31\\u5199\\u90A3\\u4E2A\\u6570\\u636E\\u5E93\n#\\u8FD9\\u4E2A\\u503C\\u548Ctest/resources\\u4E2D\\u7684\\u6570\\u636E\\u5E93\\u5BF9\\u5E94\\u7684\\u6587\\u4EF6\\u5939\\u540D\\u5B57\\u76F8\\u540C\n#\\u76EE\\u524D\\u53EF\\u9009\\u4E3A:\n#hsqldb\n#mysql\n#mariadb - \\u6CE8\\u610F\\u6D4B\\u8BD5\\u4E2D\\u7684\\u7AEF\\u53E3\\u662F3309(\\u56E0\\u4E3A\\u9ED8\\u8BA4\\u548Cmysql\\u662F\\u4E00\\u6837\\u7684)\n#oracle\n#postgresql\n#sqlserver\n#db2\n#informix - \\u4E0D\\u5305\\u542Binformix\\u7684\\u914D\\u7F6E\\uFF0C\\u4E0D\\u652F\\u6301\\u6D4B\\u8BD5\n#h2\n#derby\ndatabase = hsqldb\n"
  },
  {
    "path": "src/test/resources/xugu/mybatis-config-interceptor.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2017 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.test.basic.provider.SqlCacheInterceptor\">\n        </plugin>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <!-- 支持通过Mapper接口参数来传递分页参数 -->\n            <property name=\"helperDialect\" value=\"xugu\"/>\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <property name=\"boundSqlInterceptors\"\n                      value=\"com.github.pagehelper.test.basic.provider.TestBoundSqlInterceptor,com.github.pagehelper.test.basic.provider.TestBoundSqlInterceptor\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.xugu.cloudjdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:xugu://localhost:5138/pagehelper?keyword_filter=USER\"/>\n                <property name=\"username\" value=\"SYSDBA\"/>\n                <property name=\"password\" value=\"SYSDBA\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/xugu/mybatis-config-pagesizezero.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2017 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"helperDialect\" value=\"xugu\"/>\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n            <property name=\"pageSizeZero\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.xugu.cloudjdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:xugu://localhost:5138/pagehelper?keyword_filter=USER\"/>\n                <property name=\"username\" value=\"SYSDBA\"/>\n                <property name=\"password\" value=\"SYSDBA\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/xugu/mybatis-config-reasonable.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2017 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"helperDialect\" value=\"xugu\"/>\n            <property name=\"reasonable\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.xugu.cloudjdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:xugu://localhost:5138/pagehelper?keyword_filter=USER\"/>\n                <property name=\"username\" value=\"SYSDBA\"/>\n                <property name=\"password\" value=\"SYSDBA\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/xugu/mybatis-config-rowbounds.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2017 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <property name=\"helperDialect\" value=\"xugu\"/>\n            <property name=\"offsetAsPageNum\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.xugu.cloudjdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:xugu://localhost:5138/pagehelper?keyword_filter=USER\"/>\n                <property name=\"username\" value=\"SYSDBA\"/>\n                <property name=\"password\" value=\"SYSDBA\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/xugu/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!--\n  ~ The MIT License (MIT)\n  ~\n  ~ Copyright (c) 2014-2017 abel533@gmail.com\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in\n  ~ all copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  ~ THE SOFTWARE.\n  -->\n\n<!DOCTYPE configuration\n        PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n\n<configuration>\n    <settings>\n        <setting name=\"cacheEnabled\" value=\"true\"/>\n        <setting name=\"lazyLoadingEnabled\" value=\"false\"/>\n        <setting name=\"aggressiveLazyLoading\" value=\"true\"/>\n    </settings>\n\n    <typeAliases>\n        <package name=\"com.github.pagehelper.model\"/>\n    </typeAliases>\n\n    <plugins>\n        <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n            <!-- 支持通过Mapper接口参数来传递分页参数 -->\n            <property name=\"helperDialect\" value=\"xugu\"/>\n            <property name=\"supportMethodsArguments\" value=\"true\"/>\n            <property name=\"rowBoundsWithCount\" value=\"true\"/>\n        </plugin>\n    </plugins>\n\n    <environments default=\"development\">\n        <environment id=\"development\">\n            <transactionManager type=\"JDBC\">\n                <property name=\"\" value=\"\"/>\n            </transactionManager>\n            <dataSource type=\"UNPOOLED\">\n                <property name=\"driver\" value=\"com.xugu.cloudjdbc.Driver\"/>\n                <property name=\"url\" value=\"jdbc:xugu://localhost:5138/pagehelper?keyword_filter=USER\"/>\n                <property name=\"username\" value=\"SYSDBA\"/>\n                <property name=\"password\" value=\"SYSDBA\"/>\n            </dataSource>\n        </environment>\n    </environments>\n\n    <mappers>\n        <mapper resource=\"com/github/pagehelper/mapper/UserMapper.xml\"/>\n    </mappers>\n\n</configuration>\n"
  },
  {
    "path": "src/test/resources/xugu/mysql.sql",
    "content": "﻿CREATE DATABASE pagehelper CHARACTER SET utf8;\n\nUSE pagehelper;\nDROP TABLE IF EXISTS `user`;\n\nCREATE TABLE `user` (\n                        `id` int  IDENTITY(1,1) NOT NULL,\n                        `name` varchar(50) DEFAULT NULL,\n                        `py` varchar(50) DEFAULT NULL,\n                        PRIMARY KEY (`Id`)\n) ;\n\ninsert into `user`(id, name, py) values('1','毕淑儒','BSR');\ninsert into `user`(id, name, py) values('2','蔡兴熙','CXX');\ninsert into `user`(id, name, py) values('3','曾三杰','ZSJ');\ninsert into `user`(id, name, py) values('4','常元琴','CYQ');\ninsert into `user`(id, name, py) values('5','陈栋芬','CDF');\ninsert into `user`(id, name, py) values('6','陈宁婷','CNZ');\ninsert into `user`(id, name, py) values('7','陈瑞','CR');\ninsert into `user`(id, name, py) values('8','陈武宵','CWX');\ninsert into `user`(id, name, py) values('9','陈晓丽','CXL');\ninsert into `user`(id, name, py) values('10','陈翼涛','CYT');\ninsert into `user`(id, name, py) values('11','陈宇然','CYR');\ninsert into `user`(id, name, py) values('12','陈震','CZ');\ninsert into `user`(id, name, py) values('13','程太君','CTJ');\ninsert into `user`(id, name, py) values('14','程玉娜','CYN');\ninsert into `user`(id, name, py) values('15','丛贺轩','CHX');\ninsert into `user`(id, name, py) values('16','戴国宇','DGY');\ninsert into `user`(id, name, py) values('17','戴杰亮','DJL');\ninsert into `user`(id, name, py) values('18','丁玉华','DYH');\ninsert into `user`(id, name, py) values('19','董秋明','DQM');\ninsert into `user`(id, name, py) values('20','董政厚','DZH');\ninsert into `user`(id, name, py) values('21','杜玉焱','DYZ');\ninsert into `user`(id, name, py) values('22','段瑜芝','DZZ');\ninsert into `user`(id, name, py) values('23','傅广友','FGY');\ninsert into `user`(id, name, py) values('24','傅井飞','FJF');\ninsert into `user`(id, name, py) values('25','高辉涛','GHT');\ninsert into `user`(id, name, py) values('26','高龙飞','GLF');\ninsert into `user`(id, name, py) values('27','高汝英','GRY');\ninsert into `user`(id, name, py) values('28','高云天','GYT');\ninsert into `user`(id, name, py) values('29','郭义民','GYM');\ninsert into `user`(id, name, py) values('30','郭永洪','GYH');\ninsert into `user`(id, name, py) values('31','韩国茜','HGZ');\ninsert into `user`(id, name, py) values('32','韩龙康','HLK');\ninsert into `user`(id, name, py) values('33','韩伟佳','HWJ');\ninsert into `user`(id, name, py) values('34','韩扬谦','HYQ');\ninsert into `user`(id, name, py) values('35','郝静生','HJS');\ninsert into `user`(id, name, py) values('36','何柏红','HBH');\ninsert into `user`(id, name, py) values('37','何彩智','HCZ');\ninsert into `user`(id, name, py) values('38','何陶增','HTZ');\ninsert into `user`(id, name, py) values('39','何薇','HZ');\ninsert into `user`(id, name, py) values('40','何小凡','HXF');\ninsert into `user`(id, name, py) values('41','何振平','HZP');\ninsert into `user`(id, name, py) values('42','洪彩辉','HCH');\ninsert into `user`(id, name, py) values('43','胡仕明','HSM');\ninsert into `user`(id, name, py) values('44','黄建朋','HJP');\ninsert into `user`(id, name, py) values('45','黄祥荣','HXR');\ninsert into `user`(id, name, py) values('46','黄璇平','HZP');\ninsert into `user`(id, name, py) values('47','贾茂飞','JMF');\ninsert into `user`(id, name, py) values('48','李迪茹','LDR');\ninsert into `user`(id, name, py) values('49','李桂博','LGB');\ninsert into `user`(id, name, py) values('50','李国祯','LGZ');\ninsert into `user`(id, name, py) values('51','李宏川','LHC');\ninsert into `user`(id, name, py) values('52','李梅','LM');\ninsert into `user`(id, name, py) values('53','李媚文','LMW');\ninsert into `user`(id, name, py) values('54','李孟惠','LMH');\ninsert into `user`(id, name, py) values('55','李南懋','LNZ');\ninsert into `user`(id, name, py) values('56','李鹏龙','LPL');\ninsert into `user`(id, name, py) values('57','李诗庸','LSY');\ninsert into `user`(id, name, py) values('58','李姝勇','LZY');\ninsert into `user`(id, name, py) values('59','李树鹏','LSP');\ninsert into `user`(id, name, py) values('60','李薇红','LZH');\ninsert into `user`(id, name, py) values('61','李文章','LWZ');\ninsert into `user`(id, name, py) values('62','李星佳','LXJ');\ninsert into `user`(id, name, py) values('63','李兴','LX');\ninsert into `user`(id, name, py) values('64','李秀倩','LXZ');\ninsert into `user`(id, name, py) values('65','李艳生','LYS');\ninsert into `user`(id, name, py) values('66','李燕金','LYJ');\ninsert into `user`(id, name, py) values('67','李玉彪','LYB');\ninsert into `user`(id, name, py) values('68','李振峰','LZF');\ninsert into `user`(id, name, py) values('69','梁斌芳','LBF');\ninsert into `user`(id, name, py) values('70','梁国云','LGY');\ninsert into `user`(id, name, py) values('71','梁巧爱','LQA');\ninsert into `user`(id, name, py) values('72','梁照金','LZJ');\ninsert into `user`(id, name, py) values('73','林婧美','LZM');\ninsert into `user`(id, name, py) values('74','林沛寿','LPS');\ninsert into `user`(id, name, py) values('75','林薇程','LZC');\ninsert into `user`(id, name, py) values('76','林伟玉','LWY');\ninsert into `user`(id, name, py) values('77','林艺玲','LYL');\ninsert into `user`(id, name, py) values('78','刘睿','LR');\ninsert into `user`(id, name, py) values('79','刘芊芊','LQQ');\ninsert into `user`(id, name, py) values('80','刘海波','LHB');\ninsert into `user`(id, name, py) values('81','刘斓琴','LZQ');\ninsert into `user`(id, name, py) values('82','刘磊东','LLD');\ninsert into `user`(id, name, py) values('83','刘明琪','LMZ');\ninsert into `user`(id, name, py) values('84','刘铭恩','LME');\ninsert into `user`(id, name, py) values('85','刘任恺','LRZ');\ninsert into `user`(id, name, py) values('86','刘水秋','LSQ');\ninsert into `user`(id, name, py) values('87','刘文萱','LWZ');\ninsert into `user`(id, name, py) values('88','刘祥瑶','LXY');\ninsert into `user`(id, name, py) values('89','刘薪坪','LXP');\ninsert into `user`(id, name, py) values('90','刘秀涛','LXT');\ninsert into `user`(id, name, py) values('91','刘彦利','LYL');\ninsert into `user`(id, name, py) values('92','刘益存','LYC');\ninsert into `user`(id, name, py) values('93','龙子苹','LZP');\ninsert into `user`(id, name, py) values('94','卢秀剑','LXJ');\ninsert into `user`(id, name, py) values('95','罗乔华','LQH');\ninsert into `user`(id, name, py) values('96','罗希清','LXQ');\ninsert into `user`(id, name, py) values('97','马家兰','MJL');\ninsert into `user`(id, name, py) values('98','马莲莹','MLY');\ninsert into `user`(id, name, py) values('99','马宁文','MNW');\ninsert into `user`(id, name, py) values('100','马水鹏','MSP');\ninsert into `user`(id, name, py) values('101','孟三云','MSY');\ninsert into `user`(id, name, py) values('102','孟寿云','MSY');\ninsert into `user`(id, name, py) values('103','聂伟元','NWY');\ninsert into `user`(id, name, py) values('104','潘永飞','PYF');\ninsert into `user`(id, name, py) values('105','彭健颖','PJY');\ninsert into `user`(id, name, py) values('106','钱文松','QWS');\ninsert into `user`(id, name, py) values('107','屈江珍','QJZ');\ninsert into `user`(id, name, py) values('108','邵建林','SJL');\ninsert into `user`(id, name, py) values('109','施家晖','SJZ');\ninsert into `user`(id, name, py) values('110','施艺英','SYY');\ninsert into `user`(id, name, py) values('111','孙常程','SCC');\ninsert into `user`(id, name, py) values('112','谭佳盈','TJY');\ninsert into `user`(id, name, py) values('113','唐春珊','TCS');\ninsert into `user`(id, name, py) values('114','唐军霞','TJX');\ninsert into `user`(id, name, py) values('115','唐里丽','TLL');\ninsert into `user`(id, name, py) values('116','陶姐华','TJH');\ninsert into `user`(id, name, py) values('117','万圻艳','WZY');\ninsert into `user`(id, name, py) values('118','王傲凤','WAF');\ninsert into `user`(id, name, py) values('119','王德英','WDY');\ninsert into `user`(id, name, py) values('120','王鼎华','WDH');\ninsert into `user`(id, name, py) values('121','王慧','WH');\ninsert into `user`(id, name, py) values('122','王佳光','WJG');\ninsert into `user`(id, name, py) values('123','王家胜','WJS');\ninsert into `user`(id, name, py) values('124','王竞飞','WJF');\ninsert into `user`(id, name, py) values('125','王科磊','WKL');\ninsert into `user`(id, name, py) values('126','王丽章','WLZ');\ninsert into `user`(id, name, py) values('127','王励苗','WLM');\ninsert into `user`(id, name, py) values('128','王美东','WMD');\ninsert into `user`(id, name, py) values('129','王美媛','WMZ');\ninsert into `user`(id, name, py) values('130','王蕊颖','WRY');\ninsert into `user`(id, name, py) values('131','王士成','WSC');\ninsert into `user`(id, name, py) values('132','王熙斌','WXB');\ninsert into `user`(id, name, py) values('133','王香军','WXJ');\ninsert into `user`(id, name, py) values('134','王休娜','WXN');\ninsert into `user`(id, name, py) values('135','王仪行','WYX');\ninsert into `user`(id, name, py) values('136','王赢基','WYJ');\ninsert into `user`(id, name, py) values('137','王云芯','WYX');\ninsert into `user`(id, name, py) values('138','王郑林','WZL');\ninsert into `user`(id, name, py) values('139','王治良','WZL');\ninsert into `user`(id, name, py) values('140','王忠宇','WZY');\ninsert into `user`(id, name, py) values('141','王子冰','WZB');\ninsert into `user`(id, name, py) values('142','韦新裕','WXY');\ninsert into `user`(id, name, py) values('143','魏复冉','WFR');\ninsert into `user`(id, name, py) values('144','吴翰志','WHZ');\ninsert into `user`(id, name, py) values('145','吴美森','WMS');\ninsert into `user`(id, name, py) values('146','吴翔良','WXL');\ninsert into `user`(id, name, py) values('147','吴艳伟','WYW');\ninsert into `user`(id, name, py) values('148','吴钲辉','WZH');\ninsert into `user`(id, name, py) values('149','向盼洛','XPL');\ninsert into `user`(id, name, py) values('150','萧恩','XE');\ninsert into `user`(id, name, py) values('151','萧军杰','XJJ');\ninsert into `user`(id, name, py) values('152','萧圣梅','XSM');\ninsert into `user`(id, name, py) values('153','谢辰吉','XCJ');\ninsert into `user`(id, name, py) values('154','徐郎求','XLQ');\ninsert into `user`(id, name, py) values('155','徐铭森','XMS');\ninsert into `user`(id, name, py) values('156','徐蓉伟','XRW');\ninsert into `user`(id, name, py) values('157','许为梧','XWW');\ninsert into `user`(id, name, py) values('158','阎皓河','YZH');\ninsert into `user`(id, name, py) values('159','阎思华','YSH');\ninsert into `user`(id, name, py) values('160','杨爱秀','YAX');\ninsert into `user`(id, name, py) values('161','杨昆飞','YKF');\ninsert into `user`(id, name, py) values('162','杨良林','YLL');\ninsert into `user`(id, name, py) values('163','杨少君','YSJ');\ninsert into `user`(id, name, py) values('164','杨玉丽','YYL');\ninsert into `user`(id, name, py) values('165','杨之安','YZA');\ninsert into `user`(id, name, py) values('166','尤榕锋','YZF');\ninsert into `user`(id, name, py) values('167','余俊珠','YJZ');\ninsert into `user`(id, name, py) values('168','袁江蔓','YJM');\ninsert into `user`(id, name, py) values('169','张必翰','ZBH');\ninsert into `user`(id, name, py) values('170','张昌颜','ZCY');\ninsert into `user`(id, name, py) values('171','张恩星','ZEX');\ninsert into `user`(id, name, py) values('172','张飞强','ZFQ');\ninsert into `user`(id, name, py) values('173','张凤焯','ZFZ');\ninsert into `user`(id, name, py) values('174','张国强','ZGQ');\ninsert into `user`(id, name, py) values('175','张计欣','ZJX');\ninsert into `user`(id, name, py) values('176','张家颖','ZJY');\ninsert into `user`(id, name, py) values('177','张金安','ZJA');\ninsert into `user`(id, name, py) values('178','张莉','ZL');\ninsert into `user`(id, name, py) values('179','张米龙','ZML');\ninsert into `user`(id, name, py) values('180','张善渊','ZSY');\ninsert into `user`(id, name, py) values('181','张万敏','ZWM');\ninsert into `user`(id, name, py) values('182','张晓林','ZXL');\ninsert into `user`(id, name, py) values('183','张秀高','ZXG');\n"
  },
  {
    "path": "wikis/en/Changelog.md",
    "content": "## Changelog\n\n### 6.1.1 - 2025-06-20\n\n- Add pagination support for SunDB database **by wangsl**\n- Add adapter support for Xugu (虚谷数据库) database **by 吴启洋**\n- Fix issue where `additionalParameter` was not properly copied when copying `countBoundSql` **by yefeng**\n- Fix `offsetPage` example code error **by S00ahKim**\n- Fix Jakarta/Javax ServletRequest compatibility issue, support Spring Boot 3.x **by PING**\n- Add `PageInfo.of()` overloaded method to support manually specifying total record count for pagination info **by yesAnd**\n- Upgrade MyBatis version to 3.5.19 (from 3.5.10)\n- Upgrade Guava version to 33.4.8-jre (from 32.0.0-jre)\n- Upgrade Logback Classic version to 1.2.13 (from 1.2.11)\n- Optimize Xugu JDBC dependency configuration, add `<scope>test</scope>`\n- Fix typos and link references in English documentation **by Coco Liliace**\n- Add relevant comments to improve code readability **by yesAnd**\n- Resolve dependency security vulnerabilities, update related component versions\n\n#### Compatibility Notes\n- This version maintains backward compatibility with previous versions\n- New database support: SunDB, Xugu (虚谷数据库)\n- Fixed Spring Boot 3.x compatibility issues, recommended for users using Jakarta EE\n\n#### Upgrade Recommendations\n- All users are recommended to upgrade, especially those using Spring Boot 3.x or requiring new database support\n- Users of SunDB or Xugu databases can directly use pagination features\n- Please ensure dependency version compatibility before\n\n### 6.1.0 - 2023-12-16\n\n- Released version 6.1.0, PageHelper provides direct dependency on jsqlparser as intermediate interfaces, allowing\n  default implementation replacement through SPI.\n- Upgraded jsqlparser version to 4.7, re-implemented order by, pagination, and count queries.\n- Simplified pom.xml configuration, removed shade-embedded jsqlparser approach, and switched to selecting different\n  jsqlparser versions through external dependencies, allowing self-SPI extension.\n- jsqlparser parsing no longer uses a thread pool, supporting SPI extension to override SqlParser implementation.\n- Changed SqlServer pagination to SqlServerSqlParser interface, added parameter sqlServerSqlParser to override the\n  default value.\n- Extracted OrderByParser to OrderBySqlParser interface, added orderBySqlParser parameter to override the default\n  implementation.\n- Changed static methods of OrderByParser to regular methods, preparing for future interface changes.\n- JSqlParser interface is no longer needed after JDK 8+, removed the interface, and marked the parameter in the\n  documentation (_This parameter was used in the early stages to support special configuration for SQL Server_).\n  Compatible with jsqlparser 4.7 version.\n- Fixed maven-compiler-plugin version to remove warnings and improve build stability. qxo\n- Added .vscode to .gitignore for vscode IDE. qxo\n- Fixed bug https://github.com/pagehelper/Mybatis-PageHelper/issues/779. chenyuehui\n\nTo ensure compatibility with jsqlparser 4.5, 4.7, and possible future versions,\na new project called pagehelper-sqlparser has been created.\nCurrently, it provides two implementations: 4.5 and 4.7.\nTo use it, exclude jsqlparser from pagehelper and select one jsqlparser implementation.\nThe current version defaults to using the code from version 4.7.\nIf you want to switch to the 4.5 implementation, follow the configuration steps below:\n\n```xml\n<dependency>\n    <groupId>com.github.pagehelper</groupId>\n    <artifactId>pagehelper</artifactId>\n    <version>6.1.0</version>\n    <exclusions>\n        <exclusion>\n            <groupId>com.github.jsqlparser</groupId>\n            <artifactId>jsqlparser</artifactId>\n        </exclusion>\n    </exclusions>\n</dependency>\n<dependency>\n    <groupId>com.github.pagehelper</groupId>\n    <artifactId>sqlparser4.5</artifactId>\n    <version>6.1.0</version>\n</dependency>\n```\n\nThe priority of replacing default values with SPI is lower than the implementations specified by the sqlServerSqlParser,\norderBySqlParser, and countSqlParser parameters.\nIf no specific implementation is specified, the SPI implementation will take effect if available.\nYou can refer to the code in the pagehelper-sqlsource module for SPI implementation examples.\n\nBy default, JSqlParser uses a temporarily created `Executors.newSingleThreadExecutor()` for parsing SQL.\nHere, the thread pool is bypassed through the API:\n\n```java\nCCJSqlParser parser = CCJSqlParserUtil.newParser(statementReader);\nparser.withSquareBracketQuotation(true);\nreturn parser.Statement();\n```\n\nThe purpose of using a thread pool in JSqlParser is to prevent parsing timeouts. Therefore, if you have encountered\ntimeout situations,\nyou can introduce the following dependency (which overrides the default implementation through SPI with a timeout of 10\nseconds):\n\n```xml\n<dependency>\n    <groupId>com.github.pagehelper</groupId>\n    <artifactId>sqlparser-timeout</artifactId>\n    <version>6.1.0</version>\n</dependency>\n```\n\n### 6.0.0 - 2023-11-05\n\n- Based on JDK 8 adaptation, JDK 6 and 7 are not supported from 6.0 onwards, and 5.x versions can be used if necessary\n- Added asynchronous count support, configure `asyncCount` globally, default `false`，single activation\n  by `PageHelper.startPage(1, 10).enableAsyncCount()`;\n  Asynchronous queries are performed using independent connections (transactions),\n  and it is not suitable to enable asynchronous queries when the query is affected by addition, deletion, and\n  modification operations. closed #334\n- JSqlParser opens `parser.withSquareBracketQuotation(true)` by default and supports SqlServer `[]`(**6.1.0 remove this\n  parameter**)\n- feat: A new method for data object conversion has been added to the `PageInfo`,\n  method: ` <E> PageInfo<E> convert(Page.Function<T, E> function)` **by codeke**\n- `CountSqlParser` is changed to an interface, allowing the `countSqlParser` parameter to be replaced with your own\n  implementation, which is supported #772\n- `dialectAlias` supports simplified configurations, e.g. `dm=oracle;oracle=oracle9i`, a direct reference to the current\n  abbreviation, without writing the full name of the class\n- `countColumn`add injection detection, fixed #686\n- Add the `PageParam` class, which does not embed objects (will affect the use), if you want to use, you can inherit the\n  object,closed #562\n- All exception messages have been changed to English\n- open `setLocalPage` method, support #771\n- Solve the problem of handling order by error when `sqlserver` with union sql parsing,fixed #768\n- Optimized the total logic to solve the problem that the query is not pagination and the order by is invalid. fixed\n  #641\n- Modify the dialect instantiation logic to ensure that the class is used after the configuration is completed. fixed\n  #742\n- `dialectAliasMap` change to `LinkedHashMap` type, support matching in configuration order, fixed #758\n- fixed the pagination bug of xingyun database **by maimaitiyaer_bonc**\n-\n### 5.3.3 - 2023-06-03\n\n- Ignoring unnecessarily generated surefire-report **by java-codehunger**\n- Supports parsing of the dialect corresponding to the openGauss database from the URL **by saxisuer**\n- Fixed the issue that SQL injection verification was incorrect #716 **by uyong**\n- Support parsing of the dialect corresponding to Kingbase 8 from the URL **by univ**\n- Add support for cirrodata #705 **by sxh0570**\n\n### 5.3.2 - 2022-09-18\n\n- Use document update, all parameters are included, the default home page document changed to Chinese.\n- Add support for kingbase. by **HanHuimin001**\n- Add 'debug' parameter, default 'false', turn on 'debug' mode when 'true', call stack will be recorded after 'debug'\n  mode starts. by **huyingqian**\n- add supports for count sql hint syntax. by **zhanliquan**\n- Add a `PageProperties` interface, which can be used by the instantiated extension class inside the framework to obtain\n  the paging plug-in configuration.\n- To add the `CountMsIdGen` interface, you can configure a custom implementation class by `CountMsIdGen`, which is used\n  to generate the msId for the query corresponding to the COUNT query. The default implementation is still `countSuffix`\n  , with extensions like 'selectByExample' mapped to the corresponding 'selectCountByExample' method.\n- Added `keepOrderBy` and `keepSubSelectOrderBy` configurations.\n- Add the `sqlParser` configuration and add the `JSqlParser` interface to solve the problem that JSqlParser and JDK\n  compatibility cause no additional configuration.(**6.1.0 remove this parameter**)\n- The test uses the Logback logging framework and removes log4j.\n- Resolve that 'dialectKey' is empty resulting in NPE，fixed #656\n\nFor a detailed description of the above parameters, see [**How to use PageHelper**](HowToUse.md).\n\n### 5.3.1 - 2022-06-14\n\n- Resolve CVE-2022-28111 vulnerability, limit the order by parameter, avoid SQL injection\n- Add support for as400. **by bluezealot**\n- Optimize generic parameters of `Page` class **by Zhang Fulai * *\n- Standardize the order of PostgreSQL paging parameters **by outian**\n\n### 5.3.0 - 2021-10-07\n\n- Add `AutoDialect` interface to automatically obtain the database type, which can be configured as its own\n  implementation class through `autoDialectClass`. By default, `DataSourceNegotiationAutoDialect` is used, which is\n  obtained according to the connection pool first. In the default implementation, special processing is added\n  for `hikari,druid,tomcat-jdbc,c3p0,dbcp` type database connection pools, and jdbcUrl are obtained directly from the\n  configuration. When other types of data sources are used, the connection is still obtained in the old way. You can\n  configure `autoDialectClass=old` when you want to use exactly the same way as the old version. When the database\n  connection pool type is very clear, it is recommended to configure it as a specific value. For example, when using\n  hikari, configure `autoDialectClass=hikari`, and when using other connection pools, configure it as its own\n  implementation class.\n- Enable dynamic designation of dialect implementation at runtime, such\n  as `PageHelper.startPage(1, 10).using(\"oracle\");` Or `PageHelper.startPage(2, 10).using(\"org.exmaple.CustomDialect\");`\n- `PageInfo` adds the empty instance constant attribute `PageInfo.EMPTY` and the content judgment `boolean hasContent()`\n  .\n- Adding banner to startup requires log level debug, which can be closed by `-Dpagehelper.banner=false` or environment\n  variable `PAGEHELPER_BANNER=false`.\n  ```\n   DEBUG [main] -\n\n   ,------.                           ,--.  ,--.         ,--.\n   |  .--. '  ,--,--.  ,---.   ,---.  |  '--'  |  ,---.  |  |  ,---.   ,---.  ,--.--.\n   |  '--' | ' ,-.  | | .-. | | .-. : |  .--.  | | .-. : |  | | .-. | | .-. : |  .--'\n   |  | --'  \\ '-'  | ' '-' ' \\   --. |  |  |  | \\   --. |  | | '-' ' \\   --. |  |\n   `--'       `--`--' .`-  /   `----' `--'  `--'  `----' `--' |  |-'   `----' `--'\n   `---'                                   `--'                        is intercepting.\n   ```\n  The purpose of adding banner is that if you configure paging plug-ins multiple times, you will see banner output\n  multiple times, and you can see where it has been instantiated at the breakpoint of the `PageInterceptor` constructor.\n- Improve the Count query. When having exists, the query column is not optimized. The query column is not optimized when\n  there are functions or operations with aliases in the column, so as to avoid that aliases used in order by or having\n  do not exist.\n- It is judged that processing some data (such as TDEngine) returns null when there is no result in querying count.\n- Adding Firebird database support is the same as SqlServer2012 paging syntax.\n- Add impala database automatic recognition.\n- Upgrade JSqlParser to version 4.2.\n\n### 5.2.1 - 2021-06-20\n\n- Upgrade dependency jsqlparser 4.0, mybatis 3.5.7\n- Automatically recognize the following databases：\n  - 虚谷数据库 xugu #599\n  - 神通数据库 oscar by **ranqing**\n  - 瀚高数据库 highgo by **ashaiqing**\n- BoundSqlInterceptorChain interceptor index parameter bug, fixed #587\n- fixed #558\n- Add PostgreSQL dialect by **liym@home**\n- fixed #604, Solve the problem of total loss\n- Add code comments, fixed #547\n\n### 5.2.0 - 2020-07-26\n\n- Upgrading jsqlparser to version 3.2 makes sql parsing better and supports sqlserver better.\n\n- Modify the substitution regularity in sqlserver mode, and now allow spaces in `with( nolock)` brackets.\n\n- Solving the bugs in reasonable, pageSizeZero and offset usage, the meaning and result are more consistent now.\n\n- In the process of splicing paging SQL, a new line character is added to avoid invalid paging part caused by comments in the original SQL.\n\n- ROW_ID alias in Oracle and Db2 is changed to PAGEHELPER_ROW_ID to avoid conflict with common names.\n\n- Solve the special problem when using other interceptors with a single parameter ProviderSql (support mybatis 3.4.0+) [by Luo Zhenyu](https://github.com/luozhenyu)\n\n- Automatic identification of clickhouse is supported, and paging is performed by MySQL.\n\n- Change startRow, endRow type from int to long.\n\n- Page adds a `public <T> PageInfo<T> toPageInfo(Function<E, T> function)` method to convert the data in the query results.\n\n- Refer to `Oracle9iDialect` provided by pr#476, which is also a paging method used before. You can test and select the appropriate paging method by yourself.\n\n   At present, there are two kinds of Oracle pagination as follows:\n   ```sql\n   -- OracleDialect outer control range\n   WHERE ROW_ID <= ? AND ROW_ID > ?\n   -- Oracle9iDialect's internal and external control scope respectively\n   TMP_PAGE WHERE ROWNUM <= ? ) WHERE ROW_ID > ?\n  ```\n- Adding `BoundSqlInterceptor` of PageHelper plug-in can process or simply read SQL in three stages, adding `boundSqlInterceptors`, and configuring multiple implementation class names that implement `BoundSqlInterceptor` interface, separated by English commas. PageHelper can also be set for this paging through a `PageHelper.startPage(x,x).boundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor)`.\n\nThe biggest change of this update is the addition of `BoundSqlInterceptor`, which can intercept the SQL(BoundSQL object) of paging processing at runtime:\n\n```java\n/**\n * BoundSql 处理器\n */\npublic interface BoundSqlInterceptor {\n    /**\n     * boundsql 处理\n     *\n     * @param type     类型\n     * @param boundSql 当前类型的 boundSql\n     * @param cacheKey 缓存 key\n     * @param chain    处理器链，通过 chain.doBoundSql 方法继续执行后续方法，也可以直接返回 boundSql 终止后续方法的执行\n     * @return 允许修改 boundSql 并返回修改后的\n     */\n    BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain);\n\n    enum Type {\n        /**\n         * 原始SQL，分页插件执行前，先执行这个类型\n         */\n        ORIGINAL,\n        /**\n         * count SQL，第二个执行这里\n         */\n        COUNT_SQL,\n        /**\n         * 分页 SQL，最后执行这里\n         */\n        PAGE_SQL\n    }\n\n    /**\n     * 处理器链，可以控制是否继续执行\n     */\n    interface Chain {\n        Chain DO_NOTHING = new Chain() {\n            @Override\n            public BoundSql doBoundSql(Type type, BoundSql boundSql, CacheKey cacheKey) {\n                return boundSql;\n            }\n        };\n\n        BoundSql doBoundSql(Type type, BoundSql boundSql, CacheKey cacheKey);\n    }\n}\n```\n\nThe interface includes boundSql interface method, Type enumeration, and the definition of Chain interface, and you don't need to consider Chain when you implement it yourself.\n\nThe interceptor is configured by `boundSqlInterceptors` parameter, and there are three situations when executing:\n\n1. Regardless of whether the currently executed SQL will be paged or not, interceptor methods of `Type.ORIGINAL` will be executed.\n\n2. When the paging method is called, the interceptor will continue to execute the interceptor method of `Type.COUNT_SQL`, which will only be executed when paging is executed and count query is specified.\n\n3. When paging method is called, if count > 0, interceptor method of `Type.PAGE_SQL` will be executed, which will only be executed when paging is executed.\n\n>With the specified parameter `PageHelper.startPage(1, Integer.MAX_VALUE, false).boundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor)`, it can also play the role of not paging and count query, but can execute interceptor method of `Type.ORIGINAL`.\n\nIf you want to get the page before SQL execution, you only need to pay attention to `Type.ORIGINAL`, and the other two are before count execution and before page execution (when count=0, the page method will not be executed and will not be executed here).\n\nTake the test code as an example:\n\n```java\npublic class TestBoundSqlInterceptor implements BoundSqlInterceptor {\n    public static final String COMMENT = \"\\n /* TestBoundSqlInterceptor */\\n\";\n\n    @Override\n    public BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain) {\n        if (type == Type.ORIGINAL) {\n            String sql = boundSql.getSql();\n            MetaObject metaObject = MetaObjectUtil.forObject(boundSql);\n            metaObject.setValue(\"sql\", sql + COMMENT);\n        }\n        return chain.doBoundSql(type, boundSql, cacheKey);\n    }\n\n}\n```\nThe above code modifies the original sql before SQL execution, but only adds a comment at the end, which does not affect SQL execution. It is configured in the following way:\n\n```xml\n<plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n    <!-- 支持通过Mapper接口参数来传递分页参数 -->\n    <property name=\"helperDialect\" value=\"mysql\"/>\n    <property name=\"boundSqlInterceptors\"\n              value=\"com.github.pagehelper.test.basic.provider.TestBoundSqlInterceptor,com.github.pagehelper.test.basic.provider.TestBoundSqlInterceptor\"/>\n</plugin>\n```\n\nHere, in order to explain that the parameter value can be multiple, it is repeatedly configured once, that is, the above interceptor will execute it twice.\n\nWith this configuration, the above SQL will modify the SQL when the page is executed.\n\nIn addition to this configuration mode, temporary designation when PageHelper.startPage is also supported. This mode will put the interceptor at the chain head and execute it first, so you can control whether to execute it later or not, or you can do the final processing before returning after all subsequent executions.\n\nExample:\n\n```java\nPageHelper.startPage(1, 10).boundSqlInterceptor(new BoundSqlInterceptor() {\n    @Override\n    public BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain) {\n        System.out.println(\"before: \" + boundSql.getSql());\n        BoundSql doBoundSql = chain.doBoundSql(type, boundSql, cacheKey);\n        System.out.println(\"after: \" + doBoundSql.getSql());\n        if (type == Type.ORIGINAL) {\n            Assert.assertTrue(doBoundSql.getSql().contains(TestBoundSqlInterceptor.COMMENT));\n        }\n        return doBoundSql;\n    }\n});\n```\n\n\n\n### 5.1.11 - 2019-11-26\n\n- Added support for Shentong database **wangss**\n- Add support for HerdDB - support HerdDB, mostly like MySQL - auto detect HerdDB **Enrico Olivelli**\n- fix some typos and grammar issues **LHearen**\n\n### 5.1.10 - 2019-06-05\n\nIn version *5.1.0 - 2017-08-28*. Added `ReplaceSql` interface for handling sqlServer with (nolock) problem,\nadd the replaceSql parameters, the optional value is `simple` and `regex`, or to achieve the `ReplaceSql` interface\nfully qualified class name. The default value is `simple`, still using the original way to deal with,\nthe new regex will be convert `with (nolock)` to `table_PAGEWITHNOLOCK`.\n\nThis update only changes the default value from `simple` to `regex`, which can almost 100% solve the paging problem of sqlServer.\n\nThe following are examples from two issue.\n\n#### issue [#76](https://github.com/pagehelper/pagehelper-spring-boot/issues/76)\n\nOriginal SQL：\n```sql\nSELECT *\nFROM\nforum_post_info a with(nolock)\nLEFT JOIN forum_carcase_tags as b with(nolock) on a.id = b.carcase_id where b.tag_id = 127\n```\nConverted Count SQL：\n```sql\nSELECT COUNT(0)\nFROM forum_post_info a WITH (NOLOCK)\n\tLEFT JOIN forum_carcase_tags b WITH (NOLOCK) ON a.id = b.carcase_id\nWHERE b.tag_id = 127\n```\nConverted paging SQL：\n```sql\nSELECT TOP 10 *\nFROM (\n\tSELECT ROW_NUMBER() OVER (ORDER BY RAND()) AS PAGE_ROW_NUMBER, *\n\tFROM (\n\t\tSELECT *\n\t\tFROM forum_post_info a WITH (NOLOCK)\n\t\t\tLEFT JOIN forum_carcase_tags b WITH (NOLOCK) ON a.id = b.carcase_id\n\t\tWHERE b.tag_id = 127\n\t) PAGE_TABLE_ALIAS\n) PAGE_TABLE_ALIAS\nWHERE PAGE_ROW_NUMBER > 1\nORDER BY PAGE_ROW_NUMBER\n```\n\n#### issue [#398](https://github.com/pagehelper/Mybatis-PageHelper/issues/398)\n\nOriginal SQL：\n```sql\nSelect AUS.ScheduleID, AUS.SystemID, AUS.ClinicID, AUS.DoctorID, AUS.ScheduleDate,\n\tAUS.StartTime, AUS.EndTime, AUS.Status, AUS.BookBy, AUS.Note, AUS.Remark, AUS.SourceType, CM.CompanyName,\n\tAU.UserName As DoctorName, AU.UserNumber As DoctorNumber, CC.CodeDesc As ClinicName, CD.Lat, CD.Lng,\n\tCD.ContactTel, CD.Address, CR.ConsultationStatusID, CR.RegisterStatus,A1.CodeDesc as AreaLevel1, A2.CodeDesc as AreaLevel2\n\tFrom ACM_User_Schedule AUS with(nolock)\n\tLeft Join Client_Register CR with(nolock) On AUS.BookBy=CR.ClientID And CR.SourceType='F' And AUS.ClientRegisterNum=CR.ClientRegisterNum\n\tInner Join ACM_User AU with(nolock) On AU.UserID = AUS.DoctorID\n\tInner Join Code_Clinic CC with(nolock) On AUS.ClinicID=CC.CodeID\n\tInner Join Clinic_Detail CD with(nolock) On CC.CodeID = CD.ClinicID\n\tInner Join Code_Area A1 with(nolock) On CD.AreaLevel1ID=A1.CodeID\n\tInner Join Code_Area A2 with(nolock) On CD.AreaLevel2ID=A2.CodeID\n\tInner Join Company_Master CM with(nolock) On CC.SystemID = CM.SystemID\n\tWhere BookBy=1\n```\nConverted Count SQL：\n```sql\nSELECT COUNT(0)\nFROM ACM_User_Schedule AUS WITH (NOLOCK)\n\tLEFT JOIN Client_Register CR WITH (NOLOCK)\n\tON AUS.BookBy = CR.ClientID\n\t\tAND CR.SourceType = 'F'\n\t\tAND AUS.ClientRegisterNum = CR.ClientRegisterNum\n\tINNER JOIN ACM_User AU WITH (NOLOCK) ON AU.UserID = AUS.DoctorID\n\tINNER JOIN Code_Clinic CC WITH (NOLOCK) ON AUS.ClinicID = CC.CodeID\n\tINNER JOIN Clinic_Detail CD WITH (NOLOCK) ON CC.CodeID = CD.ClinicID\n\tINNER JOIN Code_Area A1 WITH (NOLOCK) ON CD.AreaLevel1ID = A1.CodeID\n\tINNER JOIN Code_Area A2 WITH (NOLOCK) ON CD.AreaLevel2ID = A2.CodeID\n\tINNER JOIN Company_Master CM WITH (NOLOCK) ON CC.SystemID = CM.SystemID\nWHERE BookBy = 1\n```\nConverted paging SQL：\n```sql\nSELECT TOP 10 ScheduleID, SystemID, ClinicID, DoctorID, ScheduleDate\n\t, StartTime, EndTime, Status, BookBy, Note\n\t, Remark, SourceType, CompanyName, DoctorName, DoctorNumber\n\t, ClinicName, Lat, Lng, ContactTel, Address\n\t, ConsultationStatusID, RegisterStatus, AreaLevel1, AreaLevel2\nFROM (\n\tSELECT ROW_NUMBER() OVER (ORDER BY RAND()) AS PAGE_ROW_NUMBER, ScheduleID, SystemID, ClinicID, DoctorID\n\t\t, ScheduleDate, StartTime, EndTime, Status, BookBy\n\t\t, Note, Remark, SourceType, CompanyName, DoctorName\n\t\t, DoctorNumber, ClinicName, Lat, Lng, ContactTel\n\t\t, Address, ConsultationStatusID, RegisterStatus, AreaLevel1, AreaLevel2\n\tFROM (\n\t\tSELECT AUS.ScheduleID, AUS.SystemID, AUS.ClinicID, AUS.DoctorID, AUS.ScheduleDate\n\t\t\t, AUS.StartTime, AUS.EndTime, AUS.Status, AUS.BookBy, AUS.Note\n\t\t\t, AUS.Remark, AUS.SourceType, CM.CompanyName, AU.UserName AS DoctorName, AU.UserNumber AS DoctorNumber\n\t\t\t, CC.CodeDesc AS ClinicName, CD.Lat, CD.Lng, CD.ContactTel, CD.Address\n\t\t\t, CR.ConsultationStatusID, CR.RegisterStatus, A1.CodeDesc AS AreaLevel1, A2.CodeDesc AS AreaLevel2\n\t\tFROM ACM_User_Schedule AUS WITH (NOLOCK)\n\t\t\tLEFT JOIN Client_Register CR WITH (NOLOCK)\n\t\t\tON AUS.BookBy = CR.ClientID\n\t\t\t\tAND CR.SourceType = 'F'\n\t\t\t\tAND AUS.ClientRegisterNum = CR.ClientRegisterNum\n\t\t\tINNER JOIN ACM_User AU WITH (NOLOCK) ON AU.UserID = AUS.DoctorID\n\t\t\tINNER JOIN Code_Clinic CC WITH (NOLOCK) ON AUS.ClinicID = CC.CodeID\n\t\t\tINNER JOIN Clinic_Detail CD WITH (NOLOCK) ON CC.CodeID = CD.ClinicID\n\t\t\tINNER JOIN Code_Area A1 WITH (NOLOCK) ON CD.AreaLevel1ID = A1.CodeID\n\t\t\tINNER JOIN Code_Area A2 WITH (NOLOCK) ON CD.AreaLevel2ID = A2.CodeID\n\t\t\tINNER JOIN Company_Master CM WITH (NOLOCK) ON CC.SystemID = CM.SystemID\n\t\tWHERE BookBy = 1\n\t) PAGE_TABLE_ALIAS\n) PAGE_TABLE_ALIAS\nWHERE PAGE_ROW_NUMBER > 1\nORDER BY PAGE_ROW_NUMBER\n```\n\nSQL is formatted by https://tool.oschina.net/codeformat/sql\n\n### 5.1.9 - 2019-05-29\n\n- Upgrade jsqlparser to 2.0, upgrade mybatis to 3.5.1. resolve compatibility issues.\n- Improve paging logic judgment. fixed #389\n- Solve MetaObject version compatibility issues. fixed #349\n- Processing order by output warning log when parsing fails, not throwing exception\n- Solve three problems that may cause countColumn to fail fixed #325\n- Add a comma with less BIT_ fixed #341\n- Handling invalid links in documents isea533\n- Document sample error. fixed #366\n- fixed #373 NPE problem\n\n### 5.1.8 - 2018-11-11\n\n- Resolve the problem of `with(nolock)` in SQLServer ([#pr10](https://gitee.com/free/Mybatis_PageHelper/pulls/10)) by [lvshuyan](https://gitee.com/lvshuyan)\n\n### 5.1.7 - 2018-10-11\n\n- Support Aliyun PPAS database. Automatic identification of edb. fixed #281\n\n### 5.1.6 - 2018-09-05\n\n- Add the parameter useSqlserver2012, set to true, and use sqlserver2012(Dialect) as the default paging method for SQL Server databases, which is useful in dynamic data sources.\n- Add an IPage interface. Currently, there is only one parameter to support the MyBatis query method, and when the parameter implements the IPage interface, paging query will be automatically performed if paging parameters exist. Thanks to [moonfruit](https://github.com/moonfruit) Issue two years ago.\n- fixed # 276 to resolve hashset concurrency issue\n- Optimize code structure and streamline interceptor code\n\n### 5.1.5 - 2018-09-02\n\n- Optimize the code and remove unnecessary checks(**by lenosp**)\n- Solve the small problem of pageKey multi-processing once #268\n- Added javadoc documentation on gitee(https://apidoc.gitee.com/free/Mybatis_PageHelper)\n- Solve the problem of default reflection without cache fixed #275\n- Optimizing mysql ifnull function causes paging performance problems (**by miaogr**)（This change was eventually changed to the following `aggregateFunctions`）\n- Jsqlparser has been upgraded to version 1.2, which is incompatible with 1.0 and has been resolved. fixed 273\n- Remove the g(s)etFirstPage and g(s)etLastPage methods that are ambiguous in PageInfo\n- Throws an exception that failed to parse when sorting fixed #257\n- Resolve the initialization problem when there is no properties property when configuring the spring use `<bean>`. fixed #26\n- Fix the problem that Oracle paging will leak data (**by muyun12**)\n- `aggregateFunctions`: The default is the aggregate function of all common databases,\n  allowing you to manually add aggregate functions ( affecting the number of rows ).\n  All functions that start with aggregate functions will be wrap as subquery.\n  Other functions and columns will be replaced with count(0).\n\nAfter adding the `aggregateFunctions` parameter, the biggest difference from the original is that if there is `select ifnull(XXX,YY) from table ...`, the original count query is\n `select count(0) from (select ifnull(xxx,yy) from table ... ) temp_count` now distinguishes aggregate functions, if not aggregate functions, it will become\n `select count(0) from table ...`.\n\nThe aggregate function prefixes included by default are as follows:\n\n```java\n/**\n * Aggregate functions, beginning with the following functions are considered aggregate functions\n */\nprivate static final Set<String> AGGREGATE_FUNCTIONS = new HashSet<String>(Arrays.asList(\n        (\"APPROX_COUNT_DISTINCT,\" +\n        \"ARRAY_AGG,\" +\n        \"AVG,\" +\n        \"BIT_\" +\n        //\"BIT_AND,\" +\n        //\"BIT_OR,\" +\n        //\"BIT_XOR,\" +\n        \"BOOL_,\" +\n        //\"BOOL_AND,\" +\n        //\"BOOL_OR,\" +\n        \"CHECKSUM_AGG,\" +\n        \"COLLECT,\" +\n        \"CORR,\" +\n        //\"CORR_,\" +\n        //\"CORRELATION,\" +\n        \"COUNT,\" +\n        //\"COUNT_BIG,\" +\n        \"COVAR,\" +\n        //\"COVAR_POP,\" +\n        //\"COVAR_SAMP,\" +\n        //\"COVARIANCE,\" +\n        //\"COVARIANCE_SAMP,\" +\n        \"CUME_DIST,\" +\n        \"DENSE_RANK,\" +\n        \"EVERY,\" +\n        \"FIRST,\" +\n        \"GROUP,\" +\n        //\"GROUP_CONCAT,\" +\n        //\"GROUP_ID,\" +\n        //\"GROUPING,\" +\n        //\"GROUPING,\" +\n        //\"GROUPING_ID,\" +\n        \"JSON_,\" +\n        //\"JSON_AGG,\" +\n        //\"JSON_ARRAYAGG,\" +\n        //\"JSON_OBJECT_AGG,\" +\n        //\"JSON_OBJECTAGG,\" +\n        //\"JSONB_AGG,\" +\n        //\"JSONB_OBJECT_AGG,\" +\n        \"LAST,\" +\n        \"LISTAGG,\" +\n        \"MAX,\" +\n        \"MEDIAN,\" +\n        \"MIN,\" +\n        \"PERCENT_,\" +\n        //\"PERCENT_RANK,\" +\n        //\"PERCENTILE_CONT,\" +\n        //\"PERCENTILE_DISC,\" +\n        \"RANK,\" +\n        \"REGR_,\" +\n        \"SELECTIVITY,\" +\n        \"STATS_,\" +\n        //\"STATS_BINOMIAL_TEST,\" +\n        //\"STATS_CROSSTAB,\" +\n        //\"STATS_F_TEST,\" +\n        //\"STATS_KS_TEST,\" +\n        //\"STATS_MODE,\" +\n        //\"STATS_MW_TEST,\" +\n        //\"STATS_ONE_WAY_ANOVA,\" +\n        //\"STATS_T_TEST_*,\" +\n        //\"STATS_WSR_TEST,\" +\n        \"STD,\" +\n        //\"STDDEV,\" +\n        //\"STDDEV_POP,\" +\n        //\"STDDEV_SAMP,\" +\n        //\"STDDEV_SAMP,\" +\n        //\"STDEV,\" +\n        //\"STDEVP,\" +\n        \"STRING_AGG,\" +\n        \"SUM,\" +\n        \"SYS_OP_ZONE_ID,\" +\n        \"SYS_XMLAGG,\" +\n        \"VAR,\" +\n        //\"VAR_POP,\" +\n        //\"VAR_SAMP,\" +\n        //\"VARIANCE,\" +\n        //\"VARIANCE_SAMP,\" +\n        //\"VARP,\" +\n        \"XMLAGG\").split(\",\")));\n```\n\n### 5.1.4 - 2018-04-22\n\n- Add the DaMeng Database (dm) to page using Oracle. If you want to change SqlServer, you can refer to the `dialectAlias` parameter in the 5.1.3 update log.\n\n### 5.1.3 - 2018-04-07\n\n- `Page` `toString` method adds `super.toString()`. The final output form is `Page{Attribute}[Collection]`.\n- New `defaultCount` parameter is used to control whether to perform count query in the default method without count query. By default, `true` will execute count query. This is a globally valid parameter, and it is a uniform behavior when multiple data sources are used.\n- New `dialogAlias` parameter that allows you to configure aliases for custom implementations. it can be used to automatically obtain corresponding implementations based on JDBC URL. it allows you to overwrite existing implementations in this way. configuration examples are ( Separate multiple configurations with semicolons ):\n  ```xml\n  <property name=\"dialectAlias\" value=\"oracle=com.github.pagehelper.dialect.helper.OracleDialect\"/>\n  ```\n- The new `PageSerializable` class, a simplified version of the `PageInfo` class, is recommended to use or refer to this class when it does not require much information.\n\n### 5.1.2 - 2017-09-18\n\n- Solve the problem  when using the `PageHelper.orderBy` method alone #110;\n\n### 5.1.1 - 2017-08-30\n\n- The update to solve the problem and only SqlServer 2005,2008 related.\n- Resolve `RegexWithNolockReplaceSql` in the Wrong regular `w?`, it should be `w+`.\n- Resolved `SqlServerDialect` did not initialize the default `SimpleWithNolockReplaceSql` error.\n- `SqlServerRowBoundsDialect` support for the replaceSql parameter.\n\n\n### 5.1.0 - 2017-08-28\n\n- Added the sorting functionality included in the previous version of 4.x, and the usage is consistent (PageHelper adds several sort-related methods).\n- Paging SQL is converted to PreparedStatement SQL.\n- Added `ReplaceSql` interface for handling sqlServer with (nolock) problem, add the replaceSql parameters, the optional value is `simple` and `regex`, or to achieve the `ReplaceSql` interface fully qualified class name. The default value is `simple`, still using the original way to deal with, the new regex will be convert `with (nolock)` to `table_PAGEWITHNOLOCK`.\n- `PageRowBounds` add `count` attribute, you can control whether execute the count query.\n\n\n### 5.0.4 - 2017-08-01\n\n- Add a simple configuration support for the Phoenix database, You can configure `helperDialect=phoenix`. Can also automatically identify the Phoenix database jdbc url.\n- Simplified cache of `msCountMap`\n- Add `countSuffix` count query suffix configuration parameters, this parameter is configured for `PageInterceptor`, the default value is `_COUNT`.\n- Add custom count query support, see below for details.\n\n#### Add custom count query support\n\nAdd `countSuffix` count query suffix configuration parameters, this parameter is configured for `PageInterceptor`, the default value is `_COUNT`.\n\nThe paging plugin will preferentially find the handwritten paging query by the current query `msId + countSuffix`.\n\nIf there is no custom query, the query is still automatically created using the previous way.\n\nFor example, if there are two queries:\n```xml\n<select id=\"selectLeftjoin\" resultType=\"com.github.pagehelper.model.User\">\n    select a.id,b.name,a.py from user a\n    left join user b on a.id = b.id\n    order by a.id\n</select>\n<select id=\"selectLeftjoin_COUNT\" resultType=\"Long\">\n    select count(distinct a.id) from user a\n    left join user b on a.id = b.id\n</select>\n```\nThe above `countSuffix` uses the default value of` _COUNT`, and the paging plugin will automatically get the query to `selectLeftjoin_COUNT`. This query needs to ensure that the result is correct.\n\nThe value of the return value must be `resultType =\" Long \"`, and the same parameter used by `selectLeftjoin` 'is used, so it is used in SQL to follow the selection of` selectLeftjoin`'.\n\nBecause the `selectLeftjoin_COUNT` method is invoked automatically, there is no need to provide the appropriate method on the interface, or if it is required to be invoked separately.\n\nThe above method to perform the portion of the output log is as follows：\n```\nDEBUG [main] - ==>  Preparing: select count(distinct a.id) from user a left join user b on a.id = b.id\nDEBUG [main] - ==> Parameters:\nTRACE [main] - <==    Columns: C1\nTRACE [main] - <==        Row: 183\nDEBUG [main] - <==      Total: 1\nDEBUG [main] - Cache Hit Ratio [com.github.pagehelper.mapper.CountryMapper]: 0.0\nDEBUG [main] - ==>  Preparing: select a.id,b.name,a.py from user a left join user b on a.id = b.id order by a.id LIMIT 10\nDEBUG [main] - ==> Parameters:\nTRACE [main] - <==    Columns: ID, COUNTRYNAME, COUNTRYCODE\nTRACE [main] - <==        Row: 1, Angola, AO\nTRACE [main] - <==        Row: 2, Afghanistan, AF\nTRACE [main] - <==        Row: 3, Albania, AL\n```\n\n### 5.0.3 -2017-06-20\n\n- Solve the `supportMethodsArguments` parameter problem. It is recommended to upgrade to the latest version.\n\n### 5.0.2 - 2017-05-30\n\n- `Page<E>` implements `Closeable` interface, in JDK7+ which can use the in `try ()` call, it will automatically call `PageHelper.clearPage ();`[#58](https://github.com/pagehelper/Mybatis-PageHelper/issues/58)。\n- fixed: DB2 paging must be specified sub-query alias, or an exception will occur [#52](https://github.com/pagehelper/Mybatis-PageHelper/issues/52)\n- fixed：if `page.size() == 0` then `pageInfo.isIsLastPage()` is `false` [#50](https://github.com/pagehelper/Mybatis-PageHelper/issues/50)\n\n\n### 5.0.1 - 2017-04-23\n- Add the new parameter `countColumn` used to configure the automatic count column, the default value `0`, that is, `count(0).\n- The `Page` class is also added with the `countColumn` parameter, which can be configured for a specific query.\n- Modify the document display problem, by liumian* [PR #30](https://github.com/pagehelper/Mybatis-PageHelper/pull/30)\n- Resolved sqlserver2012 paging error [42](https://github.com/pagehelper/Mybatis-PageHelper/issues/42)\n\n### 5.0.0 - 2017-01-02\n\n- Use Use [QueryInterceptor spec](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/src/main/java/com/github/pagehelper/QueryInterceptor.java) to handle paging logic\n- New pagination plugin interceptor `com.github.pagehelper.PageInterceptor`\n- New `Dialect` `PageHelper` is a special implementation class, the previous function is implemented in more user-friendly ways\n- New pagination plugin only a `dialect` parameter, the default `dialect` is `PageHelper`\n- `PageHelper` continue to support previously provided parameters, Among the latest to use the document has been fully updated\n- `PageHelper` has a `helperDialect` parameter which is the same functional as the previous `dialect`\n- Added paging implementation based on pure `RowBounds` and `PageRowBounds`,\n  in `com.github. pagehelper. dialect. rowbounds` package, it is used as `dialect` Parameter sample implementation, more\n  detailed documentation will be added later\n- Removed inappropriate orderby functions that appear in pagination plugin. It will provide a separate sort plug-ins in\n  the future\n- Remove `PageHelper` are less commonly used methods\n- A new document, an important part of the update has been mentioned in the changelog, provides the English version of this document\n- fix bug [#149](http://git.oschina.net/free/Mybatis_PageHelper/issues/149)\n- renamed Db2RowDialect to Db2RowBoundsDialect\n- All thrown exceptions being replaced by PageException\n\n## Older Changelogs are written in Chinese\nYou can [view here](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Changelog.md)\n"
  },
  {
    "path": "wikis/en/HowToUse.md",
    "content": "## HOW TO USE\n\n### 1. Installation <a href=\"https://maven-badges.herokuapp.com/maven-central/com.github.pagehelper/pagehelper\"><img src=\"https://maven-badges.herokuapp.com/maven-central/com.github.pagehelper/pagehelper/badge.svg\"/></a>\n\n#### 1). Using Maven\n\nAdd the following dependencies to the pom.xml:\n\n```xml\n\n<dependency>\n    <groupId>com.github.pagehelper</groupId>\n    <artifactId>pagehelper</artifactId>\n    <version>latestVersion</version>\n</dependency>\n```\n\n#### 2). Using Gradle\n\nTo 'build.gradle' add:\n\n```groovy\ndependencies {\n    compile(\"com.github.pagehelper:pagehelper:latestVersion\")\n}\n```\n\n#### 3). When using Spring Boot <a href=\"https://maven-badges.herokuapp.com/maven-central/com.github.pagehelper/pagehelper-spring-boot-starter\"><img src=\"https://maven-badges.herokuapp.com/maven-central/com.github.pagehelper/pagehelper-spring-boot-starter/badge.svg\"/></a>\n\nMaven：\n\n```xml\n\n<dependency>\n    <groupId>com.github.pagehelper</groupId>\n    <artifactId>pagehelper-spring-boot-starter</artifactId>\n    <version>latestVersion</version>\n</dependency>\n```\n\nGradle:\n\n```groovy\ndependencies {\n    compile(\"com.github.pagehelper:pagehelper-spring-boot-starter:latestVersion\")\n}\n```\n\n### 2. Config PageHelper\n\n#### 1). Using in mybatis-config.xml\n\n```xml\n<!--\n    In the configuration file,\n    plugins location must meet the requirements as the following order:\n    properties?, settings?,\n    typeAliases?, typeHandlers?,\n    objectFactory?,objectWrapperFactory?,\n    plugins?,\n    environments?, databaseIdProvider?, mappers?\n-->\n<plugins>\n    <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n        <!-- config params as the following -->\n        <property name=\"param1\" value=\"value1\"/>\n\t</plugin>\n</plugins>\n```\n\n#### 2). Using in Spring application.xml\nconfig `org.mybatis.spring.SqlSessionFactoryBean` as following:\n```xml\n<bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n  <!-- other configuration -->\n  <property name=\"plugins\">\n    <array>\n      <bean class=\"com.github.pagehelper.PageInterceptor\">\n        <property name=\"properties\">\n          <!-- config params as the following -->\n          <value>\n            param1=value1\n          </value>\n        </property>\n      </bean>\n    </array>\n  </property>\n</bean>\n```\n\n#### 3). Configured in Spring Boot\n\nSpring Boot automatically take effect after the introduction of the starter, the paging plug-in configuration, in the\nSpring the Boot the corresponding configuration file ` application. [properties | yaml] ` configuration:\n\nproperties:\n\n```properties\npagehelper.propertyName=propertyValue\npagehelper.reasonable=false\npagehelper.defaultCount=true\n```\n\nyaml:\n\n```yaml\npagehelper:\n  propertyName: propertyValue\n  reasonable: false\n  defaultCount: true # The default parameter of the paging plug-in is in the form of default-count. The parameter of the customized extension must be case - consistent\n```\n\n> The default parameter of the paging plug-in is in the form of default-count. The parameter of the customized extension\n> must be case - consistent.\n>\n>\nSupported default parameters for\nreference:[PageHelperStandardProperties.java](https://github.com/pagehelper/pagehelper-spring-boot/blob/master/pagehelper-spring-boot-autoconfigure/src/main/java/com/github/pagehelper/autoconfigure/PageHelperStandardProperties.java)\n\n#### 4). Banner Setting\n\nTo avoid errors caused by multiple configurations of the paging plug-in, banner is displayed when the paging plug-in is\nconfigured.\n\n```\nDEBUG [main] -\n\n,------.                           ,--.  ,--.         ,--.\n|  .--. '  ,--,--.  ,---.   ,---.  |  '--'  |  ,---.  |  |  ,---.   ,---.  ,--.--.\n|  '--' | ' ,-.  | | .-. | | .-. : |  .--.  | | .-. : |  | | .-. | | .-. : |  .--'\n|  | --'  \\ '-'  | ' '-' ' \\   --. |  |  |  | \\   --. |  | | '-' ' \\   --. |  |\n`--'       `--`--' .`-  /   `----' `--'  `--'  `----' `--' |  |-'   `----' `--'\n`---'                                   `--'                        is intercepting.\n```\n\nIf the banner is output for many times during the project startup, the paging plug-in has been configured for many\ntimes. Check whether the system has configured the paging plug-in based on the log output location.\n\nIf you don't want to output the banner at startup, you can turn it off via system variables or environment variables.\n\n- system variables: `-Dpagehelper.banner=false`\n- envionment variables: `PAGEHELPER_BANNER=false`\n\n#### 5). PageHelper Parameters\n\nPageHelper provides several optional parameters,\nthese parameters when used in accordance with the above examples to configuration.\n\n**Optional parameters as follows:**\n\n1. `debug` : Debug parameter, default 'false' off, set to 'true' enabled, can check the existence of unsafe calls in the\n   system, [see how to call safely](3-Pagehelper - secure calls). When static methods such as' pageHelper. startPage '\n   are called to set paging parameters, the current executed method stack information will be recorded. When the query\n   method of MyBatis is executed, the set paging parameters will be used, and the set method stack will be output. If it\n   is not the same as the currently executing method, then the corresponding call in the stack is an unsafe call and\n   needs to be adjusted according to the way in Safe Call (3-PageHelper-Safe Call). An example of the output stack is as\n   follows:\n   ```\n   00:19:08.915 [main] DEBUG c.github.pagehelper.PageInterceptor - java.lang.Exception: 设置分页参数时的堆栈信息\n       at com.github.pagehelper.util.StackTraceUtil.current(StackTraceUtil.java:12)\n       at com.github.pagehelper.Page.<init>(Page.java:111)\n       at com.github.pagehelper.Page.<init>(Page.java:126)\n       at com.github.pagehelper.page.PageMethod.startPage(PageMethod.java:139)\n       at com.github.pagehelper.page.PageMethod.startPage(PageMethod.java:113)\n       at com.github.pagehelper.page.PageMethod.startPage(PageMethod.java:102)\n       at com.github.pagehelper.test.basic.PageHelperTest.testNamespaceWithStartPage(PageHelperTest.java:118)\n       ...omit\n\n   00:19:09.069 [main] DEBUG c.g.pagehelper.mapper.UserMapper - Cache Hit Ratio [com.github.pagehelper.mapper.UserMapper]: 0.0\n   00:19:09.077 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Opening JDBC Connection\n   00:19:09.078 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [org.hsqldb.jdbc.JDBCConnection@6da21078]\n   00:19:09.087 [main] DEBUG c.g.p.m.UserMapper.selectAll_COUNT - ==>  Preparing: SELECT count(1) FROM user\n   00:19:09.121 [main] DEBUG c.g.p.m.UserMapper.selectAll_COUNT - ==> Parameters:\n   00:19:09.131 [main] TRACE c.g.p.m.UserMapper.selectAll_COUNT - <==    Columns: C1\n   00:19:09.131 [main] TRACE c.g.p.m.UserMapper.selectAll_COUNT - <==        Row: 183\n   00:19:09.147 [main] DEBUG c.g.p.m.UserMapper.selectAll_COUNT - <==      Total: 1\n   ```\n\n2. `dialect` : by default paging will use PageHelper way, if you want to achieve their own paging logic, can\n   realize `Dialect` (`com.github.pagehelper.Dialect`) interface, and then configure the properties to achieve the fully\n   qualified name of the class.\n\n3. `countSuffix` : msId suffix appended when creating or looking for a corresponding count query based on a query,\n   default '_COUNT'.\n\n4. `countMsIdGen`(5.3.2+) : The count method of the msId generation, the default is to query the `msId + countSuffix`,\n   want my own definition, can realize `com.github.pagehelper.CountMsIdGen` interface, the parameter configuration in\n   order to realize the fully qualified class name. A common use: In the case of an Example query, 'selectByExample' can\n   be queried using the corresponding 'selectCountByExample' method.\n\n5. `msCountCache`: Automatically create a query count query method, created the count `MappedStatement` caching, the\n   default will be preferred to find `com.google.common.cache.Cache`. The cache implementation, Projects without Guava\n   dependencies are created using MyBatis' built-in CacheBuilder. Want to fine-grained cache configuration: please refer\n   to the source code. `com.github.pagehelper.cache.CacheFactory`, two configurations of default provides multiple\n   attributes, can also according to the requirements to build themselves here.\n\n**The following parameters are the parameters for the default dialect case.\nWhen implemented using a custom dialect, the following parameter has no effect.**\n\n1. `helperDialect`: PageHelper will detect the current database url by default, automatically select the corresponding\n   database dialect.\n   You can configure `helperDialect` Property to specify the dialect. You can use the following abbreviations :\n   `oracle`, `mysql`, `mariadb`, `sqlite`, `hsqldb`, `postgresql`,\n   `db2`, `sqlserver`, `informix`, `h2`, `sqlserver2012`, `derby`.\n   You can also implement `AbstractHelperDialect`,\n   and then configure the attribute to achieve the fully qualified class name.\n   **Special note :** When using the SqlServer2012 database,\n   you need to manually specify for `sqlserver2012`, otherwise it will use the SqlServer2005 for paging.\n\n2. `dialectAlias`：Allows you to configure an alias for a custom implementation. It can be used to automatically obtain\n   the corresponding implementation according to JDBCURL. It allows you to override existing implementations in this\n   way.\n   ```xml\n   <property name=\"dialectAlias\" value=\"oracle=com.github.pagehelper.dialect.helper.OracleDialect\"/>\n   ```\n   When you use jdbcurl is not [PageAutoDialect](src/main/java/com/github/pagehelper/page/PageAutoDialect.java) default\n   provide range, can be realized through the change of parameters automatic identification.\n\n3. `useSqlserver2012`(sqlserver)：To use the SqlServer2012 database, manually specify SqlServer2012. Otherwise,\n   SqlServer2005 will be used for paging. You can also set `useSqlserver2012=true` to change 2012 to the default mode of\n   SQLServer.\n\n4. `defaultCount`：Use to control whether a count query is executed in a method that does not default to count queries.\n   By default, true executes a count query. This is a globally valid parameter and a uniform behavior across multiple\n   data sources.\n\n5. `countColumn`：Used to configure the query column for automatic count queries. The default value is `0`, which\n   is `count(0)`. The Page object also has a new 'countColumn' parameter, which can be configured for specific queries.\n\n6`offsetAsPageNum`: Default value is `false`, This parameter is valid for `RowBounds` as a pagination parameter.\nWhen this parameter is set to `true`, the` offset` parameter in `RowBounds` is used as` pageNum`.\n\n7. `rowBoundsWithCount`: Default value is `false`, When this parameter is set to `true`,\n   PageHelper will execute count query.\n\n8. `pageSizeZero`: Default value is `false`, When this parameter is set to `true`,\n   if `pageSize=0` or `RowBounds.Limit = 0` will query all the results (the equivalent of a Paged query did not execute,\n   but the return type of the result is still `Page`).\n\n\n9. `reasonable`: Rationalization of paging parameters, Default value is `false`。\n   When this parameter is set to `true`,` pageNum <= 0` will query the first page,\n   `PageNum> pages` (over the total number), will query the last page. Default `false`, the query directly based on\n   parameters.\n\n10. `params`: In support of `startPage(Object params)` method,\n    The parameter is added to configure the parameter mapping for the value from the object based on the attribute name,\n    you can configure `pageNum,pageSize,count,pageSizeZero,reasonable`,\n    Default value is `pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero`。\n\n11. `supportMethodsArguments`: Support via the Mapper interface parameters to pass the page parameter, the default value\n    is 'false'.\n    The use of methods can refer to the test code in the `com.github.pagehelper.test.basic` package under\n    the` ArgumentsMapTest` and `ArgumentsObjTest`.\n\n12. `autoRuntimeDialect`: Default value is `false`。When set to `true`,\n    it is possible to automatically recognize pagination of the corresponding dialect at run time from multiple data\n    sources\n    (Does not support automatic selection of `sqlserver2012`, can only use` sqlserver`), usage and precautions refer to\n    the following **Scene 5**.\n\n\n13. `closeConn`: Default value is **`true`**。\n    When you use a runtime dynamic data source or do not set the `helperDialect` property, PageHelper will automatically\n    get the database type, then a database connection is automatically obtained,\n    This property is used to set whether to close the connection, the default `true` close. When 'false' is set, It will\n    not close the connection.\n\n14. `aggregateFunctions`(5.1.5+): The default is the aggregate function of all common databases,\n    allowing you to manually add aggregate functions ( affecting the number of rows ).\n    All functions that start with aggregate functions will be wrap as subquery.\n    Other functions and columns will be replaced with count(0).\n\n15. `replaceSql`(sqlserver): Optional value of `regex` and `simple`, default value is used when empty `regex` way, also\n    can realize `com.github.pagehelper.dialect.ReplaceSql` interface.\n\n16. `sqlCacheClass`(sqlserver): Used to generate the count and page caching, SQL cache\n    using `com.github.pagehelper.cache.CacheFactory`, optional parameters and the front `msCountCache`.\n\n17. `autoDialectClass`: Add `AutoDialect` interface for automatic access to the database type, can be achieved\n    by `autoDialectClass` configuration for their implementation class, default `DataSourceNegotiationAutoDialect`,\n    priority according to the connection pool. Default implementation, added special handling for 'hikari, Druid,\n    tomcat-JDBC, C3P0, DBCP' type database connection pool, directly from the configuration to get jdbcUrl, when using\n    other types of data sources, still use the old way to get the connection in read jdbcUrl. To use the same method as\n    the old version, you can configure 'autoDialectClass=old'. If the database connection pool type is very clear, you\n    are advised to set it to a specific value. For example, if hikari is used, 'autoDialectClass=hikari' is set. If\n    other connection pools are used, set it to its own implementation class.\n\n18. `boundSqlInterceptors`: Add the `BoundSqlInterceptor` interceptor of the paging plug-in, which can process or simply\n    read SQL in three stages, add the parameter `boundSqlInterceptors`, You can configure multiple implementation class\n    names that implement the BoundSqlInterceptor interface, separated by commas. When PageHelper is called, You can also\n    set this page by using something\n    like `PageHelper.startPage(x,x).boundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor)`.\n\n19. `keepOrderBy`: Preserves the Order by sort of the query when converting count queries. In addition to global\n    configuration, you can set the parameters for a single operation.\n\n20. `keepSubSelectOrderBy`: Preserves the Order by sort of subqueries when converting count queries. You can avoid\n    adding `/*keep orderby*/` to all subqueries and can set it for a single operation in addition to the global\n    configuration.\n\n21. `sqlParser`: configure JSqlParser parser, attention is `com.github.pagehelper.JSqlParser` interface, used to support\n    such as essentially a need for additional configuration.(**6.1.0 remove this parameter**)\n\n#### 6. How to choose Configure these parameters\n\nHere are a few examples for some of the parameters may be used.\n\n##### Scene 1\n\nIf you are still in with a way to call a namespace like iBATIS, you might use `rowBoundsWithCount`.\nIf you want to count when the paging query query, you need to set this parameter to `true`.\n\n**Note:** `PageRowBounds` also need `true`.\n\n##### Scene 2\n\nIf you are still in with a way to call a namespace like iBATIS, If  you think `RowBounds` in the two parameters` offset, limit` not as good as `pageNum, pageSize` easy to understand.\nYou can use the `offsetAsPageNum` parameter, when the parameter is set to `true`, `offset` as `pageNum`, `limit` and `pageSize` mean the same thing.\n\n##### Scene 3\n\nIf you feel you have to paginate a page somewhere and you still want to query all the results with control parameters.\nYou can configure `pageSizeZero` to` true`,\nAfter configuration, when `pageSize = 0` or `RowBounds.limit = 0` will query all the results.\n\n##### Scene 4\n\nIf you want the user to enter the page number is not in the legal scope (the first page to the last page) to correctly respond to the correct results page,\nThen you can configure `reasonable` to` true`, and if `pageNum <= 0` will query the first page, the `pageNum> pages(total pages)` will query the last page.\n\n##### Scene 5\n\nIf you configure dynamic data sources in Spring and connect different types of databases,\nyou can configure `autoRuntimeDialect` to` true`,\nwhich will use matching pagination queries when using different data sources.\nIn this case, you also need to pay attention to the `closeConn` parameter,\nbecause the type of access to the data source will get a database connection,\nso the need to control this parameter to obtain a connection, whether to close the connection.\n\nDefault is `true`, and some database connections can not be closed after the follow-up database operations.\nAnd some database connections will not be closed soon because the number of connections out of the database caused no\nresponse.\nTherefore, when using this feature, in particular, you need to pay attention to whether the use of the data source needs\nto close the database connection.\n\nWhen you do not use dynamic data sources but only automatically get `helperDialect`,\nthe database connection will only get once,\nso there is no need to worry about whether this connection will lead to a database error,\nbut also according to the characteristics of the data source to choose whether to close the connection.\n\n### 3. How to use in your code\n\nPlease note before\nreading [Important Notice](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/en/Important.md)\n\nPageHelper supports the following usage:\n\n```java\n//1. use by RowBounds\nList<User> list = sqlSession.selectList(\"x.y.selectIf\", null, new RowBounds(0, 10));\n//or interface\nList<User> list = userMapper.selectIf(1, new RowBounds(0, 10));\n//or PageRowBounds\nPageRowBounds rowBounds = new PageRowBounds(0, 10);\nList<User> list = userMapper.selectIf(1, rowBounds);\nlong total = rowBounds.getTotal();\n\n//2. use static method startPage\nPageHelper.startPage(1, 10);\nList<User> list = userMapper.selectIf(1);\n\n//3. use static method offsetPage\nPageHelper.offsetPage(0, 10);\nList<User> list = userMapper.selectIf(1);\n\n//4. method parameters\npublic interface CountryMapper {\n    List<User> selectByPageNumSize(\n            @Param(\"user\") User user,\n            @Param(\"pageNum\") int pageNum,\n            @Param(\"pageSize\") int pageSize);\n}\n//config supportMethodsArguments=true\nList<User> list = userMapper.selectByPageNumSize(user, 1, 10);\n\n//5. POJO parameters\npublic class User {\n    //other fields\n    //The following two parameters must be the same name as the params parameter\n    private Integer pageNum;\n    private Integer pageSize;\n}\npublic interface CountryMapper {\n    List<User> selectByPageNumSize(User user);\n}\n//When the pageNum! = null && pageSize! = null in the user instance, this method will be automatically pagination\nList<User> list = userMapper.selectByPageNumSize(user);\n\n//6. ISelect interface\n//jdk6,7 anonymous class, return Page\nPage<User> page = PageHelper.startPage(1, 10).doSelectPage(new ISelect() {\n    @Override\n    public void doSelect() {\n        userMapper.selectGroupBy();\n    }\n});\n//jdk8 lambda\nPage<User> page = PageHelper.startPage(1, 10).doSelectPage(()-> userMapper.selectGroupBy());\n\n//return PageInfo\npageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(new ISelect() {\n    @Override\n    public void doSelect() {\n        userMapper.selectGroupBy();\n    }\n});\n//in lambda\npageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(() -> userMapper.selectGroupBy());\n\n//do count only\nlong total = PageHelper.count(new ISelect() {\n    @Override\n    public void doSelect() {\n        userMapper.selectLike(user);\n    }\n});\n//lambda\ntotal = PageHelper.count(()->userMapper.selectLike(user));\n```\n\nIntroduced The most common ways.\n\n#### 1). RowBounds and PageRowBounds\n\n```java\nList<User> list=sqlSession.selectList(\"x.y.selectIf\",null,new RowBounds(1,10));\n```\n\nUsing this method, you can use the Row Bounds parameter for paging, which is the least invasive method. As we can see,\nthe call using the Row Bounds parameter doesn't add anything else.\n\nWhen the paging plug-in detects that the Row Bounds parameter is used, the query is <b> physically paginated</b>.\n\nThere are two special arguments to RowBounds for this method of calling. You can see Scene 1 and 2 above\n\n**Note:**  You can use Row Bounds not only in namespace mode, but also when using an interface. For example:\n\n```java\n//A physical paging query is also performed in this case\nList<User> selectAll(RowBounds rowBounds);\n```\n\n**Note:** Since RowBounds by default does not get the total number of queries, the PageRowBounds plug-in provides a '\nPageRowBounds' object that inherits from RowBounds. The' Total 'property is added to this object to get the total number\nof queries after performing a pagination query.\n\n#### 2). `PageHelper.startPage` Static method calls\n\nIn addition to the `PageHelper.startPage` method, the `PageHelper.offsetPage` method is also provided.\n\nCall the `PageHelper.startPage` static method before the MyBatis query method that you want to page. The first MyBatis\nquery method immediately following this method will be paginated.\n\n##### Example 1：\n\n```java\n//Get page 1, 10 items, default query total count\nPageHelper.startPage(1,10);\n//The first SELECT method immediately following is paginated\n        List<User> list=userMapper.selectIf(1);\nassertEquals(2, list.get(0).getId());\n        assertEquals(10,list.size());\n//When paging, the actual returned result list type is Page<E>. If you want to take out paging information, you need to force the conversion to Page<E>.\n        assertEquals(182,((Page)list).getTotal());\n```\n\n##### Example 2：\n```java\n//request: url?pageNum=1&pageSize=10\n//Supports ServletRequest,Map,POJO objects, and PARams parameters\nPageHelper.startPage(request);\n//The first SELECT method immediately following is paginated\nList<User> list = userMapper.selectIf(1);\n\n//Subsequent pages will not be paginated unless Page helper.start Page is called again\nList<User> list2 = userMapper.selectIf(null);\n//list1\nassertEquals(2, list.get(0).getId());\nassertEquals(10, list.size());\n//During paging, the actual returned result list type is Page<E>. If you want to take out paging information, you need to force conversion to Page<E>.\n//Or use the Page Info class (described in the example below)\nassertEquals(182, ((Page) list).getTotal());\n//list2\nassertEquals(1, list2.get(0).getId());\nassertEquals(182, list2.size());\n```\n\n##### Example 3，Use `PageInfo`:\n\n```java\n//Get page 1, 10 items, default query total count\nPageHelper.startPage(1,10);\n        List<User> list=userMapper.selectAll();\n//Wrap the results with Page Info\n        PageInfo page=new PageInfo(list);\n//Test all Page Info properties\n//Page Info contains a very comprehensive set of paging properties\n        assertEquals(1,page.getPageNum());\n        assertEquals(10,page.getPageSize());\n        assertEquals(1,page.getStartRow());\n        assertEquals(10,page.getEndRow());\n        assertEquals(183,page.getTotal());\n        assertEquals(19,page.getPages());\n        assertEquals(1,page.getFirstPage());\n        assertEquals(8,page.getLastPage());\n        assertEquals(true,page.isFirstPage());\n        assertEquals(false,page.isLastPage());\n        assertEquals(false,page.isHasPreviousPage());\n        assertEquals(true,page.isHasNextPage());\n```\n\n#### 3). Using parameters\n\nTo use the parametric approach, you need to set the `supportMethodsArguments` parameter to `true`, as well as\nthe `params` parameter.\nFor example, the following configuration:\n\n```xml\n<plugins>\n    <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n        <!-- Use the following method to configure the parameters, all of which are described later -->\n        <property name=\"supportMethodsArguments\" value=\"true\"/>\n        <property name=\"params\" value=\"pageNum=pageNumKey;pageSize=pageSizeKey;\"/>\n\t</plugin>\n</plugins>\n```\n\nIn the MyBatis method:\n```java\nList<User> selectByPageNumSize(\n@Param(\"user\") User user,\n@Param(\"pageNumKey\") int pageNum,\n@Param(\"pageSizeKey\") int pageSize);\n```\n\nWhen this method is called, it is paged because both `pageNumKey` and `pageSizeKey` arguments are found. Several\nparameters provided by PARams can be used in this way.\n\nIn addition to the above method, if the User object contains these two parameter values, you can also have the following\nmethod:\n\n```java\nList<User> selectByPageNumSize(User user);\n```\n\nWhen both `pageNumKey` and `pageSizeKey` arguments are found from User, the method is paged.\n\nNote: The presence of both `pageNum` and `pageSize` will trigger the paging operation. In this case, the other paging\nparameters will take effect.\n\n#### 3). `PageHelper` Safety call\n\n##### 1. Using the RowBounds and PageRowBounds arguments is extremely safe\n\n##### 2. The parametric approach is extremely safe\n\n##### 3. The call using the `ISelect` interface is extremely secure\n\nIn addition to being secure, the ISelect interface specifically converts the query to a simple count query, which\nconverts any query method into a `select count(*)` query method.\n\n##### 4. When does this lead to unsafe paging?\n\nThe `PageHelper` method uses a static `ThreadLocal` argument, and the page argument is bound to the thread.\n\nThis is safe as long as you can ensure that the MyBatis query method is followed by the `PageHelper` method call.\nBecause PageHelper automatically clears objects stored in ThreadLocal in the Finally section.\n\nIf an exception occurs before the code enters the Executor, the thread is not available. This is an artificial Bug (for\nexample, when an interface method does not match an XML method and a 'MappedStatement' is not found). It does not cause\nthe ThreadLocal argument to be used incorrectly.\n\nBut if you write code like this, it is not safe to use it:\n```java\nPageHelper.startPage(1, 10);\nList<User> list;\nif(param1 != null){\n    list = userMapper.selectIf(param1);\n} else {\n    list = new ArrayList<User>();\n}\n```\n\nIn this case, because param1 is null, it causes PageHelper to produce a page parameter, but it is not consumed, so it\nremains on the thread. When this thread is used again, it may cause the paging parameter to be consumed by a method that\nshould not be paged, resulting in unexplained paging.\n\nThe above code should look like this:\n```java\nList<User> list;\nif(param1 != null){\n    PageHelper.startPage(1, 10);\n    list = userMapper.selectIf(param1);\n} else {\n    list = new ArrayList<User>();\n}\n```\n\nIt's safe to write it this way.\n\nIf you're worried about this, you can manually clean up the paging parameters stored in ThreadLocal by using the\nfollowing:\n```java\nList<User> list;\nif(param1 != null){\n    PageHelper.startPage(1, 10);\n    try{\n        list = userMapper.selectAll();\n    } finally {\n        PageHelper.clearPage();\n    }\n} else {\n    list = new ArrayList<User>();\n}\n```\n\nIt's not pretty, and it's unnecessary.\n\n### 4. MyBatis and Spring integration example\n\nIf you are not familiar with Spring integration, you can refer to the following two\n\nThere is only basic configuration information, without any off-the-shelf functionality, as a starting point for building\nthe framework\n\n- [integration Spring 3.x](https://github.com/abel533/Mybatis-Spring/tree/spring3.x)\n- [integration Spring 4.x](https://github.com/abel533/Mybatis-Spring)\n\n### 5. Spring Boot integration example\n\n- [pagehelper-spring-boot-samples](https://github.com/pagehelper/pagehelper-spring-boot/tree/master/pagehelper-spring-boot-samples)\n- https://github.com/abel533/MyBatis-Spring-Boot\n"
  },
  {
    "path": "wikis/en/Important.md",
    "content": "## Important Note \n\n### `PageHelper.startPage` method important tips\n\nOnly the first Mybatis query (select) method immediately after the `PageHelper.startPage` method will be paged.\n\n### Please do not configure more than one PageHelper\n\nWhen using Spring, you can config PageHelper by `mybatis-config.xml` or `Spring<bean>`.\nSelect one of them, do not configure PageHelper in two ways at the same time.\n\n### PageHelper does not support paging with `for update` statement\n\n### PageHelper does not support Nested Results Mapping\n\nSince the nested result mode causes the resultSet to be folded, \nthe total number of results for the paged query will decrease after folding.\nSo It cannot guarantee the number of paged results correctly.\n"
  },
  {
    "path": "wikis/en/Test.md",
    "content": "## Test\n\nIn order to guarantee the stability of PageHelper, the project contains a large number of unit tests, and can be tested for supported databases.\n\n### Multi database test\n\nTo make it easier to test different databases, \nadd a different database mybatis configuration file to the `src/test/resources` directory, \nand modify the configuration in `test.properties` \nso that the tests can be tested with different configurations.\n\nIn order to make it easier to test different database, \nthere are many different mybatis profile in the `src/test/resources` directory.\nBy modifying the `test.properties` allows you to test different databases.\n`test.properties`：  \n\n```properties\n# Need to configure the corresponding database first\n\n# Write the database name which you want to test\n# Optional values as following\n#hsqldb\n#mysql\n#mariadb - Note In the config files, database port is 3309\n#oracle\n#postgresql\n#sqlserver\n#db2\n#h2\n#derby\ndatabase = hsqldb\n```"
  },
  {
    "path": "wikis/zh/Changelog.md",
    "content": "## 更新日志\n\n\n### 6.1.1 - 2025-06-20\n\n- 新增对 SunDB 数据库的分页功能支持 **by wangsl**\n- 新增对 Xugu（虚谷数据库）的适配支持 **by 吴启洋**\n- 修复在复制 `countBoundSql` 时未正确复制 `additionalParameter` 的问题 **by yefeng**\n- 修复 `offsetPage` 示例代码错误 **by S00ahKim**\n- 修复 Jakarta/Javax ServletRequest 兼容性问题，支持 Spring Boot 3.x **by PING**\n- 新增 `PageInfo.of()` 重载方法，支持手动指定查询记录总数返回分页信息 **by yesAnd**\n- 升级 MyBatis 版本至 3.5.19（从 3.5.10）\n- 升级 Guava 版本至 33.4.8-jre（从 32.0.0-jre）\n- 升级 Logback Classic 版本至 1.2.13（从 1.2.11）\n- 优化 Xugu JDBC 依赖配置，添加 `<scope>test</scope>`\n- 修复英文文档中的拼写错误和链接引用 **by Coco Liliace**\n- 补充相关注释信息，提高代码可读性 **by yesAnd**\n- 解决依赖安全漏洞，更新相关组件版本\n\n#### 兼容性说明\n- 本版本与之前版本保持向后兼容\n- 新增数据库支持：SunDB、Xugu（虚谷数据库）\n- 修复了 Spring Boot 3.x 兼容性问题，建议使用 Jakarta EE 的用户升级\n\n#### 升级建议\n- 所有用户建议升级，特别是使用 Spring Boot 3.x 或需要新数据库支持的用户\n- 使用 SunDB 或虚谷数据库的用户可以直接使用分页功能\n- 升级前请确保相关依赖版本兼容性\n\n### 6.1.0 - 2023-12-16\n\n- 发布6.1.0，PageHelper 提供 jsqlparser直接依赖都是中间接口，可以通过SPI替换默认实现\n- 升级jsqlparser版本4.7，重新实现order by，分页，count查询\n- 简化pom.xml配置，去掉shade内嵌jsqlparser方式，改为通过外部依赖选择不同的jsqlparser版本，允许自己SPI扩展\n- jsqlparser解析不使用线程池，支持SPI扩展覆盖SqlParser实现\n- SqlServer分页改为SqlServerSqlParser接口，添加参数 sqlServerSqlParser 覆盖默认值\n- OrderByParser提取OrderBySqlParser接口，增加 orderBySqlParser 参数，可以覆盖默认实现\n- OrderByParser静态方法改为普通方法，为后续改接口做准备\n- jdk8+后不再需要JSqlParser接口，移除该接口，文档标记该参数（_该参数早期用于支持sqlserver特殊配置_）\n  兼容jsqlparser4.7版本\n- maven-compiler-plugin固定版本以去除警告，并增加构建稳定性 qxo\n- gitignore .vscode for vscode ide qxo\n- 修改bug https://github.com/pagehelper/Mybatis-PageHelper/issues/779 chenyuehui\n\n为了兼容 jsqlparser 4.5 和 4.7，以及后续可能存在的其他版本，新建了一个 pagehelper-sqlparser 项目，目前提供了 4.5 和 4.7\n两个实现，\n使用时从 pagehelper 排除 jsqlparser，然后选择一个 jsqlparser 实现即可，当前版本默认使用的 4.7 版本的代码，\n因此如果想换 4.5 的实现，可以按照下面方式进行配置：\n\n```xml\n\n<dependency>\n    <groupId>com.github.pagehelper</groupId>\n    <artifactId>pagehelper</artifactId>\n    <version>6.1.0</version>\n    <exclusions>\n        <exclusion>\n            <groupId>com.github.jsqlparser</groupId>\n            <artifactId>jsqlparser</artifactId>\n        </exclusion>\n    </exclusions>\n</dependency>\n<dependency>\n    <groupId>com.github.pagehelper</groupId>\n    <artifactId>sqlparser4.5</artifactId>\n    <version>6.1.0</version>\n</dependency>\n```\n\nSPI 替换默认值的优先级低于 `sqlServerSqlParser`,`orderBySqlParser`,`countSqlParser` 参数指定的实现，不指定时如果存在SPI实现，即可生效，\nSPI 可以参考 pagehelper-sqlsource 模块代码。\n\nJSqlParser 默认解析 SQL 会使用临时创建的 `Executors.newSingleThreadExecutor()`，这里通过 API 跳过了线程池：\n\n```java\nCCJSqlParser parser = CCJSqlParserUtil.newParser(statementReader);\nparser.withSquareBracketQuotation(true);\nreturn parser.Statement();\n```\n\nJSqlParser 使用线程池的目的是为了防止解析超时，因此如果你遇到过超时的情况，可以引入下面的依赖（通过SPI覆盖了默认实现，超时时间10秒）：\n\n```xml\n\n<dependency>\n    <groupId>com.github.pagehelper</groupId>\n    <artifactId>sqlparser-timeout</artifactId>\n    <version>6.1.0</version>\n</dependency>\n```\n\n### 6.0.0 - 2023-11-05\n\n- 基于jdk8适配，6.0开始不支持jdk6和7，如果有需要可以使用5.x版本\n- 增加异步count支持，全局配置`asyncCount`，默认`false`，单次设置：`PageHelper.startPage(1, 10).enableAsyncCount()`;\n  异步使用独立连接（事务）查询，有增删改操作影响查询时不适合开启异步查询。closed #334\n- JSqlParser默认开启 `parser.withSquareBracketQuotation(true)`，支持 SqlServer `[]`\n- feat: 在`PageInfo`类中新增了用以进行数据对象转换的方法 ` <E> PageInfo<E> convert(Page.Function<T, E> function)` **by\n  codeke**\n- `CountSqlParser`改为接口，允许通过`countSqlParser`参数替换为自己的实现，支持 #772\n- `dialectAlias`支持简化配置，例如`dm=oracle;oracle=oracle9i`，直接引用现在的缩写，不用写类全名\n- `countColumn`添加注入检测，fixed #686\n- 增加`PageParam`类，不内嵌对象（会影响使用），如果想用可以继承该对象，closed #562\n- 所有异常信息改为英文提示\n- 放开 `setLocalPage`，支持 #771\n- 解决`sqlserver`带union sql解析时处理order by错误的问题，fixed #768\n- 优化total逻辑，解决指定不分页查询，同时指定order by时无效的问题，fixed #641\n- 修改 dialect 实例化逻辑，保证类完成配置后使用，fixed #742\n- `dialectAliasMap`改为`LinkedHashMap`，可以按配置顺序进行匹配，fixed #758\n- 行云数据库分页BUG修复 **by maimaitiyaer_bonc**\n\n### 5.3.3 - 2023-06-03\n\n- Ignoring unnecessarily generated surefire-report **by java-codehunger**\n- 支持从URL中解析openGauss 数据库 对应的方言 **by saxisuer**\n- 修复sql注入检验不正确问题 #716 **by uyong**\n- 支持从url中解析人大金仓kingbase8对应的方言 **by univ**\n- 添加支持cirrodata的分页 #705 **by sxh0570**\n\n### 5.3.2 - 2022-09-18\n\n- 使用文档更新，所有参数都包含在内，首页默认文档改为中文。\n- Add support for kingbase. by **HanHuimin001**\n- 增加 `debug` 参数，默认 `false`，为`true`时开启`debug`模式，开始 `debug` 模式后将记录调用堆栈 by **huyingqian**\n- Add 支持count的sql支持hint语法 by **zhanliquan**\n- 增加 `PageProperties` 接口，框架内部实例化的扩展类如果实现了这个接口，可以通过这个接口的方法获取分页插件配置。\n- 增加 `CountMsIdGen` 接口，可以通过 `countMsIdGen`\n  配置自定义实现类，该类用于生成查询对应COUNT查询的msId。默认实现还是使用`countSuffix`\n  ，通过扩展可以实现如 `selectByExample` 映射到对应的 `selectCountByExample` 方法。\n- 增加 `keepOrderBy` 和 `keepSubSelectOrderBy` 配置。\n- 增加 `sqlParser` 配置，增加 `JSqlParser` 接口，解决 jsqlparser 和 jdk 兼容性导致无法额外配置的问题(**6.1.0 移除该参数\n  **)。\n- 测试使用 logback 日志框架，去掉log4j。\n- 解决 `dialectKey` 为空导致NPE，fixed #656\n\n关于以上参数的详细介绍，请查看 [如何使用分页插件](HowToUse.md)。\n\n### 5.3.1 - 2022-06-14\n\n- 处理 CVE-2022-28111 漏洞，限制 order by 参数，避免 SQL 注入\n- Add support for as400. **by bluezealot**\n- 优化分页结果包装类的泛型参数 **by 章福来**\n- 规范PostgreSQL分页参数的顺序 **by outian**\n\n### 5.3.0 - 2021-10-07\n\n- 增加 `AutoDialect` 接口用于自动获取数据库类型，可以通过 `autoDialectClass` 配置为自己的实现类，默认使用 `DataSourceNegotiationAutoDialect`，优先根据连接池获取。\n  默认实现中，增加针对 `hikari,druid,tomcat-jdbc,c3p0,dbcp` 类型数据库连接池的特殊处理，直接从配置获取jdbcUrl，当使用其他类型数据源时，仍然使用旧的方式获取连接在读取jdbcUrl。\n  想要使用和旧版本完全相同方式时，可以配置 `autoDialectClass=old`。当数据库连接池类型非常明确时，建议配置为具体值，例如使用 hikari 时，配置 `autoDialectClass=hikari`\n  ，使用其他连接池时，配置为自己的实现类。\n- 支持运行时动态指定使用的 dialect 实现，例如 `PageHelper.startPage(1, 10).using(\"oracle\");`\n  或者 `PageHelper.startPage(2, 10).using(\"org.exmaple.CustomDialect\");`\n- `PageInfo` 增加空实例常量属性 `PageInfo.EMPTY` 以及内容判断 `boolean hasContent()`。\n- 启动中增加 banner, 需要日志级别 debug，可以通过 `-Dpagehelper.banner=false` 或者环境变量 `PAGEHELPER_BANNER=false` 关闭\n  ```\n   DEBUG [main] -\n\n   ,------.                           ,--.  ,--.         ,--.\n   |  .--. '  ,--,--.  ,---.   ,---.  |  '--'  |  ,---.  |  |  ,---.   ,---.  ,--.--.\n   |  '--' | ' ,-.  | | .-. | | .-. : |  .--.  | | .-. : |  | | .-. | | .-. : |  .--'\n   |  | --'  \\ '-'  | ' '-' ' \\   --. |  |  |  | \\   --. |  | | '-' ' \\   --. |  |\n   `--'       `--`--' .`-  /   `----' `--'  `--'  `----' `--' |  |-'   `----' `--'\n   `---'                                   `--'                        is intercepting.\n   ```\n  增加 banner 的目的在于，如果你配置了多次分页插件，你会看到 banner 输出多次，你可以在 `PageInterceptor` 构造方法断点看看那些地方进行了实例化。\n- 完善 Count 查询，当存在 having 时，不在优化查询列。查询列存在有别名的函数或者运算时也不优化查询列，避免 order by 或 having 中使用的别名不存在。\n- 增加判断处理某些数据（如 TDEngine）查询 count 无结果时返回 null\n- 添加 Firebird 数据库支持和 SqlServer2012 分页语法相同。\n- 添加 impala 数据库自动识别。\n- JSqlParser 升级为 4.2 版本。\n\n> 距离上次更新3个月左右，这次更新直接让假期少了3天 :running: ，关了 GitHub 和 Gitee 上的 200 多个issue，不一定所有问题都得到了处理，如果你还有疑问，可以继续提 issue，下个大版本会考虑直接 6.0，计划全部升级到 java 8，功能保持不变。\n\n### 5.2.1 - 2021-06-20\n\n- 升级依赖 jsqlparser 4.0, mybatis 3.5.7\n- 自动识别以下数据库：\n    - 虚谷数据库 xugu #599\n    - 神通数据库 oscar by **ranqing**\n    - 瀚高数据库 highgo by **ashaiqing**\n- BoundSqlInterceptorChain拦截器index参数bug, fixed #587\n- fixed #558\n- 添加 PostgreSQL 方言 by **liym@home**\n- fixed #604, 解决total丢失的问题\n- 规范注释, fixed #547\n\n### 5.2.0 - 2020-07-26\n\n- jsqlparser升级到3.2版本，sql解析更好，对sqlserver支持更好。\n- 修改 sqlserver 方式中的替换正则，现在允许 with( nolock ) 括号中存在空格。\n- 解决 reasonable 和 pageSizeZero,以及 offset 用法中的bug，现在的含义和结果更一致。\n- 分页 SQL 拼接过程中增加换行符，避免原始 SQL 中存在注释导致分页部分无效。\n- Oracle 和 Db2 中的行号 ROW_ID 别名改为 PAGEHELPER_ROW_ID，避免和常用名称冲突。\n- 解决单个参数ProviderSql使用其他拦截器时的特殊问题（支持 mybatis 3.4.0+）[by 罗震宇](https://github.com/luozhenyu)\n- 支持自动识别 clickhouse，使用 MySQL 方式进行分页。\n- 将 startRow, endRow 类型从 int 改为 long。\n- Page 增加 `public <T> PageInfo<T> toPageInfo(Function<E, T> function)` 方法，用于转换查询结果中的数据。\n- 参考 pr#476 提供 `·`Oracle9iDialect`，这也是曾经用过的一种分页方式，可以自己测试选择合适的分页方式。\n\n   目前提供的两种 Oracle 分页如下：\n   ```sql\n   -- OracleDialect 外层控制范围\n   WHERE ROW_ID <= ? AND ROW_ID > ?\n   -- Oracle9iDialect 内外分别控制范围\n   TMP_PAGE WHERE ROWNUM <= ? ) WHERE ROW_ID > ?\n   ```\n- 增加分页插件的 `BoundSqlInterceptor` 拦截器，可以在3个阶段对 SQL 进行处理或者简单读取，\n   增加参数 `boundSqlInterceptors`，可以配置多个实现 `BoundSqlInterceptor` 接口的实现类名，\n   使用英文逗号隔开。PageHelper调用时，也可以通过类似\n   `PageHelper.startPage(x,x).boundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor)`针对本次分页进行设置。\n\n\n本次更新最大的变化是增加了 `BoundSqlInterceptor`，通过该接口可以在运行时拦截分页处理的 SQL（BoundSQL对象）：\n```java\n/**\n * BoundSql 处理器\n */\npublic interface BoundSqlInterceptor {\n    /**\n     * boundsql 处理\n     *\n     * @param type     类型\n     * @param boundSql 当前类型的 boundSql\n     * @param cacheKey 缓存 key\n     * @param chain    处理器链，通过 chain.doBoundSql 方法继续执行后续方法，也可以直接返回 boundSql 终止后续方法的执行\n     * @return 允许修改 boundSql 并返回修改后的\n     */\n    BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain);\n\n    enum Type {\n        /**\n         * 原始SQL，分页插件执行前，先执行这个类型\n         */\n        ORIGINAL,\n        /**\n         * count SQL，第二个执行这里\n         */\n        COUNT_SQL,\n        /**\n         * 分页 SQL，最后执行这里\n         */\n        PAGE_SQL\n    }\n\n    /**\n     * 处理器链，可以控制是否继续执行\n     */\n    interface Chain {\n        Chain DO_NOTHING = new Chain() {\n            @Override\n            public BoundSql doBoundSql(Type type, BoundSql boundSql, CacheKey cacheKey) {\n                return boundSql;\n            }\n        };\n\n        BoundSql doBoundSql(Type type, BoundSql boundSql, CacheKey cacheKey);\n    }\n}\n```\n\n接口中包含了 boundSql 接口方法，还有 Type 枚举，和 Chain 接口的定义，自己实现的时候不需要考虑 Chain。\n\n通过 `boundSqlInterceptors` 参数配置拦截器，执行时存在下面三种情况：\n\n1. 不管当前执行的 SQL 是否会分页，都会执行 `Type.ORIGINAL` 类型的拦截器方法，配置后一定会执行。\n\n2. 调用分页方法时，拦截器会继续执行 `Type.COUNT_SQL` 类型的拦截器方法，这个方法只有执行分页并且指定要进行 count 查询时才会执行。\n\n3. 调用分页方法时，如果 count > 0，就会执行 `Type.PAGE_SQL` 类型的拦截器方法，这个方法只有执行分页时才会执行。\n\n> 通过 `PageHelper.startPage(1, Integer.MAX_VALUE, false).boundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor)`\n> 这种指定的参数时，也能起到不进行分页和count查询，但是可以执行 `Type.ORIGINAL` 类型的拦截器方法。\n\n当前拦截器在整个分页执行过程中，会执行3次，对应 Type 枚举的 3 个类型，执行顺序也一致。\n\n如果想获取分页 SQL 执行前的，只需要关注 Type.ORIGINAL，另外两种就是 count 执行前和分页执行前（count=0时分页方法不执行，这里也不会执行）。\n\n以测试代码为例：\n\n```java\npublic class TestBoundSqlInterceptor implements BoundSqlInterceptor {\n    public static final String COMMENT = \"\\n /* TestBoundSqlInterceptor */\\n\";\n\n    @Override\n    public BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain) {\n        if (type == Type.ORIGINAL) {\n            String sql = boundSql.getSql();\n            MetaObject metaObject = MetaObjectUtil.forObject(boundSql);\n            metaObject.setValue(\"sql\", sql + COMMENT);\n        }\n        return chain.doBoundSql(type, boundSql, cacheKey);\n    }\n\n}\n```\n上面这段代码在 sql 执行前先修改原始 SQL，只是在最后增加了一段注释，不影响 SQL 执行，通过下面的方式配置：\n\n```xml\n<plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n    <!-- 支持通过Mapper接口参数来传递分页参数 -->\n    <property name=\"helperDialect\" value=\"mysql\"/>\n    <property name=\"boundSqlInterceptors\"\n              value=\"com.github.pagehelper.test.basic.provider.TestBoundSqlInterceptor,com.github.pagehelper.test.basic.provider.TestBoundSqlInterceptor\"/>\n</plugin>\n```\n这里为了说明该参数值可以是多个，因此重复配置了一次，也就是上面的拦截器会执行两次。\n\n这样配置后，上面的 SQL 在分页执行的时候就会修改 SQL。\n\n除了这种配置方式外，还支持 PageHelper.startPage 时临时指定，这种方式会把拦截器放到链头先执行，因此可以控制后续的是否执行，也可以在后续所有执行外，做最后处理再返回。\n\n示例：\n\n```java\nPageHelper.startPage(1, 10).boundSqlInterceptor(new BoundSqlInterceptor() {\n    @Override\n    public BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain) {\n        System.out.println(\"before: \" + boundSql.getSql());\n        BoundSql doBoundSql = chain.doBoundSql(type, boundSql, cacheKey);\n        System.out.println(\"after: \" + doBoundSql.getSql());\n        if (type == Type.ORIGINAL) {\n            Assert.assertTrue(doBoundSql.getSql().contains(TestBoundSqlInterceptor.COMMENT));\n        }\n        return doBoundSql;\n    }\n});\n```\n\n\n\n\n### 5.1.11 - 2019-11-26\n\n- 增加神通数据库的支持 **wangss**\n- Add support for HerdDB - support HerdDB, mostly like MySQL - auto detect HerdDB **Enrico Olivelli**\n- fix some typos and grammar issues **LHearen**\n\n### 5.1.10 - 2019-06-05\n\n在 *5.1.0 - 2017-08-28* 版本中，增加 `ReplaceSql` 接口用于处理 sqlServer 的 `with(nolock)` 问题，增加了针对性的 `replaceSql` 参数，\n可选值为 `simple` 和 `regex`，或者是实现了ReplaceSql接口的全限定类名。默认值为 `simple`，仍然使用原来的方式处理，\n新的 `regex` 会将如 `table with(nolock)` 处理为 `table_PAGEWITHNOLOCK`。\n\n本次更新仅仅是把默认值从 `simple` 改为了 `regex`，使用 `regex` 方式几乎能 100% 解决 sqlServer 的分页问题。\n\n下面是两个 issue 中的示例。\n\n#### 示例 SQL [#76](https://github.com/pagehelper/pagehelper-spring-boot/issues/76)\n\n原始 SQL：\n```sql\nSELECT *\nFROM\nforum_post_info a with(nolock)\nLEFT JOIN forum_carcase_tags as b with(nolock) on a.id = b.carcase_id where b.tag_id = 127\n```\n转换的 Count SQL：\n```sql\nSELECT COUNT(0)\nFROM forum_post_info a WITH (NOLOCK)\n\tLEFT JOIN forum_carcase_tags b WITH (NOLOCK) ON a.id = b.carcase_id\nWHERE b.tag_id = 127\n```\n转换的分页 SQL：\n```sql\nSELECT TOP 10 *\nFROM (\n\tSELECT ROW_NUMBER() OVER (ORDER BY RAND()) AS PAGE_ROW_NUMBER, *\n\tFROM (\n\t\tSELECT *\n\t\tFROM forum_post_info a WITH (NOLOCK)\n\t\t\tLEFT JOIN forum_carcase_tags b WITH (NOLOCK) ON a.id = b.carcase_id\n\t\tWHERE b.tag_id = 127\n\t) PAGE_TABLE_ALIAS\n) PAGE_TABLE_ALIAS\nWHERE PAGE_ROW_NUMBER > 1\nORDER BY PAGE_ROW_NUMBER\n```\n\n#### 示例 SQL [#398](https://github.com/pagehelper/Mybatis-PageHelper/issues/398)\n\n原始 SQL：\n```sql\nSelect AUS.ScheduleID, AUS.SystemID, AUS.ClinicID, AUS.DoctorID, AUS.ScheduleDate,\n\tAUS.StartTime, AUS.EndTime, AUS.Status, AUS.BookBy, AUS.Note, AUS.Remark, AUS.SourceType, CM.CompanyName,\n\tAU.UserName As DoctorName, AU.UserNumber As DoctorNumber, CC.CodeDesc As ClinicName, CD.Lat, CD.Lng,\n\tCD.ContactTel, CD.Address, CR.ConsultationStatusID, CR.RegisterStatus,A1.CodeDesc as AreaLevel1, A2.CodeDesc as AreaLevel2\n\tFrom ACM_User_Schedule AUS with(nolock)\n\tLeft Join Client_Register CR with(nolock) On AUS.BookBy=CR.ClientID And CR.SourceType='F' And AUS.ClientRegisterNum=CR.ClientRegisterNum\n\tInner Join ACM_User AU with(nolock) On AU.UserID = AUS.DoctorID\n\tInner Join Code_Clinic CC with(nolock) On AUS.ClinicID=CC.CodeID\n\tInner Join Clinic_Detail CD with(nolock) On CC.CodeID = CD.ClinicID\n\tInner Join Code_Area A1 with(nolock) On CD.AreaLevel1ID=A1.CodeID\n\tInner Join Code_Area A2 with(nolock) On CD.AreaLevel2ID=A2.CodeID\n\tInner Join Company_Master CM with(nolock) On CC.SystemID = CM.SystemID\n\tWhere BookBy=1\n```\n转换的 Count SQL：\n```sql\nSELECT COUNT(0)\nFROM ACM_User_Schedule AUS WITH (NOLOCK)\n\tLEFT JOIN Client_Register CR WITH (NOLOCK)\n\tON AUS.BookBy = CR.ClientID\n\t\tAND CR.SourceType = 'F'\n\t\tAND AUS.ClientRegisterNum = CR.ClientRegisterNum\n\tINNER JOIN ACM_User AU WITH (NOLOCK) ON AU.UserID = AUS.DoctorID\n\tINNER JOIN Code_Clinic CC WITH (NOLOCK) ON AUS.ClinicID = CC.CodeID\n\tINNER JOIN Clinic_Detail CD WITH (NOLOCK) ON CC.CodeID = CD.ClinicID\n\tINNER JOIN Code_Area A1 WITH (NOLOCK) ON CD.AreaLevel1ID = A1.CodeID\n\tINNER JOIN Code_Area A2 WITH (NOLOCK) ON CD.AreaLevel2ID = A2.CodeID\n\tINNER JOIN Company_Master CM WITH (NOLOCK) ON CC.SystemID = CM.SystemID\nWHERE BookBy = 1\n```\n转换的分页 SQL：\n```sql\nSELECT TOP 10 ScheduleID, SystemID, ClinicID, DoctorID, ScheduleDate\n\t, StartTime, EndTime, Status, BookBy, Note\n\t, Remark, SourceType, CompanyName, DoctorName, DoctorNumber\n\t, ClinicName, Lat, Lng, ContactTel, Address\n\t, ConsultationStatusID, RegisterStatus, AreaLevel1, AreaLevel2\nFROM (\n\tSELECT ROW_NUMBER() OVER (ORDER BY RAND()) AS PAGE_ROW_NUMBER, ScheduleID, SystemID, ClinicID, DoctorID\n\t\t, ScheduleDate, StartTime, EndTime, Status, BookBy\n\t\t, Note, Remark, SourceType, CompanyName, DoctorName\n\t\t, DoctorNumber, ClinicName, Lat, Lng, ContactTel\n\t\t, Address, ConsultationStatusID, RegisterStatus, AreaLevel1, AreaLevel2\n\tFROM (\n\t\tSELECT AUS.ScheduleID, AUS.SystemID, AUS.ClinicID, AUS.DoctorID, AUS.ScheduleDate\n\t\t\t, AUS.StartTime, AUS.EndTime, AUS.Status, AUS.BookBy, AUS.Note\n\t\t\t, AUS.Remark, AUS.SourceType, CM.CompanyName, AU.UserName AS DoctorName, AU.UserNumber AS DoctorNumber\n\t\t\t, CC.CodeDesc AS ClinicName, CD.Lat, CD.Lng, CD.ContactTel, CD.Address\n\t\t\t, CR.ConsultationStatusID, CR.RegisterStatus, A1.CodeDesc AS AreaLevel1, A2.CodeDesc AS AreaLevel2\n\t\tFROM ACM_User_Schedule AUS WITH (NOLOCK)\n\t\t\tLEFT JOIN Client_Register CR WITH (NOLOCK)\n\t\t\tON AUS.BookBy = CR.ClientID\n\t\t\t\tAND CR.SourceType = 'F'\n\t\t\t\tAND AUS.ClientRegisterNum = CR.ClientRegisterNum\n\t\t\tINNER JOIN ACM_User AU WITH (NOLOCK) ON AU.UserID = AUS.DoctorID\n\t\t\tINNER JOIN Code_Clinic CC WITH (NOLOCK) ON AUS.ClinicID = CC.CodeID\n\t\t\tINNER JOIN Clinic_Detail CD WITH (NOLOCK) ON CC.CodeID = CD.ClinicID\n\t\t\tINNER JOIN Code_Area A1 WITH (NOLOCK) ON CD.AreaLevel1ID = A1.CodeID\n\t\t\tINNER JOIN Code_Area A2 WITH (NOLOCK) ON CD.AreaLevel2ID = A2.CodeID\n\t\t\tINNER JOIN Company_Master CM WITH (NOLOCK) ON CC.SystemID = CM.SystemID\n\t\tWHERE BookBy = 1\n\t) PAGE_TABLE_ALIAS\n) PAGE_TABLE_ALIAS\nWHERE PAGE_ROW_NUMBER > 1\nORDER BY PAGE_ROW_NUMBER\n```\n\nSQL 经过 https://tool.oschina.net/codeformat/sql 格式化。\n\n\n### 5.1.9 - 2019-05-29\n\n- 升级 jsqlparser 为 2.0，升级 mybatis 为 3.5.1，解决兼容性问题。\n- 完善分页逻辑判断，fixed #389\n- 解决 MetaObject 版本兼容性问题 fixed #349\n- 处理 order by 解析失败时输出警告日志，不在抛出异常\n- 解决三处可能会导致countColumn失效的问题 fixed #325\n- 解决 BIT_ 少的逗号 fixed #341\n- 处理文档中的失效链接 isea533\n- 文档示例错误，fixed #366\n- fixed #373 NPE 问题\n\n### 5.1.8 - 2018-11-11\n\n- 解决 sqlserver 中 with(nolock) 的问题([#pr10](https://gitee.com/free/Mybatis_PageHelper/pulls/10)) by [lvshuyan](https://gitee.com/lvshuyan)\n\n### 5.1.7 - 2018-10-11\n\n- 增加对阿里云PPAS数据库的支持，自动识别edb，fixed #281\n\n### 5.1.6 - 2018-09-05\n\n- 增加参数 useSqlserver2012，设置为 true 后，使用 sqlserver2012(Dialect) 作为 SqlServer 数据库的默认分页方式，这种情况在动态数据源时方便使用。默认使用的低版本(05,08)分页方式。\n- 增加 IPage 接口，目前支持 mybatis 查询方法只有一个参数，并且参数实现 IPage 接口时，如果存在分页参数，就会自动进行分页查询。感谢 [moonfruit](https://github.com/moonfruit) 两年前的 issue。\n- 解决 HashSet 并发问题 fixed #276\n- 优化代码结构，精简拦截器代码\n\n### 5.1.5 - 2018-09-02\n\n- 优化代码，去掉没必要的校验(**by lenosp**)\n- 解决 pageKey 多处理一次的小问题 #268\n- 新增 gitee 提供的 javadoc 文档(https://apidoc.gitee.com/free/Mybatis_PageHelper)\n- 解决默认反射不带缓存的问题 fixed #275\n- 优化mysql ifnull函数导致分页性能问题 (**by miaogr**)（这个修改最终改成了下面的 `aggregateFunctions`）\n- jsqlparser 升级为 1.2 版本，和 1.0 有不兼容的情况，已经解决。 fixed 273\n- 去掉 PageInfo 中存在歧义的 g(s)etFirstPage 和 g(s)etLastPage 两个方法\n- 抛出排序时解析失败的异常 fixed #257\n- 解决 Spring `<bean>` 方式配置时，没有 `properties` 属性时的初始化问题 fixed #26\n- 修复Oracle分页会漏查数据的问题 (**by muyun12**)\n- 新增 `aggregateFunctions` 参数(`CountSqlParser`), 允许手动添加聚合函数（影响行数），所以以聚合函数开头的函数，在进行 count 转换时，会套一层。其他函数和列会被替换为 count(0),其中count列可以自己配置。\n\n增加 `aggregateFunctions` 参数后，和原先最大的区别是，如果存在 `select ifnull(xxx, yy) from table ...`，原先的 count 查询是\n`select count(0) from (select ifnull(xxx, yy) from table ...) temp_count`，现在会区别聚合函数，如果不是聚合函数，就会变成\n`select count(0) from table ...`。\n\n默认包含的聚合函数前缀如下：\n\n```java\n/**\n * 聚合函数，以下列函数开头的都认为是聚合函数\n */\nprivate static final Set<String> AGGREGATE_FUNCTIONS = new HashSet<String>(Arrays.asList(\n        (\"APPROX_COUNT_DISTINCT,\" +\n        \"ARRAY_AGG,\" +\n        \"AVG,\" +\n        \"BIT_\" +\n        //\"BIT_AND,\" +\n        //\"BIT_OR,\" +\n        //\"BIT_XOR,\" +\n        \"BOOL_,\" +\n        //\"BOOL_AND,\" +\n        //\"BOOL_OR,\" +\n        \"CHECKSUM_AGG,\" +\n        \"COLLECT,\" +\n        \"CORR,\" +\n        //\"CORR_,\" +\n        //\"CORRELATION,\" +\n        \"COUNT,\" +\n        //\"COUNT_BIG,\" +\n        \"COVAR,\" +\n        //\"COVAR_POP,\" +\n        //\"COVAR_SAMP,\" +\n        //\"COVARIANCE,\" +\n        //\"COVARIANCE_SAMP,\" +\n        \"CUME_DIST,\" +\n        \"DENSE_RANK,\" +\n        \"EVERY,\" +\n        \"FIRST,\" +\n        \"GROUP,\" +\n        //\"GROUP_CONCAT,\" +\n        //\"GROUP_ID,\" +\n        //\"GROUPING,\" +\n        //\"GROUPING,\" +\n        //\"GROUPING_ID,\" +\n        \"JSON_,\" +\n        //\"JSON_AGG,\" +\n        //\"JSON_ARRAYAGG,\" +\n        //\"JSON_OBJECT_AGG,\" +\n        //\"JSON_OBJECTAGG,\" +\n        //\"JSONB_AGG,\" +\n        //\"JSONB_OBJECT_AGG,\" +\n        \"LAST,\" +\n        \"LISTAGG,\" +\n        \"MAX,\" +\n        \"MEDIAN,\" +\n        \"MIN,\" +\n        \"PERCENT_,\" +\n        //\"PERCENT_RANK,\" +\n        //\"PERCENTILE_CONT,\" +\n        //\"PERCENTILE_DISC,\" +\n        \"RANK,\" +\n        \"REGR_,\" +\n        \"SELECTIVITY,\" +\n        \"STATS_,\" +\n        //\"STATS_BINOMIAL_TEST,\" +\n        //\"STATS_CROSSTAB,\" +\n        //\"STATS_F_TEST,\" +\n        //\"STATS_KS_TEST,\" +\n        //\"STATS_MODE,\" +\n        //\"STATS_MW_TEST,\" +\n        //\"STATS_ONE_WAY_ANOVA,\" +\n        //\"STATS_T_TEST_*,\" +\n        //\"STATS_WSR_TEST,\" +\n        \"STD,\" +\n        //\"STDDEV,\" +\n        //\"STDDEV_POP,\" +\n        //\"STDDEV_SAMP,\" +\n        //\"STDDEV_SAMP,\" +\n        //\"STDEV,\" +\n        //\"STDEVP,\" +\n        \"STRING_AGG,\" +\n        \"SUM,\" +\n        \"SYS_OP_ZONE_ID,\" +\n        \"SYS_XMLAGG,\" +\n        \"VAR,\" +\n        //\"VAR_POP,\" +\n        //\"VAR_SAMP,\" +\n        //\"VARIANCE,\" +\n        //\"VARIANCE_SAMP,\" +\n        //\"VARP,\" +\n        \"XMLAGG\").split(\",\")));\n```\n\n### 5.1.4 - 2018-04-22\n\n- 默认增加达梦数据库(dm)，可以自动根据 jdbcurl 使用Oracle方式进行分页。如果想换 SqlServer 可以参考 5.1.3 更新日志中的 `dialectAlias` 参数。\n\n### 5.1.3 - 2018-04-07\n\n- `Page` 的 `toString` 方法增加 `super.toString()`。最终输出形式如 `Page{属性}[集合]`。\n- 增加 `defaultCount` 参数，用于控制默认不带 count 查询的方法中，是否执行 count 查询，默认 true 会执行 count 查询，这是一个全局生效的参数，多数据源时也是统一的行为。\n- 增加 `dialectAlias` 参数，允许配置自定义实现的 别名，可以用于根据 JDBCURL 自动获取对应实现，允许通过此种方式覆盖已有的实现，配置示例如（多个时分号隔开）：\n  ```xml\n  <property name=\"dialectAlias\" value=\"oracle=com.github.pagehelper.dialect.helper.OracleDialect\"/>\n  ```\n- 增加 `PageSerializable`，简化版的 `PageInfo` 类，不需要那么多信息时，推荐使用或者参考这个类实现。\n\n### 5.1.2 - 2017-09-18\n\n- 解决单独使用 `PageHelper.orderBy` 方法时的问题 #110;\n\n### 5.1.1 - 2017-08-30\n\n- 此次更新解决的问题只和 SqlServer 2005,2008 有关\n- 解决 `RegexWithNolockReplaceSql` 中正则 `w?` 错误的问题，应该是 `w+`。\n- 解决 `SqlServerDialect` 中没有初始化默认 `SimpleWithNolockReplaceSql` 的错误。\n- `SqlServerRowBoundsDialect` 增加对 `replaceSql` 参数的支持。\n\n### 5.1.0 - 2017-08-28\n\n- 增加 4.x 以前版本包含的排序功能，用法一致（PageHelper增加了几个排序相关的方法）。\n- 分页 SQL 转换为预编译 SQL。\n- 增加 `ReplaceSql` 接口用于处理 sqlServer 的 `with(nolock)` 问题，增加了针对性的 `replaceSql` 参数，可选值为 `simple` 和 `regex`，或者是实现了ReplaceSql接口的全限定类名。默认值为\n`simple`，仍然使用原来的方式处理，新的 `regex` 会将如 `table with(nolock)` 处理为 `table_PAGEWITHNOLOCK`。\n- `PageRowBounds` 增加 `count` 属性，可以控制是否进行 `count` 查询。\n\n### 5.1.0-beta2 - 2017-08-23\n\n- 增加 `ReplaceSql` 接口用于处理 sqlServer 的 `with(nolock)` 问题，增加了针对性的 `replaceSql` 参数，可选值为 `simple` 和 `regex`，或者是实现了ReplaceSql接口的全限定类名。默认值为\n`simple`，仍然使用原来的方式处理，新的 `regex` 会将如 `table with(nolock)` 处理为 `table_PAGEWITHNOLOCK`。\n\n### 5.1.0-beta - 2017-08-22\n\n- 增加 4.x 以前版本包含的排序功能，用法一致（PageHelper增加了几个排序相关的方法）。\n- 分页 SQL 转换为预编译 SQL。\n\n### 5.0.4 - 2017-08-01\n\n- 增加对 `Phoenix` 数据库的简单配置支持，配置 `helperDialect=phoenix` 即可，也可以自动识别 `Phoenix` 数据库的 jdbc url。\n- count 查询的缓存 `msCountMap` key 改为 `String` 类型，key 为 count 查询的 `MappedStatement` 的 id。\n- 增加 `countSuffix` count 查询后缀配置参数，该参数是针对 `PageInterceptor` 配置的，默认值为 `_COUNT`。\n- 增加手写 count 查询支持，详情看下面介绍。\n\n#### 增加手写 count 查询支持\n\n增加 `countSuffix` count 查询后缀配置参数，该参数是针对 `PageInterceptor` 配置的，默认值为 `_COUNT`。\n\n分页插件会优先通过当前查询的 msId + `countSuffix` 查找手写的分页查询。\n\n如果存在就使用手写的 count 查询，如果不存在，仍然使用之前的方式自动创建 count 查询。\n\n例如，如果存在下面两个查询：\n```xml\n<select id=\"selectLeftjoin\" resultType=\"com.github.pagehelper.model.User\">\n    select a.id,b.name,a.py from user a\n    left join user b on a.id = b.id\n    order by a.id\n</select>\n<select id=\"selectLeftjoin_COUNT\" resultType=\"Long\">\n    select count(distinct a.id) from user a\n    left join user b on a.id = b.id\n</select>\n```\n上面的 `countSuffix` 使用的默认值 `_COUNT`，分页插件会自动获取到 `selectLeftjoin_COUNT` 查询，这个查询需要自己保证结果数正确。\n\n返回值的类型必须是`resultType=\"Long\"`，入参使用的和 `selectLeftjoin` 查询相同的参数，所以在 SQL 中要按照 `selectLeftjoin` 的入参来使用。\n\n因为 `selectLeftjoin_COUNT` 方法是自动调用的，所以不需要在接口提供相应的方法，如果需要单独调用，也可以提供。\n\n上面方法执行输出的部分日志如下：\n```\nDEBUG [main] - ==>  Preparing: select count(distinct a.id) from user a left join user b on a.id = b.id\nDEBUG [main] - ==> Parameters:\nTRACE [main] - <==    Columns: C1\nTRACE [main] - <==        Row: 183\nDEBUG [main] - <==      Total: 1\nDEBUG [main] - Cache Hit Ratio [com.github.pagehelper.mapper.CountryMapper]: 0.0\nDEBUG [main] - ==>  Preparing: select a.id,b.name,a.py from user a left join user b on a.id = b.id order by a.id LIMIT 10\nDEBUG [main] - ==> Parameters:\nTRACE [main] - <==    Columns: ID, COUNTRYNAME, COUNTRYCODE\nTRACE [main] - <==        Row: 1, Angola, AO\nTRACE [main] - <==        Row: 2, Afghanistan, AF\nTRACE [main] - <==        Row: 3, Albania, AL\n```\n\n### 5.0.3 -2017-06-20\n\n- 解决`supportMethodsArguments`参数不起作用的问题，由于之前默认为`false`，不起作用后效果为`true`，建议升级到最新版本。\n\n### 5.0.2 - 2017-05-30\n\n- `Page<E>` 继承 `Closeable` 接口，在 JDK7+中可以使用 `try()`方式调用，自动调用`PageHelper.clearPage();`[#58](https://github.com/pagehelper/Mybatis-PageHelper/issues/58)。\n- 解决：DB2分页时必须要指定子查询的别名,不然会发生异常 [#52](https://github.com/pagehelper/Mybatis-PageHelper/issues/52)\n- 解决：分页取数据时，如果数据一条都没有返回, pageInfo.isIsLastPage(); 返回false [#50](https://github.com/pagehelper/Mybatis-PageHelper/issues/50)\n\n### 5.0.1 - 2017-04-23\n\n- 增加新的参数 `countColumn` 用于配置自动 count 查询时的查询列，默认值`0`，也就是 `count(0)`\n- `Page` 对象也新增了 `countColumn` 参数，可以针对具体查询进行配置\n- 针对文档显示问题进行修改，by liumian* [PR #30](https://github.com/pagehelper/Mybatis-PageHelper/pull/30)\n- 解决 sqlserver2012 分页错误的问题 [42](https://github.com/pagehelper/Mybatis-PageHelper/issues/42)\n\n### 5.0.0 - 2017-01-02\n\n- 使用 [QueryInterceptor 规范](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/src/main/java/com/github/pagehelper/QueryInterceptor.java) 处理分页逻辑\n- 新的分页插件拦截器为 `com.github.pagehelper.PageInterceptor`\n- 新的 `PageHelper` 是一个特殊的 `Dialect` 实现类，以更友好的方式实现了以前的功能\n- 新的分页插件仅有 `dialect` 一个参数，默认的 `dialect` 实现类为 `PageHelper`\n- `PageHelper` 仍然支持以前提供的参数，在最新的使用文档中已经全部更新\n- `PageHelper` 的 `helperDialect` 参数和以前的 `dialect` 功能一样，具体可以看文档的参数说明\n- 增加了基于纯 `RowBounds` 和 `PageRowBounds` 的分页实现，在 `com.github.pagehelper.dialect.rowbounds` 包中，这是用于作为 `dialect` 参数示例的实现，后面会补充更详细的文档\n- 去掉了不适合出现在分页插件中的 orderby 功能，以后会提供单独的排序插件\n- 去掉了 `PageHelper` 中不常用的方法\n- 新的文档，更新历来更新日志中提到的重要内容，提供英文版本文档\n- 解决 bug [#149](http://git.oschina.net/free/Mybatis_PageHelper/issues/149)\n- 将 Db2RowDialect 改为 Db2RowBoundsDialect\n- 所有分页插件抛出的异常改为 PageException\n\n### 4.2.1 - 2016-12-11\n\n- 解决`SimpleCache`类遗留问题导致的错误 [#143](http://git.oschina.net/free/Mybatis_PageHelper/issues/143) fix by [dhhua](https://github.com/dhhua)\n\n### 4.2.0 - 2016-12-09\n\n- 使用新的方式进行分页，4.2版本是从5.0版本分离出来的一个特殊版本，这个版本兼容4.x的所有功能，5.0版本时为了简化分页逻辑，会去掉部分功能，所以4.2是4.x的最后一个版本。\n- 支持 MyBatis 3.1.0+ 版本\n- 增加对 Derby 数据库的支持\n- 对除 informix 外的全部数据库进行测试，全部通过\n- PageHelper增加手动清除方法`clearPage()`\n- 解决 SqlServer 多个`with(nolock)`时出错的问题\n- 对CountMappedStatement 进行缓存，配置方式见BaseSqlUtil 319行\n- 由于SqlServer的sql处理特殊，因此增加了两个SQL缓存，具体配置参考SqlServerDialect类\n- 添加 sqlserver 别名进行排序功能，在解析sql时，会自动将使用的别名转换成列名 by panmingzhi\n- 新增`sqlCacheClass`参数，该参数可选，可以设置sql缓存实现类，默认为`SimpleCache`，当项目包含guava时，使用`GuavaCache`，也可以通过参数`sqlCacheClass`指定自己的实现类，有关详情看`com.github.pagehelper.cache`包。\n- 解决#135，增加/*keep orderby*/注解，SQL中包含该注释时，count查询时不会移出order by\n- sqlserver没有orderby时，使用`order by rand()` #82 #118\n\n### 4.1.6 - 2016-06-05\n\n- 通过间接处理字符串解决SqlServer中不支持`with(nolock)`的问题#86，详情可以看`SqlServerParser`和`SqlServer2012Dialect`\n\n### 4.1.5 - 2016-05-29\n\n- 更新`PageProviderSqlSource`，支持3.4.0版本的`Provider`注解方式的分页#102\n- 解决`SqlUtil`未初始化`PARAMS`属性导致的错误\n\n### 4.1.4 - 2016-05-12\n\n- 解决`closeConn`未设置时，默认值被覆盖变成`false`的问题#97\n- `closeConn`不只对动态数据源有效，当没有设置`dialect`属性自动获取数据库类型的时候同样有效\n- 解决关闭tomcat的时候提示线程安全问题#98，这个问题不会导致内存溢出，已经增加处理\n\n### 4.1.3 - 2016-03-31\n\n- 解决反射类没有完全捕获异常的问题#94\n- 把SqlServer类所有private都改成了protected，方便继承修改#93\n\n### 4.1.2 - 2016-03-06\n\n- 增加可配参数`closeConn`，当使用动态数据源时，分页插件获取jdbcUrl后，控制是否关闭当前连接，默认`true`关闭\n- count查询改为`count(0)`，分库分表情况下的效率可能更高\n\n### 4.1.1 - 2016-01-05：\n\n- 解决动态数据源时获取连接后未关闭的严重bug#80\n- 解决动态数据源时SqlSource和parser绑定导致不能切换方言的问题\n\n### 4.1.0 - 2015-12-30：\n\n- 增加`autoRuntimeDialect`参数，允许在运行时根据多数据源自动识别对应方言的分页（暂时不支持自动选择`sqlserver2012`，只能使用`sqlserver`）。\n- 去掉了4.0.3版本增加的`returnPageInfo`参数，接口返回值不支持`PageInfo`类型，可以使用下面`ISelect`中演示的方法获取\n- 增加对`SqlServer2012`的支持，需要手动指定`dialect=sqlserver2012`，否则会使用2005的方式进行分页\n- jsqlparser升级到0.9.4版本，使用jar包时必须用最新的0.9.4版本，使用Maven会自动依赖0.9.4\n- 增加`ISelect`接口，方便调用，使用方法可以参考`src/test/java/com.github.pagehelper.test.basic.TestISelect`测试。\n\n### 使用该接口可以参考如下用法(返回值为`Page`或`PageInfo`)：\n\n```java\n//jdk6,7用法，创建接口\nPage<User> page = PageHelper.startPage(1, 10).setOrderBy(\"id desc\").doSelectPage(new ISelect() {\n    @Override\n    public void doSelect() {\n        userMapper.selectGroupBy();\n    }\n});\n//jdk8 lambda用法\nPage<User> page = PageHelper.startPage(1, 10).setOrderBy(\"id desc\").doSelectPage(()-> userMapper.selectGroupBy());\n//为了说明可以链式使用，上面是单独setOrderBy(\"id desc\")，也可以直接如下\nPage<User> page = PageHelper.startPage(1, 10, \"id desc\").doSelectPage(()-> userMapper.selectGroupBy());\n\n//也可以直接返回PageInfo，注意doSelectPageInfo方法和doSelectPage\npageInfo = PageHelper.startPage(1, 10).setOrderBy(\"id desc\").doSelectPageInfo(new ISelect() {\n    @Override\n    public void doSelect() {\n        userMapper.selectGroupBy();\n    }\n});\n//对应的lambda用法\npageInfo = PageHelper.startPage(1, 10).setOrderBy(\"id desc\").doSelectPageInfo(() -> userMapper.selectGroupBy());\n\n//count查询，返回一个查询语句的count数\nlong total = PageHelper.count(new ISelect() {\n    @Override\n    public void doSelect() {\n        userMapper.selectLike(user);\n    }\n});\n//lambda\ntotal = PageHelper.count(()->userMapper.selectLike(user));\n```\n\n### 4.0.3 - 2015-11-09：\n\n - `PageHelper`新增3个`offsetPage`方法，参数主要是`offset`和`limit`，允许不规则分页\n\n - 新增两个可配参数`supportMethodsArguments`和`returnPageInfo`（该参数在4.1.0版本去掉），具体含义和用法请看[如何使用分页插件](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md)中的参数介绍\n\n### 4.0.2 - 2015-11-02\n\n - 简化`Page<E>`类，包含排序条件`orderBy`\n\n - `dialect`参数是数据库名称时不区分大小写\n\n - `dialect`参数可以设置为实现`com.github.pagehelper.parser.Parser`接口的实现类全限定名称\n\n - 增加对`h2`数据库的支持\n\n - 将`OrderByHelper`(排序插件)融合到`PageHelper`中，移除`OrderByHelper`\n\n - 该版本调整比较大，但对开发人员影响较小，为以后扩展和完善提供方便\n\n### 4.0.1 -2015-09-10\n\n - 解决[#60 -使用RPC时，因Page类引用了RowBounds，导致反序列化失败](http://git.oschina.net/free/Mybatis_PageHelper/issues/60) by [马金凯](http://git.oschina.net/mxb)\n\n - 这个改动主要是去掉了`Page<E>`构造方法中的`RowBounds`，用`int[]`数组替换了`RowBounds`\n\n### 4.0.0 - 2015-07-13\n\n - 配置属性`dialect`不在强制要求，可以不写，分页插件会自动判断\n\n - 解决从request中获取分页参数时的错误,感谢<b>探路者☆</b>\n\n - `PageInfo`增加空构造方法，所有属性增加`setter`方法\n\n - 增加对排序的支持\n\n - 可以单独使用`PageHelper.orderBy(String orderBy)`对查询语句增加排序，也可以配合`startPage`的其他方法使用\n\n - 可以使用`PageHelper.startPage(int start,int size,String orderBy)`对分页查询进行排序\n\n - 修改分页查询的处理逻辑，主要是将原`sqlSource`包装成可以分页和排序的`sqlSource`\n\n### 3.7.5 - 2015-06-12\n\n - 增加对MyBatis3.2.0以上版本的校验，如果是不是3.2.0以上版本，会抛出异常提示\n\n - 解决3.7.1更新中实际没有解决的入参为不可变`Map`类型时的错误\n\n### 3.7.4 - 2015-05-26\n\n - 为了支持`3.3.0`去掉了分页插件自带的`SytemObjectMetaObject`类(该类在早期版本为了支持3.2.0以前的MyBatis)\n\n - 最新支持MyBatis - 3.2.0到最新3.3.0版本\n\n### 3.7.3 - 2015-05-22\n\n - `Page`继承的`ArrayList`，会根据`pageSize`初始化大小，这就导致当`pageSize`过大（如`Integer.MAX_VALUE`），实际数据量很小时的内存溢出，此处改为初始化大小为0的`List`。\n\n - 当想查询某页后面的全部数据时，可以使用`PageHelper.startPage(pageNum, Integer.MAX_VALUE)`进行分页，`RowBounds(offset, Integer.MAX_VALUE)`一样。\n\n - 针对`PageHelper.startPage(1, Integer.MAX_VALUE)`优化，会取消分页，直接查询全部数据（能起到`pageSizeZero`参数所起的作用）。\n\n - 针对`RowBounds(0, Integer.MAX_VALUE)`优化，会取消分页，直接查询全部数据（能起到`pageSizeZero`参数所起的作用）。\n\n### 3.7.2 - 2015-05-13\n\n - jsqlparser解析sql会抛出Error异常，由于只捕获Exception，所以导致部分解析失败的sql无法使用嵌套方式处理，所以修改为捕获`Throwable`。\n\n### 3.7.1 - 2015-05-05\n\n - 增加`Infomix`数据库支持，设置`dialect`值为`infomix`即可\n - 解决入参为不可变`Map`类型时的错误\n\n### 3.7.0 - 2015-04-21\n\n - 由于`orderby`参数经常被错误认为的使用，因此该版本全面移除了`orderby`\n - `Page<E>`移除`orderby`属性\n - `PageHelper`的`startPage`方法中，移除包含`orderby`参数的方法，sqlserver相关包含该参数的全部移除\n - 对SqlServer进行分页查询时，请在sql中包含order by语句，否则会抛出异常\n - 当`offsetAsPageNum=false`的时候，由于PageNum问题，`RowBounds`查询的时候`reasonable`会强制为false，已解决\n - 少数情况下的select中包含单个函数查询时，会使用嵌套的count查询\n\n### 3.6.4 - 2015-04-05\n\n - 重构，将原来的内部类全部独立出来，尤其是`Parser`接口以及全部实现。\n   现在可以直接使用`Parser`，使用方法如下：\n\n   ```java\n   String originalSql = \"Select * from user o where id > 10 order by id desc \";\n\n   Parser parser = AbstractParser.newParser(\"mysql\");\n   //获取count查询sql\n   String countSql = parser.getCountSql(originalSql);\n   //获取分页sql，这种方式不适合sqlserver数据库\n   String pageSql = parser.getPageSql(originalSql);\n\n   //sqlserver用下面的方法\n   SqlServer sqlServer = new SqlServer();\n   pageSql = sqlServer.convertToPageSql(originalSql, 1, 10);\n   ```\n\n### 3.6.3 - 2015-03-10\n\n - 解决了一个潜在的bug，对[通用Mapper](http://git.oschina.net/free/Mapper)中的`SqlMapper`进行分页时，需要使用这个版本\n\n### 3.6.2 - 2015-03-09\n\n - 本次更新只是增加了一个异常提示，当错误的配置了多个分页插件时，会有更友好的错误提示：\n\n   >分页插件配置错误:请不要在系统中配置多个分页插件(使用Spring时,mybatis-config.xml和Spring<bean>配置方式，请选择其中一种，不要同时配置多个分页插件)！\n\n### 3.6.1 - 2015-02-28\n\n - 解决select distinct导致count查询结果不正确的bug#35\n\n - 完善测试\n\n### 3.6.0 - 2015-02-03\n\n- 支持db2数据库\n\n- 支持sqlserver(2005+)数据库\n\n- sqlserver注意事项：\n    - 请先保证你的SQL可以执行\n    - sql中最好直接包含order by，可以自动从sql提取\n    - 如果没有order by，可以通过入参提供，但是需要自己保证正确(<b>3.7.0版本以后，移除了该参数，请在sql中包含order by</b>)\n    - 如果sql有order by，可以通过orderby参数覆盖sql中的order by\n    - order by的列名不能使用别名(`UNION,INTERSECT,MINUS,EXCEPT`等复杂sql不受限制，具体可以自己尝试)\n    - 表和列使用别名的时候不要使用单引号(')\n\n- 简单修改结构\n\n- `startPage`方法返回值从`void`改为`Page`，获取`Page`后可以修改参数值\n\n - `Page`增加一个针对sqlserver的属性`orderBy`(<b>3.7.0版本以后，移除了该属性</b>)，用法看上面的<b>注意事项</b>\n\n - `Page`增加了一个链式赋值的方法，可以像下面这样使用：\n   `PageHelper.startPage(1,10).count(false).reasonable(true).pageSizeZero(false)`\n\n - `PageHelper`增加了`startPage(int pageNum, int pageSize,String orderBy)`方法(<b>3.7.0版本以后，移除了该方法</b>)，针对sqlserver\n\n### 3.5.1 - 2015-01-20\n\n - 解决[bug#25](http://git.oschina.net/free/Mybatis_PageHelper/issues/25)，当参数是null并且是动态查询时，由于加入分页参数，导致参数不在是null，因而会导致部分判断出错，导致异常。\n\n - 上面这个bug会影响使用了动态标签并且允许入参为null的所有查询，虽然并不常见，但是建议各位使用最新版本\n\n### 3.5.0 - 2015-01-11\n\n - 增加更丰富的调用方法[#23](http://git.oschina.net/free/Mybatis_PageHelper/issues/23)\n   - `startPage(int pageNum, int pageSize)`\n   - `startPage(int pageNum, int pageSize, boolean count)`\n   - +`startPage(int pageNum, int pageSize, boolean count, Boolean reasonable)`\n   - +`startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero)`\n   - +`startPage(Object params)`<b>注：只能是`Map`或`ServletRequest`类型</b>\n\n   参数中的`reasonable`、`pageSizeZero`都可以覆盖默认配置，如果传`null`会用默认配置。\n\n - 为了支持`startPage(Object params)`方法，增加了一个`params`参数来配置参数映射，用于从`Map`或`ServletRequest`中取值，详细内容看文档下面的具体介绍。\n\n - 解决一个`<foreach>`标签使用对象内部属性循环时的bug[#24](http://git.oschina.net/free/Mybatis_PageHelper/issues/24)\n\n### 3.4.2 - 2014-12-27\n\n- `PageInfo`中的`judgePageBoudary`方法修改：\n   ```java\n    isLastPage = pageNum == pages && pageNum != 1;\n    //改为\n    isLastPage = pageNum == pages;\n   ```\n\n### 3.4.1 - 2014-12-24\n\n - 重大bug修复，`SqlParser`解析sql失败的时候返回了不带`count(*)`的sql，导致查询失败。\n\n - 产生原因，由于`SqlParser`在系统中出现的位置修改后，导致这里出现错误。\n\n - 强烈推荐各位更新到最新版本。\n\n### v3.4.0 - 2014-12-18\n\n - 增加了对`@SelectProvider`注解方法的支持，不使用这种方式的不影响\n\n - 对基本逻辑进行修改，减少反射调用和获取`BoundSql`次数\n\n### v3.3.2 - 2014-12-10\n\n - `PageInfo` 增加序列化。\n\n### v3.3.1bug修复 - 2014-12-07\n\n- 动态sql时，判断条件不会出现在ParameterMappings中，会导致获取不到属性。通常是因为判断条件中的属性没有出现在`#{}`中。\n\n### v3.3.0\n\n1. 对`MappedStatement`对象进行缓存，包括count查询的`MappedStatement`以及分页查询的`MappedStatement`，分页查询改为预编译查询。\n\n2. 独立的`SqlUtil`类，由于原来的`PageHelper`太复杂，因此将拦截器外的其他代码独立到`SqlUtil`中，方便查看代码和维护。`SqlUtil`中增加`Parser`接口，提供一个抽象的`SimpleParser`实现，不同数据库的分页代码通过继承`SimpleParser`实现。\n\n3. 特殊的`Parser`实现类`SqlParser`类，这是一个独立的java类，主要提供了更高性能的count查询sql，可以根据sql自动改为`count(*)`查询，自动去除不需要的`order by`\n   语句，如果需要使用该类，只要把该类放到`SqlUtil`类相同的包下即可，同时需要引入Jar包`jsqlparser-0.9.1.jar`。\n\n4. 增强的`PageInfo`类，`PageInfo`类包含了分页几乎所有需要用到的属性值，减少了对分页逻辑的过多投入。\n\n4. 分页合理化，自动处理pageNum的异常情况。例如当pageNum<=0时，会设置pageNum=1，然后查询第一页。当pageNum>pages(总页数)时，自动将pageNum=pages，查询最后一页。\n\n5. 增加对`PostgreSQL`,`MariaDB`,`SQLite`支持。其中`MariaDB`,`SQLite`和`Mysql`分页一样。\n\n### v3.2.3\n\n1. 解决`mysql`带有`for update`时分页错误的问题。\n\n2. 当`pageSize`（或`RowBounds`的`limit`）`<=0` 时不再进行分页查询，只会进行count查询（RowBounds需要配置进行count查询），相当于用分页查询来做count查询了。\n\n3. 增加了`pageSizeZero`参数，当`pageSizeZero=true`时，如果`pageSize=0`（或`RowBounds.limit`\n   =0），就会查询全部的结果。这个参数对于那些在特殊情况下要查询全部结果的人有用。配置该参数后会与上面第二条冲突，解决方法就是如果只想查询count，就设置`pageSize<0`（如 `-1`\n   ），只要不等于0（或者不配置pageSizeZero）就不会出现全部查询的情况。\n\n4. 这个版本没有包含count查询时自动去除`order by`的功能，这个功能将会添加到3.3.0版本中。\n\n5. 为了便于本项目的统一管理和发布，本项目会和github上面同步，项目会改为Maven管理的结构。\n\n\n### v3.2.2\n\n1. 简单重构优化代码。\n\n2. 新增`PageInfo`包装类，对分页结果Page<E>进行封装，方便EL使用。\n\n3. 将`SystemMetaObject`类的`fromObject`方法内置到分页插件中，方便低版本的Mybatis使用该插件。\n\n### v3.2.1\n\n1. 新增`offsetAsPageNum`参数，用来控制`RowBounds`中的`offset`是否作为`pageNum`使用，`pageNum`和`startPage`中的含义相同，`pageNum`是页码。该参数默认为`false`，使用默认值时，不需要配置该参数。\n\n2. 新增`rowBoundsWithCount`参数，用来控制使用`RowBounds`时是否执行`count`查询。该参数默认为`false`，使用默认值时，不需要配置该参数。\n\n### v3.2.0\n\n1. 增加了对`Hsqldb`的支持，主要目的是为了方便测试使用`Hsqldb`\n\n2. 增加了该项目的一个测试项目[Mybatis-Sample](http://git.oschina.net/free/Mybatis-Sample)，测试项目数据库使用`Hsqldb`\n\n3. 增加MIT协议\n\n### v3.1.2\n\n1. 解决count sql在`oracle`中的错误\n\n### v3.1.1\n\n1. 统一返回值为`Page<E>`（可以直接按`List`使用）,方便在页面使用EL表达式，如`${page.pageNum}`,`${page.total}`\n\n### v3.1.0\n\n1. 解决了`RowBounds`分页的严重BUG，原先会在物理分页基础上进行内存分页导致严重错误，已修复\n\n2. 增加对MySql的支持，该支持由[鲁家宁](http://my.oschina.net/lujianing)增加。\n\n### v3.0\n\n1. 现在支持两种形式的分页，使用`PageHelper.startPage`方法或者使用`RowBounds`参数\n\n2. `PageHelper.startPage`方法修改，原先的`startPage(int pageNum, int pageSize)`\n   默认求count，新增的`startPage(int pageNum, int pageSize, boolean count)`设置`count=false`可以不执行count查询\n\n3. 移除`endPage`方法，现在本地变量`localPage`改为取出后清空本地变量。\n\n4. 修改`Page<E>`类，继承`ArrayList<E>`\n\n5. 关于两种形式的调用，请看示例代码\n\n### v2.1\n\n1. 解决并发异常\n\n2. 分页sql改为直接拼sql\n\n### v2.0\n\n1. 支持Mybatis缓存，count和分页同时支持（二者同步）\n\n2. 修改拦截器签名，拦截`Executor`\n\n3. 将`Page<E>`类移到外面，方便调用\n\n### v1.0\n\n1. 支持`<foreach>`等标签的分页查询\n\n2. 提供便捷的使用方式\n\n"
  },
  {
    "path": "wikis/zh/HowToUse.md",
    "content": "## 使用方法\n\n### 1. 引入分页插件 <a href=\"https://maven-badges.herokuapp.com/maven-central/com.github.pagehelper/pagehelper\"><img src=\"https://maven-badges.herokuapp.com/maven-central/com.github.pagehelper/pagehelper/badge.svg\"/></a>\n\n#### 1). 使用 Maven\n\n在 pom.xml 中添加如下依赖：\n\n```xml\n\n<dependency>\n    <groupId>com.github.pagehelper</groupId>\n    <artifactId>pagehelper</artifactId>\n    <version>最新版本</version>\n</dependency>\n```\n\n#### 2). 使用 Gradle\n\n在 `build.gradle` 中添加：\n\n```groovy\ndependencies {\n    compile(\"com.github.pagehelper:pagehelper:最新版本\")\n}\n```\n\n#### 3). 使用 Spring Boot 时 <a href=\"https://maven-badges.herokuapp.com/maven-central/com.github.pagehelper/pagehelper-spring-boot-starter\"><img src=\"https://maven-badges.herokuapp.com/maven-central/com.github.pagehelper/pagehelper-spring-boot-starter/badge.svg\"/></a>\n\nMaven：\n\n```xml\n\n<dependency>\n    <groupId>com.github.pagehelper</groupId>\n    <artifactId>pagehelper-spring-boot-starter</artifactId>\n    <version>最新版本</version>\n</dependency>\n```\n\nGradle:\n\n```groovy\ndependencies {\n    compile(\"com.github.pagehelper:pagehelper-spring-boot-starter:最新版本\")\n}\n```\n\n### 2. 配置拦截器插件\n\n特别注意，新版拦截器是 `com.github.pagehelper.PageInterceptor`。\n`com.github.pagehelper.PageHelper` 现在是一个特殊的 `dialect` 实现类，是分页插件的默认实现类，提供了和以前相同的用法。\n\n#### 1). 在 MyBatis 配置 xml 中配置拦截器插件\n\n```xml\n<!--\n    plugins在配置文件中的位置必须符合要求，否则会报错，顺序如下:\n    properties?, settings?,\n    typeAliases?, typeHandlers?,\n    objectFactory?,objectWrapperFactory?,\n    plugins?,\n    environments?, databaseIdProvider?, mappers?\n-->\n<plugins>\n    <!-- com.github.pagehelper为PageHelper类所在包名 -->\n    <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n        <!-- 使用下面的方式配置参数，后面会有所有的参数介绍 -->\n        <property name=\"param1\" value=\"value1\"/>\n    </plugin>\n</plugins>\n```\n\n#### 2). 在 Spring 配置文件中配置拦截器插件\n\n使用 spring 的 XML 配置方式，可以使用 `plugins` 属性像下面这样配置：\n```xml\n<bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n  <!-- 注意其他配置 -->\n  <property name=\"plugins\">\n    <array>\n      <bean class=\"com.github.pagehelper.PageInterceptor\">\n          <property name=\"properties\">\n              <!--使用下面的方式配置参数，一行配置一个 -->\n              <value>\n                  params=value1\n              </value>\n          </property>\n      </bean>\n    </array>\n  </property>\n</bean>\n```\n\n#### 3). 在 Spring Boot 中配置\n\nSpring Boot 引入 starter 后自动生效，对分页插件进行配置时，在 Spring Boot 对应的配置文件 `application.[properties|yaml]` 中配置：\n\nproperties:\n\n```properties\npagehelper.propertyName=propertyValue\npagehelper.reasonable=false\npagehelper.defaultCount=true\n```\n\nyaml:\n\n```yaml\npagehelper:\n  propertyName: propertyValue\n  reasonable: false\n  defaultCount: true # 分页插件默认参数支持 default-count 形式，自定义扩展的参数，必须大小写一致\n```\n\n> 分页插件默认参数支持 default-count 形式，自定义扩展的参数，必须大小写一致。\n>\n>\n支持的默认参数参考: [PageHelperStandardProperties.java](https://github.com/pagehelper/pagehelper-spring-boot/blob/master/pagehelper-spring-boot-autoconfigure/src/main/java/com/github/pagehelper/autoconfigure/PageHelperStandardProperties.java)\n\n#### 4). 分页插件横幅banner设置\n\n为了避免多次配置分页插件导致的错误，配置分页插件后，启动时会输出 banner。\n\n```\nDEBUG [main] -\n\n,------.                           ,--.  ,--.         ,--.\n|  .--. '  ,--,--.  ,---.   ,---.  |  '--'  |  ,---.  |  |  ,---.   ,---.  ,--.--.\n|  '--' | ' ,-.  | | .-. | | .-. : |  .--.  | | .-. : |  | | .-. | | .-. : |  .--'\n|  | --'  \\ '-'  | ' '-' ' \\   --. |  |  |  | \\   --. |  | | '-' ' \\   --. |  |\n`--'       `--`--' .`-  /   `----' `--'  `--'  `----' `--' |  |-'   `----' `--'\n`---'                                   `--'                        is intercepting.\n```\n\n如果在项目启动时输出了多次 banner，就是配置了多次分页插件，根据日志输出的位置排查系统通过哪些方式配置了分页插件。\n\n如果不想在启动时输出 banner，可以通过系统变量或环境变量关闭。\n\n- 系统变量：`-Dpagehelper.banner=false`\n- 环境变量：`PAGEHELPER_BANNER=false`\n\n#### 5). 分页插件参数介绍\n\n分页插件提供了多个可选参数，这些参数使用时，按照上面配置方式中的示例配置即可。\n\n**分页插件可选参数如下：**\n\n1. `debug`: 调试参数，默认 `false` 关闭，设置为 `true` 启用后，可以排查系统中存在的**不安全调用**，[#查看如何安全调用](#3-pagehelper-安全调用)。\n   通过 `PageHelper.startPage` 等静态方法调用设置分页参数时，会记录当前执行的方法堆栈信息，当执行 MyBatis 的查询方法时，会使用设置好的分页参数，\n   此时会输出设置时的方法堆栈，通过查看堆栈，如果和当前执行的方法不一致，那么堆栈中对应的调用就是**不安全调用**，需要根据 [#安全调用](#3-pagehelper-安全调用) 中的方式调整。输出的堆栈示例如下：\n   ```\n   00:19:08.915 [main] DEBUG c.github.pagehelper.PageInterceptor - java.lang.Exception: 设置分页参数时的堆栈信息\n       at com.github.pagehelper.util.StackTraceUtil.current(StackTraceUtil.java:12)\n       at com.github.pagehelper.Page.<init>(Page.java:111)\n       at com.github.pagehelper.Page.<init>(Page.java:126)\n       at com.github.pagehelper.page.PageMethod.startPage(PageMethod.java:139)\n       at com.github.pagehelper.page.PageMethod.startPage(PageMethod.java:113)\n       at com.github.pagehelper.page.PageMethod.startPage(PageMethod.java:102)\n       at com.github.pagehelper.test.basic.PageHelperTest.testNamespaceWithStartPage(PageHelperTest.java:118)\n       ...省略\n\n   00:19:09.069 [main] DEBUG c.g.pagehelper.mapper.UserMapper - Cache Hit Ratio [com.github.pagehelper.mapper.UserMapper]: 0.0\n   00:19:09.077 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Opening JDBC Connection\n   00:19:09.078 [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [org.hsqldb.jdbc.JDBCConnection@6da21078]\n   00:19:09.087 [main] DEBUG c.g.p.m.UserMapper.selectAll_COUNT - ==>  Preparing: SELECT count(1) FROM user\n   00:19:09.121 [main] DEBUG c.g.p.m.UserMapper.selectAll_COUNT - ==> Parameters:\n   00:19:09.131 [main] TRACE c.g.p.m.UserMapper.selectAll_COUNT - <==    Columns: C1\n   00:19:09.131 [main] TRACE c.g.p.m.UserMapper.selectAll_COUNT - <==        Row: 183\n   00:19:09.147 [main] DEBUG c.g.p.m.UserMapper.selectAll_COUNT - <==      Total: 1\n   ```\n\n2. `dialect`：默认情况下会使用 PageHelper 方式进行分页，如果想要实现自己的分页逻辑，可以实现 `Dialect`(`com.github.pagehelper.Dialect`)\n   接口，然后配置该属性为实现类的全限定名称。\n\n3. `countSuffix`：根据查询创建或者查找对应的 count 查询时，追加的 msId 后缀，默认 `_COUNT`。\n\n4. `countMsIdGen`（5.3.2+）：count 方法的 msId 生成方式，默认是 查询的 msId +\n   countSuffix，想要自己定义时，可以实现 `com.github.pagehelper.CountMsIdGen` 接口，将该参数配置为实现的全限定类名即可。\n   **一个常见的用途：** 在有Example查询的情况，`selectByExample` 可以使用对应的 `selectCountByExample` 方法进行 count 查询。\n\n5. `msCountCache`：自动创建查询的 count 查询方法时，创建的 count `MappedStatement` 会进行缓存，默认会优先查找 `com.google.common.cache.Cache`\n   的实现，如果项目没有 guava 依赖就会使用 mybatis 内置的 `CacheBuilder` 创建。想要对缓存进行细粒度的配置请参考源码: `com.github.pagehelper.cache.CacheFactory`\n   ，两种默认方案提供了多个属性进行配置，也可以按照这里要求自己扩展实现。\n\n**下面几个参数都是针对默认 dialect 情况下的参数。使用自定义 dialect 实现时，下面的参数没有任何作用。**\n\n1. `helperDialect`：分页插件会自动检测当前的数据库链接，自动选择合适的分页方式。\n   你可以配置`helperDialect`属性来指定分页插件使用哪种方言。配置时，可以使用下面的缩写值：\n   `oracle`,`mysql`,`mariadb`,`sqlite`,`hsqldb`,`postgresql`,`db2`,`sqlserver`,`informix`,`h2`,`sqlserver2012`,`derby`\n   （完整内容看 [PageAutoDialect](src/main/java/com/github/pagehelper/page/PageAutoDialect.java)）\n   <b>特别注意：</b>使用 SqlServer2012 数据库时，需要手动指定为 `sqlserver2012`，否则会使用 SqlServer2005 的方式进行分页，还可以设置 `useSqlserver2012=true`\n   将2012改为sqlserver的默认方式。\n   你也可以实现 `AbstractHelperDialect`，然后配置该属性为实现类的全限定名称即可使用自定义的实现方法。\n\n2. `dialectAlias`：允许配置自定义实现的 别名，可以用于根据 JDBCURL 自动获取对应实现，允许通过此种方式覆盖已有的实现，配置示例如（多个时分号隔开）：\n   ```xml\n   <property name=\"dialectAlias\" value=\"oracle=com.github.pagehelper.dialect.helper.OracleDialect\"/>\n   ```\n   当你使用的 jdbcurl 不在 [PageAutoDialect](src/main/java/com/github/pagehelper/page/PageAutoDialect.java)\n   默认提供范围时，可以通过改参数实现自动识别。\n\n3. `useSqlserver2012`(sqlserver)：使用 SqlServer2012 数据库时，需要手动指定为 `sqlserver2012`，否则会使用 SqlServer2005\n   的方式进行分页，还可以设置 `useSqlserver2012=true`将2012改为sqlserver的默认方式。\n\n4. `defaultCount`：用于控制默认不带 count 查询的方法中，是否执行 count 查询，默认 `true` 会执行 count 查询，这是一个全局生效的参数，多数据源时也是统一的行为。\n\n5. `countColumn`：用于配置自动 count 查询时的查询列，默认值`0`，也就是 `count(0)`，`Page` 对象也新增了 `countColumn` 参数，可以针对具体查询进行配置。\n\n6. `offsetAsPageNum`：默认值为 `false`，该参数对使用 `RowBounds` 作为分页参数时有效。\n   当该参数设置为 `true` 时，会将 `RowBounds` 中的 `offset` 参数当成 `pageNum` 使用，可以用页码和页面大小两个参数进行分页。\n\n7. `rowBoundsWithCount`：默认值为`false`，该参数对使用 `RowBounds` 作为分页参数时有效。\n   当该参数设置为`true`时，使用 `RowBounds` 分页会进行 count 查询。\n\n8. `pageSizeZero`：默认值为 `false`，当该参数设置为 `true` 时，如果 `pageSize=0` 或者 `RowBounds.limit = 0`\n   就会查询出全部的结果（相当于没有执行分页查询，但是返回结果仍然是 `Page` 类型）。\n\n9. `reasonable`：分页合理化参数，默认值为`false`。当该参数设置为 `true` 时，`pageNum<=0` 时会查询第一页，\n   `pageNum>pages`（超过总数时），会查询最后一页。默认`false` 时，直接根据参数进行查询。\n\n10. `params`：为了支持`startPage(Object params)`方法，增加了该参数来配置参数映射，用于从对象中根据属性名取值，\n    可以配置 `pageNum,pageSize,count,pageSizeZero,reasonable`，不配置映射的用默认值，\n    默认值为`pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero`。\n\n11. `supportMethodsArguments`：支持通过 Mapper 接口参数来传递分页参数，默认值`false`，分页插件会从查询方法的参数值中，自动根据上面 `params`\n    配置的字段中取值，查找到合适的值时就会自动分页。\n    使用方法可以参考测试代码中的 `com.github.pagehelper.test.basic` 包下的 `ArgumentsMapTest` 和 `ArgumentsObjTest`。\n\n12. `autoRuntimeDialect`：默认值为 `false`。设置为 `true` 时，允许在运行时根据多数据源自动识别对应方言的分页\n    （不支持自动选择`sqlserver2012`，只能使用`sqlserver`），用法和注意事项参考下面的**场景五**。\n\n13. `closeConn`：默认值为 `true`。当使用运行时动态数据源或没有设置 `helperDialect` 属性自动获取数据库类型时，会自动获取一个数据库连接，\n    通过该属性来设置是否关闭获取的这个连接，默认`true`关闭，设置为 `false` 后，不会关闭获取的连接，这个参数的设置要根据自己选择的数据源来决定。\n\n14. `aggregateFunctions`(5.1.5+)：默认为所有常见数据库的聚合函数，允许手动添加聚合函数（影响行数），所有以聚合函数开头的函数，在进行 count 转换时，会套一层。其他函数和列会被替换为 count(0)\n    ，其中count列可以自己配置。\n\n15. `replaceSql`(sqlserver): 可选值为 `regex` 和 `simple`，默认值空时采用 `regex`\n    方式，也可以自己实现 `com.github.pagehelper.dialect.ReplaceSql` 接口。\n\n16. `sqlCacheClass`(sqlserver): 针对 sqlserver 生成的 count 和 page sql 进行缓存，缓存使用的 `com.github.pagehelper.cache.CacheFactory`\n    ，可选的参数和前面的 `msCountCache` 一样。\n\n17. `autoDialectClass`：增加 `AutoDialect` 接口用于自动获取数据库类型，可以通过 `autoDialectClass`\n    配置为自己的实现类，默认使用 `DataSourceNegotiationAutoDialect`，优先根据连接池获取。\n    默认实现中，增加针对 `hikari,druid,tomcat-jdbc,c3p0,dbcp` 类型数据库连接池的特殊处理，直接从配置获取jdbcUrl，当使用其他类型数据源时，仍然使用旧的方式获取连接在读取jdbcUrl。\n    想要使用和旧版本完全相同方式时，可以配置 `autoDialectClass=old`。当数据库连接池类型非常明确时，建议配置为具体值，例如使用 hikari 时，配置 `autoDialectClass=hikari`\n    ，使用其他连接池时，配置为自己的实现类。\n\n18. `boundSqlInterceptors`：增加分页插件的 `BoundSqlInterceptor` 拦截器，可以在3个阶段对 SQL 进行处理或者简单读取，\n    增加参数 `boundSqlInterceptors`，可以配置多个实现 `BoundSqlInterceptor` 接口的实现类名，\n    使用英文逗号隔开。PageHelper调用时，也可以通过类似\n    `PageHelper.startPage(x,x).boundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor)`针对本次分页进行设置。\n\n19. `keepOrderBy`：转换count查询时保留查询的 order by 排序。除全局配置外，可以针对单次操作进行设置。\n\n20. `keepSubSelectOrderBy`：转换count查询时保留子查询的 order by 排序。可以避免给所有子查询添加 `/*keep orderby*/`，除全局配置外，可以针对单次操作进行设置。\n\n21. `sqlParser`：配置 JSqlParser 解析器，注意是 `com.github.pagehelper.JSqlParser` 接口，用于支持 sqlserver\n    等需要额外配置的情况(**6.1.0 移除该参数**)。\n\n**重要提示：**\n\n当 `offsetAsPageNum=false` 的时候，由于 `PageNum` 问题，`RowBounds`查询的时候 `reasonable` 会强制为 `false`。使用 `PageHelper.startPage`\n方法不受影响。\n\n#### 6. 如何选择配置这些参数\n\n单独看每个参数的说明可能是一件让人不爽的事情，这里列举一些可能会用到某些参数的情况。\n\n##### 场景一\n\n如果你仍然在用类似ibatis式的命名空间调用方式，你也许会用到`rowBoundsWithCount`，\n分页插件对`RowBounds`支持和 MyBatis 默认的方式是一致，默认情况下不会进行 count 查询，如果你想在分页查询时进行 count 查询，\n以及使用更强大的 `PageInfo` 类，你需要设置该参数为 `true`。\n\n**注：** `PageRowBounds` 想要查询总数也需要配置该属性为 `true`。\n\n##### 场景二\n\n如果你仍然在用类似ibatis式的命名空间调用方式，你觉得 `RowBounds` 中的两个参数 `offset,limit` 不如 `pageNum,pageSize` 容易理解，\n你可以使用 `offsetAsPageNum` 参数，将该参数设置为 `true` 后，`offset`会当成 `pageNum` 使用，`limit` 和 `pageSize` 含义相同。\n\n##### 场景三\n\n如果觉得某个地方使用分页后，你仍然想通过控制参数查询全部的结果，你可以配置 `pageSizeZero` 为 `true`，\n配置后，当 `pageSize=0` 或者 `RowBounds.limit = 0` 就会查询出全部的结果。\n\n##### 场景四\n\n如果你分页插件使用于类似分页查看列表式的数据，如新闻列表，软件列表，\n你希望用户输入的页数不在合法范围（第一页到最后一页之外）时能够正确的响应到正确的结果页面，\n那么你可以配置 `reasonable` 为 `true`，这时如果 `pageNum<=0` 会查询第一页，如果 `pageNum>总页数` 会查询最后一页。\n\n##### 场景五\n\n如果你在 Spring 中配置了动态数据源，并且连接不同类型的数据库，这时你可以配置 `autoRuntimeDialect` 为 `true`，这样在使用不同数据源时，会使用匹配的分页进行查询。\n这种情况下，你还需要特别注意 `closeConn` 参数，由于获取数据源类型会获取一个数据库连接，所以需要通过这个参数来控制获取连接后，是否关闭该连接。\n默认为 `true`，有些数据库连接关闭后就没法进行后续的数据库操作。而有些数据库连接不关闭就会很快由于连接数用完而导致数据库无响应。所以在使用该功能时，特别需要注意你使用的数据源是否需要关闭数据库连接。\n\n当不使用动态数据源而只是自动获取 `helperDialect` 时，数据库连接只会获取一次，所以不需要担心占用的这一个连接是否会导致数据库出错，但是最好也根据数据源的特性选择是否关闭连接。\n\n### 3. 如何在代码中使用\n\n阅读前请注意看[重要提示](https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/Important.md)\n\n分页插件支持以下几种调用方式：\n\n```java\n//第一种，RowBounds方式的调用\nList<User> list = sqlSession.selectList(\"x.y.selectIf\", null, new RowBounds(0, 10));\n\n//第二种，Mapper接口方式的调用，推荐这种使用方式。\nPageHelper.startPage(1, 10);\nList<User> list = userMapper.selectIf(1);\n\n//第三种，Mapper接口方式的调用，推荐这种使用方式。\nPageHelper.offsetPage(0, 10);\nList<User> list = userMapper.selectIf(1);\n\n//第四种，参数方法调用\n//存在以下 Mapper 接口方法，你不需要在 xml 处理后两个参数\npublic interface CountryMapper {\n    List<User> selectByPageNumSize(\n            @Param(\"user\") User user,\n            @Param(\"pageNum\") int pageNum,\n            @Param(\"pageSize\") int pageSize);\n}\n//配置supportMethodsArguments=true\n//在代码中直接调用：\nList<User> list = userMapper.selectByPageNumSize(user, 1, 10);\n\n//第五种，参数对象\n//如果 pageNum 和 pageSize 存在于 User 对象中，只要参数有值，也会被分页\n//有如下 User 对象\npublic class User {\n    //其他fields\n    //下面两个参数名和 params 配置的名字一致\n    private Integer pageNum;\n    private Integer pageSize;\n}\n//存在以下 Mapper 接口方法，你不需要在 xml 处理后两个参数\npublic interface CountryMapper {\n    List<User> selectByPageNumSize(User user);\n}\n//当 user 中的 pageNum!= null && pageSize!= null 时，会自动分页\nList<User> list = userMapper.selectByPageNumSize(user);\n\n//第六种，ISelect 接口方式\n//jdk6,7用法，创建接口\nPage<User> page = PageHelper.startPage(1, 10).doSelectPage(new ISelect() {\n    @Override\n    public void doSelect() {\n        userMapper.selectGroupBy();\n    }\n});\n//jdk8 lambda用法\nPage<User> page = PageHelper.startPage(1, 10).doSelectPage(()-> userMapper.selectGroupBy());\n\n//也可以直接返回PageInfo，注意doSelectPageInfo方法和doSelectPage\npageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(new ISelect() {\n    @Override\n    public void doSelect() {\n        userMapper.selectGroupBy();\n    }\n});\n//对应的lambda用法\npageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(() -> userMapper.selectGroupBy());\n\n//count查询，返回一个查询语句的count数\nlong total = PageHelper.count(new ISelect() {\n    @Override\n    public void doSelect() {\n        userMapper.selectLike(user);\n    }\n});\n//lambda\n        total=PageHelper.count(()->userMapper.selectLike(user));\n```\n\n下面对最常用的方式进行详细介绍\n\n#### 1). RowBounds方式的调用\n\n```java\nList<User> list=sqlSession.selectList(\"x.y.selectIf\",null,new RowBounds(1,10));\n```\n\n使用这种调用方式时，你可以使用RowBounds参数进行分页，这种方式侵入性最小，我们可以看到，通过RowBounds方式调用只是使用了这个参数，并没有增加其他任何内容。\n\n分页插件检测到使用了RowBounds参数时，就会对该查询进行<b>物理分页</b>。\n\n关于这种方式的调用，有两个特殊的参数是针对 `RowBounds` 的，你可以参看上面的 **场景一** 和 **场景二**\n\n<b>注：</b>不只有命名空间方式可以用RowBounds，使用接口的时候也可以增加RowBounds参数，例如：\n\n```java\n//这种情况下也会进行物理分页查询\nList<User> selectAll(RowBounds rowBounds);\n```\n\n**注意：** 由于默认情况下的 `RowBounds` 无法获取查询总数，分页插件提供了一个继承自 `RowBounds` 的 `PageRowBounds`，这个对象中增加了 `total` 属性，执行分页查询后，可以从该属性得到查询总数。\n\n\n#### 2). `PageHelper.startPage` 静态方法调用\n\n除了 `PageHelper.startPage` 方法外，还提供了类似用法的 `PageHelper.offsetPage` 方法。\n\n在你需要进行分页的 MyBatis 查询方法前调用 `PageHelper.startPage` 静态方法即可，紧跟在这个方法后的第一个**MyBatis 查询方法**会被进行分页。\n\n##### 例一：\n\n```java\n//获取第1页，10条内容，默认查询总数count\nPageHelper.startPage(1, 10);\n//紧跟着的第一个select方法会被分页\nList<User> list = userMapper.selectIf(1);\nassertEquals(2, list.get(0).getId());\nassertEquals(10, list.size());\n//分页时，实际返回的结果list类型是Page<E>，如果想取出分页信息，需要强制转换为Page<E>\nassertEquals(182, ((Page) list).getTotal());\n```\n\n##### 例二：\n```java\n//request: url?pageNum=1&pageSize=10\n//支持 ServletRequest,Map,POJO 对象，需要配合 params 参数\nPageHelper.startPage(request);\n//紧跟着的第一个select方法会被分页\nList<User> list = userMapper.selectIf(1);\n\n//后面的不会被分页，除非再次调用PageHelper.startPage\nList<User> list2 = userMapper.selectIf(null);\n//list1\nassertEquals(2, list.get(0).getId());\nassertEquals(10, list.size());\n//分页时，实际返回的结果list类型是Page<E>，如果想取出分页信息，需要强制转换为Page<E>，\n//或者使用PageInfo类（下面的例子有介绍）\nassertEquals(182, ((Page) list).getTotal());\n//list2\nassertEquals(1, list2.get(0).getId());\nassertEquals(182, list2.size());\n```\n\n##### 例三，使用`PageInfo`的用法：\n\n```java\n//获取第1页，10条内容，默认查询总数count\nPageHelper.startPage(1, 10);\nList<User> list = userMapper.selectAll();\n//用PageInfo对结果进行包装\nPageInfo page = new PageInfo(list);\n//测试PageInfo全部属性\n//PageInfo包含了非常全面的分页属性\nassertEquals(1, page.getPageNum());\nassertEquals(10, page.getPageSize());\nassertEquals(1, page.getStartRow());\nassertEquals(10, page.getEndRow());\nassertEquals(183, page.getTotal());\nassertEquals(19, page.getPages());\nassertEquals(1, page.getFirstPage());\nassertEquals(8, page.getLastPage());\nassertEquals(true, page.isFirstPage());\nassertEquals(false, page.isLastPage());\nassertEquals(false, page.isHasPreviousPage());\nassertEquals(true, page.isHasNextPage());\n```\n#### 3). 使用参数方式\n想要使用参数方式，需要配置 `supportMethodsArguments` 参数为 `true`，同时要配置 `params` 参数。\n例如下面的配置：\n```xml\n<plugins>\n    <!-- com.github.pagehelper为PageHelper类所在包名 -->\n    <plugin interceptor=\"com.github.pagehelper.PageInterceptor\">\n        <!-- 使用下面的方式配置参数，后面会有所有的参数介绍 -->\n        <property name=\"supportMethodsArguments\" value=\"true\"/>\n        <property name=\"params\" value=\"pageNum=pageNumKey;pageSize=pageSizeKey;\"/>\n\t</plugin>\n</plugins>\n```\n在 MyBatis 方法中：\n```java\nList<User> selectByPageNumSize(\n@Param(\"user\") User user,\n@Param(\"pageNumKey\") int pageNum,\n@Param(\"pageSizeKey\") int pageSize);\n```\n当调用这个方法时，由于同时发现了 `pageNumKey` 和 `pageSizeKey` 参数，这个方法就会被分页。params 提供的几个参数都可以这样使用。\n\n除了上面这种方式外，如果 User 对象中包含这两个参数值，也可以有下面的方法：\n```java\nList<User> selectByPageNumSize(User user);\n```\n当从 User 中同时发现了 `pageNumKey` 和 `pageSizeKey` 参数，这个方法就会被分页。\n\n注意：`pageNum` 和 `pageSize` 两个属性同时存在才会触发分页操作，在这个前提下，其他的分页参数才会生效。\n\n\n#### 3). `PageHelper` 安全调用\n\n##### 1. 使用 `RowBounds` 和 `PageRowBounds` 参数方式是极其安全的\n\n##### 2. 使用参数方式是极其安全的\n\n##### 3. 使用 ISelect 接口调用是极其安全的\n\nISelect 接口方式除了可以保证安全外，还特别实现了将查询转换为单纯的 count 查询方式，这个方法可以将任意的查询方法，变成一个 `select count(*)` 的查询方法。\n\n##### 4. 什么时候会导致不安全的分页？\n\n`PageHelper` 方法使用了静态的 `ThreadLocal` 参数，分页参数和线程是绑定的。\n\n只要你可以保证在 `PageHelper` 方法调用后紧跟 MyBatis 查询方法，这就是安全的。因为 `PageHelper` 在 `finally` 代码段中自动清除了 `ThreadLocal` 存储的对象。\n\n如果代码在进入 `Executor` 前发生异常，就会导致线程不可用，这属于人为的 Bug（例如接口方法和 XML 中的不匹配，导致找不到 `MappedStatement` 时），\n这种情况由于线程不可用，也不会导致 `ThreadLocal` 参数被错误的使用。\n\n但是如果你写出下面这样的代码，就是不安全的用法：\n```java\nPageHelper.startPage(1, 10);\nList<User> list;\nif(param1 != null){\n    list = userMapper.selectIf(param1);\n} else {\n    list = new ArrayList<User>();\n}\n```\n这种情况下由于 param1 存在 null 的情况，就会导致 PageHelper 生产了一个分页参数，但是没有被消费，这个参数就会一直保留在这个线程上。当这个线程再次被使用时，就可能导致不该分页的方法去消费这个分页参数，这就产生了莫名其妙的分页。\n\n上面这个代码，应该写成下面这个样子：\n```java\nList<User> list;\nif(param1 != null){\n    PageHelper.startPage(1, 10);\n    list = userMapper.selectIf(param1);\n} else {\n    list = new ArrayList<User>();\n}\n```\n这种写法就能保证安全。\n\n如果你对此不放心，你可以手动清理 `ThreadLocal` 存储的分页参数，可以像下面这样使用：\n```java\nList<User> list;\nif(param1 != null){\n    PageHelper.startPage(1, 10);\n    try{\n        list = userMapper.selectAll();\n    } finally {\n        PageHelper.clearPage();\n    }\n} else {\n    list = new ArrayList<User>();\n}\n```\n这么写很不好看，而且没有必要。\n\n### 4. MyBatis 和 Spring 集成示例\n\n如果和Spring集成不熟悉，可以参考下面两个\n\n<b>只有基础的配置信息，没有任何现成的功能，作为新手入门搭建框架的基础</b>\n\n- [集成 Spring 3.x](https://github.com/abel533/Mybatis-Spring/tree/spring3.x)\n- [集成 Spring 4.x](https://github.com/abel533/Mybatis-Spring)\n\n这两个集成框架集成了 PageHelper 和 [通用 Mapper](https://github.com/abel533/Mapper)。\n\n### 5. Spring Boot 集成示例\n\n- [pagehelper-spring-boot-samples](https://github.com/pagehelper/pagehelper-spring-boot/tree/master/pagehelper-spring-boot-samples)\n- https://github.com/abel533/MyBatis-Spring-Boot\n"
  },
  {
    "path": "wikis/zh/Important.md",
    "content": "## 重要提示  \n\n### `PageHelper.startPage`方法重要提示\n\n只有紧跟在`PageHelper.startPage`方法后的<b>第一个</b>Mybatis的<b>查询（Select）</b>方法会被分页。\n\n### 请不要配置多个分页插件\n\n请不要在系统中配置多个分页插件(使用Spring时,`mybatis-config.xml`和`Spring<bean>`配置方式，请选择其中一种，不要同时配置多个分页插件)！\n\n### 分页插件不支持带有`for update`语句的分页\n\n对于带有`for update`的sql，会抛出运行时异常，对于这样的sql建议手动分页，毕竟这样的sql需要重视。\n\n### 分页插件不支持嵌套结果映射\n\n由于嵌套结果方式会导致结果集被折叠，因此分页查询的结果在折叠后总数会减少，所以无法保证分页结果数量正确。"
  },
  {
    "path": "wikis/zh/Interceptor.md",
    "content": "## Executor 拦截器高级教程 - QueryInterceptor 规范\n这篇文档涉及下面几个方面\n1. Executor query 方法介绍\n2. 拦截器配置和调用顺序\n3. 拦截 query 方法的技巧\n4. 拦截 query 方法的规范\n5. 如何配置不同的 Executor 插件\n\n### 1. Executor query 方法介绍\n在 MyBatis 的拦截器的文档部分，我们知道 Executor 中的 query 方法可以被拦截，如果你真正写过这个方法的拦截器，\n你可能会知道在 Executor 中的 query 方法有两个：\n```java\n<E> List<E> query(\n      MappedStatement ms, \n      Object parameter, \n      RowBounds rowBounds, \n      ResultHandler resultHandler, \n      CacheKey cacheKey, \n      BoundSql boundSql) throws SQLException;\n\n<E> List<E> query(\n      MappedStatement ms, \n      Object parameter, \n      RowBounds rowBounds, \n      ResultHandler resultHandler) throws SQLException;\n```\n这两个方法的区别是第一个方法多两个参数 CacheKey 和 BoundSql，在多数情况下，我们用拦截器的目的就是针对 SQL\n做处理，如果能够拦截第一个方法，可以直接得到 BoundSql 对象，就会很容易的得到执行的 SQL，也可以对 SQL\n做处理。\n\n虽然想的很好，但是 MyBatis 提供的 Exctutor 实现中，参数多的这个 query\n方法都是被少的这个 query 方法在内部进行调用的。\n\n在 `CachingExecutor` 中：\n```java\npublic <E> List<E> query(\n        MappedStatement ms, \n        Object parameter, \n        RowBounds rowBounds, \n        ResultHandler resultHandler) throws SQLException {\n    BoundSql boundSql = ms.getBoundSql(parameterObject);\n    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);\n    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);\n}\n```\n在 `BaseExecutor` 中：\n```java\npublic <E> List<E> query(\n        MappedStatement ms, \n        Object parameter, \n        RowBounds rowBounds, \n        ResultHandler resultHandler) throws SQLException {\n    BoundSql boundSql = ms.getBoundSql(parameter);\n    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);\n    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);\n}\n```\n上面这两个方法一样。由于第一个 query 方法在这里是内部调用，并且我们所有的拦截器都是层层代理的 `CachingExecutor` 或基于 `BaseExecutor` 的实现类，所以我们能拦截的就是参数少的这个方法。\n\n分页插件开始从 Executor 拦截开始就一直是拦截的参数少的这个方法。但是从 5.0 版本开始，query 的这两个方法都可以被拦截了。在讲这个**原理**之前，我们先了解一下拦截器的执行顺序。\n\n### 2. 拦截器配置和调用顺序\n拦截器的调用顺序分为两大种，第一种是拦截的不同对象，例如拦截 Executor 和 拦截 StatementHandler 就属于不同的拦截对象，\n这两类的拦截器在整体执行的逻辑上是不同的，在 Executor 中的 query 方法执行过程中，会调用下面的代码：\n```java\npublic <E> List<E> doQuery(\n        MappedStatement ms, \n        Object parameter, \n        RowBounds rowBounds, \n        ResultHandler resultHandler, \n        BoundSql boundSql) throws SQLException {\n    Statement stmt = null;\n    try {\n          Configuration configuration = ms.getConfiguration();\n          StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);\n          stmt = prepareStatement(handler, ms.getStatementLog());\n          return handler.<E>query(stmt, resultHandler);\n    } finally {\n        closeStatement(stmt);\n    }\n}\n```\n在这段代码中，才会轮到 StatementHandler 去执行，StatementHandler 属于 Executor 执行过程中的一个子过程。\n所以这两种不同类别的插件在配置时，一定是先执行 Executor 的拦截器，然后才会轮到 StatementHandler。所以这种情况下配置拦截器的顺序就不重要了，在 MyBatis 逻辑上就已经控制了先后顺序。\n\n第二种拦截器的顺序就是指拦截同一种对象的同一个方法，例如都拦截 Executor 的 query 方法，这时你配置拦截器的顺序就会对这里有影响了。假设有如下几个拦截器，都是拦截的 Executor 的 query 方法。\n```\n<plugins>\n    <plugin interceptor=\"com.github.pagehelper.ExecutorQueryInterceptor1\"/>\n    <plugin interceptor=\"com.github.pagehelper.ExecutorQueryInterceptor2\"/>\n    <plugin interceptor=\"com.github.pagehelper.ExecutorQueryInterceptor3\"/>\n</plugins>\n```\n在`org.apache.ibatis.session.Configuration` 中有如下方法：\n```java\npublic void addInterceptor(Interceptor interceptor) {\n    interceptorChain.addInterceptor(interceptor);\n}\n```\nMyBatis 会按照拦截器配置的顺序依次添加到 interceptorChain 中，其内部就是 `List<Interceptor> interceptors`。再看 `Configuration` 中创建 Executor 的代码：\n```java\npublic Executor newExecutor(Transaction transaction, ExecutorType executorType) {\n    executorType = executorType == null ? defaultExecutorType : executorType;\n    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;\n    Executor executor;\n    if (ExecutorType.BATCH == executorType) {\n        executor = new BatchExecutor(this, transaction);\n    } else if (ExecutorType.REUSE == executorType) {\n        executor = new ReuseExecutor(this, transaction);\n    } else {\n        executor = new SimpleExecutor(this, transaction);\n    }\n    if (cacheEnabled) {\n        executor = new CachingExecutor(executor);\n    }\n    executor = (Executor) interceptorChain.pluginAll(executor);\n    return executor;\n}\n```\n在调用 interceptorChain.pluginAll 之前，executor 就是前一节中的 `CachingExecutor` 或基于 `BaseExecutor` 的实现类。\n然后看 interceptorChain.pluginAll 方法：\n```java\npublic Object pluginAll(Object target) {\n    for (Interceptor interceptor : interceptors) {\n        target = interceptor.plugin(target);\n    }\n    return target;\n}\n```\n前面我们配置拦截器的顺序是1，2，3。在这里也会按照 1，2，3 的顺序被层层代理，代理后的结构如下：\n```json\nInterceptor3:{\n    Interceptor2: {\n        Interceptor1: {\n            target: Executor\n        }\n    }\n}\n```\n从这个结构应该就很容易能看出来，将来执行的时候肯定是按照 3>2>1>Executor>1>2>3 的顺序去执行的。\n可能有些人不知道为什么3>2>1>Executor之后会有1>2>3，这是因为使用代理时，调用完代理方法后，还能继续进行其他处理。处理结束后，将代理方法的返回值继续往外返回即可。例如：\n```    \nInterceptor3 前置处理      \nObject result = Interceptor2..query(4个参数方法);     \nInterceptor3 后续处理   \nreturn result;\n```\n对于 Interceptor2.query 方法也是相同的逻辑：\n```\nInterceptor2 前置处理      \nObject result = Interceptor1..query(4个参数方法);     \nInterceptor2 后续处理   \nreturn result;\n```\n同理 Interceptor1.query ：\n```\nInterceptor1 前置处理      \nObject result = executor.query(4个参数方法);     \nInterceptor1 后续处理   \nreturn result;\n```\n叠加到一起后，如下：\n```\nInterceptor3 前置处理\nInterceptor2 前置处理\nInterceptor1 前置处理  \nObject result = executor.query(4个参数方法);     \nInterceptor1 后续处理   \nInterceptor2 后续处理  \nInterceptor3 后续处理   \nreturn result;\n```\n所以这个顺序就是 3>2>1>Executor>1>2>3。\n\n在你弄清楚这个逻辑后，再继续往下看，因为后面的技巧会颠覆这个逻辑，所以才会有后面的规范以及如何配置不同的插件。\n\n### 3. 拦截 query 方法的技巧\n上一节的内容中，对拦截器的用法是最常见的一种用法，所以才会出现这种都能理解的执行顺序。但是分页插件 5.0 不是这样，这个插件颠覆了这种顺序，这种颠覆其实也很普通，这也是本节要说的技巧。\n\n在我写作 MyBatis 技术书籍的过程中（还没写完，已经因为分页插件占用了几周的写作时间），我就在考虑为什么不能拦截第一个 query（6个参数的）方法，\n如果能拦截这个方法，就可以直接拿到 BoundSql，然后处理 SQL 就很容易实现其他的操作。\n\n在第 1 节介绍为什么第一个 query 方法不能被拦截时，是因为下面这段代码：\n```java\npublic <E> List<E> query(\n        MappedStatement ms, \n        Object parameter, \n        RowBounds rowBounds, \n        ResultHandler resultHandler) throws SQLException {\n    BoundSql boundSql = ms.getBoundSql(parameter);\n    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);\n    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);\n}\n```\n既然 `CachingExecutor` 或基于 `BaseExecutor` 的实现类只是这么简单的调用两个方法得到了 BoundSql 和 Cachekey，我们为什么不直接替代他们呢？\n\n所以我们可以有类似下面的拦截器用法：\n```java\n@Intercepts(@Signature(type = Executor.class, method = \"query\", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))\npublic class QueryInterceptor implements Interceptor {\n\n    @Override\n    public Object intercept(Invocation invocation) throws Throwable {\n        Object[] args = invocation.getArgs();\n        MappedStatement ms = (MappedStatement) args[0];\n        Object parameterObject = args[1];\n        RowBounds rowBounds = (RowBounds) args[2];\n        ResultHandler resultHandler = (ResultHandler) args[3];\n        Executor executor = (Executor) invocation.getTarget();\n        BoundSql boundSql = ms.getBoundSql(parameterObject);\n        //可以对参数做各种处理\n        CacheKey cacheKey = executor.createCacheKey(ms, parameterObject, rowBounds, boundSql);\n        return executor.query(ms, parameterObject, rowBounds, resultHandler, cacheKey, boundSql);\n    }\n\n    @Override\n    public Object plugin(Object target) {\n        return Plugin.wrap(target, this);\n    }\n\n    @Override\n    public void setProperties(Properties properties) {\n    }\n\n}\n```\n这个拦截器直接替代了原有 Executor 的部分逻辑，直接去调用了 6 个参数的方法，因而导致 4 个参数的后续方法被跳过了。但是由于这里的 executor 是代理对象\n所以 6 个参数的 query 方法可以被代理了，这就扰乱了上一节中的执行顺序。\n\n在上一节拦截器的例子中，做简单修改，将 ExecutorQueryInterceptor2 换成上面的 QueryInterceptor，配置如下：\n```\n<plugins>\n    <plugin interceptor=\"com.github.pagehelper.ExecutorQueryInterceptor1\"/>\n    <plugin interceptor=\"com.github.pagehelper.QueryInterceptor\"/>\n    <plugin interceptor=\"com.github.pagehelper.ExecutorQueryInterceptor3\"/>\n</plugins>\n```\n代理后的结构如下：\n```json\nInterceptor3:{\n    QueryInterceptor: {\n        Interceptor1: {\n            target: Executor\n        }\n    }\n}\n```\n这时，调用顺序就变了，Interceptor3 执行顺序如下：\n```    \nInterceptor3 前置处理      \nObject result = QueryInterceptor.query(4个参数方法);     \nInterceptor3 后续处理   \nreturn result;\n```\nQueryInterceptor.query 执行逻辑如下：\n```\nInterceptor2 前置处理      \nObject result = executor.query(6个参数方法);     \nInterceptor2 后续处理   \nreturn result;\n```\n在 QueryInterceptor 中，没有继续执行 4个参数方法，而是执行了 6 个参数方法。\n但是 Interceptor1 拦截的 4 个参数的方法，所以 Interceptor1 就被跳过去了，整体的执行逻辑就变成下面这样了：\n```\nInterceptor3 前置处理\nInterceptor2 前置处理\nObject result = executor.query(6个参数方法);     \nInterceptor2 后续处理  \nInterceptor3 后续处理   \nreturn result;\n```\n如果 Interceptor1 拦截的是 6 个参数的方法，因为 QueryInterceptor 获取的是 Interceptor1 代理的 executor 对象，那么 Interceptor1 就会被 QueryInterceptor 继续执行下去。\n\n分页插件就是类似 QueryInterceptor 的执行逻辑，所以当你使用 5.0 版本之后的插件时，如果你还需要配置其他 Executor 的 query 插件，你就会遇到一些问题（可以解决，继续往下看）。\n\n如果你是自己开发的插件，那么你按照下一节的规范去开发也不会遇到问题。如果你使用的其他人提供的插件，按照第 5 节的配置顺序也能解决问题。\n\n### 4. 拦截 query 方法的规范\n\nQueryInterceptor 的逻辑就是进去的是 4 个参数的方法，出去的是 6 个参数的方法。这种处理方法不仅仅不方便和一般的 Excutor 拦截器搭配使用，\n当出现两个以上类似 QueryInterceptor 的插件时，由于接口变了，类似 QueryInterceptor 插件也无法连贯的执行下去。\n因而有必要解决这个问题。解决的办法就是使用统一的规范。经过规范后 QueryInterceptor 如下：\n```java\n@Intercepts(\n    {\n        @Signature(type = Executor.class, method = \"query\", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),\n        @Signature(type = Executor.class, method = \"query\", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),\n    }\n)\npublic class QueryInterceptor implements Interceptor {\n\n    @Override\n    public Object intercept(Invocation invocation) throws Throwable {\n        Object[] args = invocation.getArgs();\n        MappedStatement ms = (MappedStatement) args[0];\n        Object parameter = args[1];\n        RowBounds rowBounds = (RowBounds) args[2];\n        ResultHandler resultHandler = (ResultHandler) args[3];\n        Executor executor = (Executor) invocation.getTarget();\n        CacheKey cacheKey;\n        BoundSql boundSql;\n        //由于逻辑关系，只会进入一次\n        if(args.length == 4){\n            //4 个参数时\n            boundSql = ms.getBoundSql(parameter);\n            cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);\n        } else {\n            //6 个参数时\n            cacheKey = (CacheKey) args[4];\n            boundSql = (BoundSql) args[5];\n        }\n        //TODO 自己要进行的各种处理\n        //注：下面的方法可以根据自己的逻辑调用多次，在分页插件中，count 和 page 各调用了一次\n        return executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);\n    }\n\n    @Override\n    public Object plugin(Object target) {\n        return Plugin.wrap(target, this);\n    }\n\n    @Override\n    public void setProperties(Properties properties) {\n    }\n\n}\n```\n注意两个变化，第一个就是拦截器签名同时拦截了 4 个 和 6 个参数的方法，这样不管那个插件在前在后都会被执行。\n\n第二个变化就是这段代码：\n```java\nCacheKey cacheKey;\nBoundSql boundSql;\n//由于逻辑关系，只会进入一次\nif(args.length == 4){\n    //4 个参数时\n    boundSql = ms.getBoundSql(parameterObject);\n    cacheKey = executor.createCacheKey(ms, parameterObject, rowBounds, boundSql);\n} else {\n    //6 个参数时\n    cacheKey = (CacheKey) args[4];\n    boundSql = (BoundSql) args[5];\n}\n```\n如果这个插件配置的靠后，是通过 4 个参数方法进来的，我们就获取这两个对象。如果这个插件配置的靠前，已经被别的拦截器处理成 6 个参数的方法了，\n那么我们直接从 args 中取出这两个参数直接使用即可。取出这两个参数就保证了当其他拦截器对这两个参数做过处理时，这两个参数在这里会继续生效。\n\n假设有个排序插件和分页插件，排序插件将 BoundSql 修改为带排序的 SQL 后，SQL 会继续交给分页插件使用。分页插件的分页 SQL 执行时，会保留排序去执行，\n这样的规范就保证了两个插件都能正常的执行下去。\n\n所以如果大家想要使用这种方式去实现拦截器，建议大家遵守这个规范。\n\n这个规范对于已经存在的插件来说就没法控制了，但是仍然可以通过配置顺序来解决。\n\n### 5. 如何配置不同的 Executor 插件\n\n当引入类似 QueryInterceptor 插件时，由于扰乱了原有的插件执行方式，当配置 Executor 顺序不对时会导致插件无法生效。\n\n第 4 节中的例子：\n```\n<plugins>\n    <plugin interceptor=\"com.github.pagehelper.ExecutorQueryInterceptor1\"/>\n    <plugin interceptor=\"com.github.pagehelper.QueryInterceptor\"/>\n    <plugin interceptor=\"com.github.pagehelper.ExecutorQueryInterceptor3\"/>\n</plugins>\n```\n首先执行顺序为  3>Query>1>Executor，由于 Query 是 4 或 6 个参数进来，6 个参数出去。\n所以在 Query 前面执行的拦截器必须是 4 个的（Query 规范拦截器先后都能执行，需要根据逻辑配置先后）参数的，在 Query 后面执行的拦截器必须是 6 个参数的。\n\n这个顺序对应到配置顺序时，也就是 4 个参数的配置在 QueryInterceptor 拦截器的下面，6 个参数的配置在 QueryInterceptor 拦截器的上面。\n按照这个顺序进行配置时，就能保证拦截器都执行。\n\n如果你想获得如分页插件（QueryInterceptor 规范）执行的 SQL，你就得按照 QueryInterceptor 规范去实现，否则只能配置在分页插件的下面，也就只能获得分页处理前的 SQL。"
  },
  {
    "path": "wikis/zh/Test.md",
    "content": "## 项目测试   \n\n为了保证分页插件的稳定性，项目中包含大量的单元测试，并且可以针对支持的数据库进行测试。\n\n### 分页插件多数据库测试  \n\n为了更方便的测试不同的数据库，在`src/test/resources`目录下增加了不同数据库的mybatis配置文件，通过修改`test.properties`中的配置可以让测试使用不同的配置进行测试。  \n\n`test.properties`内容：  \n\n```properties\n#首先需要在本机配置对应的数据库\n\n#想要测试那个数据库，这里就写那个数据库\n#这个值和test/resources中的数据库对应的文件夹名字相同\n#目前可选为:\n#hsqldb\n#mysql\n#mariadb - 注意测试中的端口是3309(因为默认和mysql是一样的)\n#oracle\n#postgresql\n#sqlserver\n#db2\n#h2\n#derby\ndatabase = hsqldb\n```  \n各种数据库对应的sql文件都在对应的目录中。"
  }
]