Browse Source

jfinal 2.2 release ^_^

James 10 years ago
parent
commit
fa95dd9394

+ 19 - 18
src/com/jfinal/plugin/activerecord/Db.java

@@ -335,31 +335,32 @@ public class Db {
 		return dbPro.delete(tableName, record);
 	}
 	
-	static Page<Record> paginate(Config config, Connection conn, int pageNumber, int pageSize, String sql, Object... paras) throws SQLException {
-		return dbPro.paginate(config, conn, pageNumber, pageSize, sql, paras);
+	static Page<Record> paginate(Config config, Connection conn, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) throws SQLException {
+		return dbPro.paginate(config, conn, pageNumber, pageSize, select, sqlExceptSelect, paras);
 	}
 	
 	/**
 	 * Paginate.
 	 * @param pageNumber the page number
 	 * @param pageSize the page size
-	 * @param sql the sql statement 
+	 * @param select the select part of the sql statement
+	 * @param sqlExceptSelect the sql statement excluded select part
 	 * @param paras the parameters of sql
 	 * @return the Page object
 	 */
-	public static Page<Record> paginate(int pageNumber, int pageSize, String sql, Object... paras) {
-		return dbPro.paginate(pageNumber, pageSize, sql, paras);
+	public static Page<Record> paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {
+		return dbPro.paginate(pageNumber, pageSize, select, sqlExceptSelect, paras);
 	}
 	
-	public static Page<Record> paginate(int pageNumber, int pageSize, String[] selectAndSqlExceptSelect, Object... paras) {
-		return dbPro.paginate(pageNumber, pageSize, selectAndSqlExceptSelect, paras);
+	public static Page<Record> paginate(int pageNumber, int pageSize, boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {
+		return dbPro.paginate(pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);
 	}
 	
 	/**
-	 * @see #paginate(String, int, int, String, Object...)
+	 * @see #paginate(String, int, int, String, String, Object...)
 	 */
-	public static Page<Record> paginate(int pageNumber, int pageSize, String sql) {
-		return dbPro.paginate(pageNumber, pageSize, sql);
+	public static Page<Record> paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect) {
+		return dbPro.paginate(pageNumber, pageSize, select, sqlExceptSelect);
 	}
 	
 	static boolean save(Config config, Connection conn, String tableName, String primaryKey, Record record) throws SQLException {
@@ -499,22 +500,22 @@ public class Db {
 	
 	/**
 	 * Paginate by cache.
-	 * @see #paginate(int, int, String, Object...)
+	 * @see #paginate(int, int, String, String, Object...)
 	 * @return Page
 	 */
-	public static Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String sql, Object... paras) {
-		return dbPro.paginateByCache(cacheName, key, pageNumber, pageSize, sql, paras);
+	public static Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {
+		return dbPro.paginateByCache(cacheName, key, pageNumber, pageSize, select, sqlExceptSelect, paras);
 	}
 	
-	public static Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String[] selectAndSqlExceptSelect, Object... paras) {
-		return dbPro.paginateByCache(cacheName, key, pageNumber, pageSize, selectAndSqlExceptSelect, paras);
+	public static Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {
+		return dbPro.paginateByCache(cacheName, key, pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);
 	}
 	
 	/**
-	 * @see #paginateByCache(String, Object, int, int, String, Object...)
+	 * @see #paginateByCache(String, Object, int, int, String, String, Object...)
 	 */
-	public static Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String sql) {
-		return dbPro.paginateByCache(cacheName, key, pageNumber, pageSize, sql);
+	public static Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String select, String sqlExceptSelect) {
+		return dbPro.paginateByCache(cacheName, key, pageNumber, pageSize, select, sqlExceptSelect);
 	}
 	
 	/**

+ 33 - 32
src/com/jfinal/plugin/activerecord/DbPro.java

@@ -452,28 +452,30 @@ public class DbPro {
 		return deleteById(tableName, defaultPrimaryKey, record.get(defaultPrimaryKey));
 	}
 	
-	Page<Record> paginate(Config config, Connection conn, int pageNumber, int pageSize, String sql, Object... paras) throws SQLException {
-		Object[] actualSqlParas = new Object[2];
-		String totalRowSql = config.dialect.forTotalRow(actualSqlParas, sql, paras);
-		sql = (String)actualSqlParas[0];
-		paras = (Object[])actualSqlParas[1];
-		return doPaginate(config, conn, pageNumber, pageSize, totalRowSql, sql, paras);
+	Page<Record> paginate(Config config, Connection conn, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) throws SQLException {
+		return doPaginate(config, conn, pageNumber, pageSize, null, select, sqlExceptSelect, paras);
 	}
 	
-	Page<Record> doPaginate(Config config, Connection conn, int pageNumber, int pageSize, String totalRowSql, String sql, Object... paras) throws SQLException {
+	Page<Record> doPaginate(Config config, Connection conn, int pageNumber, int pageSize, Boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) throws SQLException {
 		if (pageNumber < 1 || pageSize < 1) {
-			throw new ActiveRecordException("pageNumber and pageSize must be more than 0");
+			throw new ActiveRecordException("pageNumber and pageSize must more than 0");
 		}
 		if (config.dialect.isTakeOverDbPaginate()) {
-			return config.dialect.takeOverDbPaginate(conn, pageNumber, pageSize, totalRowSql, sql, paras);
+			return config.dialect.takeOverDbPaginate(conn, pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);
 		}
 		
-		long totalRow;
+		String totalRowSql = "select count(*) " + config.dialect.replaceOrderBy(sqlExceptSelect);
 		List result = query(config, conn, totalRowSql, paras);
-		if (config.dialect.isGroupBySql(sql)) {
-			totalRow = result.size();
+		int size = result.size();
+		if (isGroupBySql == null) {
+			isGroupBySql = size > 1;
+		}
+		
+		long totalRow;
+		if (isGroupBySql) {
+			totalRow = size;
 		} else {
-			totalRow = (result.size() > 0) ? ((Number)result.get(0)).longValue() : 0;
+			totalRow = (size > 0) ? ((Number)result.get(0)).longValue() : 0;
 		}
 		if (totalRow == 0) {
 			return new Page<Record>(new ArrayList<Record>(0), pageNumber, pageSize, 0, 0);
@@ -489,7 +491,7 @@ public class DbPro {
 		}
 		
 		// --------
-		sql = config.dialect.forPaginate(pageNumber, pageSize, sql);
+		String sql = config.dialect.forPaginate(pageNumber, pageSize, select, sqlExceptSelect);
 		List<Record> list = find(config, conn, sql, paras);
 		return new Page<Record>(list, pageNumber, pageSize, totalPage, (int)totalRow);
 	}
@@ -498,15 +500,16 @@ public class DbPro {
 	 * Paginate.
 	 * @param pageNumber the page number
 	 * @param pageSize the page size
-	 * @param sql the sql statement 
+	 * @param select the select part of the sql statement
+	 * @param sqlExceptSelect the sql statement excluded select part
 	 * @param paras the parameters of sql
 	 * @return the Page object
 	 */
-	public Page<Record> paginate(int pageNumber, int pageSize, String sql, Object... paras) {
+	public Page<Record> paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {
 		Connection conn = null;
 		try {
 			conn = config.getConnection();
-			return paginate(config, conn, pageNumber, pageSize, sql, paras);
+			return paginate(config, conn, pageNumber, pageSize, select, sqlExceptSelect, paras);
 		} catch (Exception e) {
 			throw new ActiveRecordException(e);
 		} finally {
@@ -514,13 +517,11 @@ public class DbPro {
 		}
 	}
 	
-	public Page<Record> paginate(int pageNumber, int pageSize, String[] selectAndSqlExceptSelect, Object... paras) {
+	public Page<Record> paginate(int pageNumber, int pageSize, boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {
 		Connection conn = null;
 		try {
-			String totalRowSql = "select count(*) " + config.dialect.replaceOrderBy(selectAndSqlExceptSelect[1]);
-			String sql = selectAndSqlExceptSelect[0] + " " + selectAndSqlExceptSelect[1];
 			conn = config.getConnection();
-			return doPaginate(config, conn, pageNumber, pageSize, totalRowSql, sql, paras);
+			return doPaginate(config, conn, pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);
 		} catch (Exception e) {
 			throw new ActiveRecordException(e);
 		} finally {
@@ -529,10 +530,10 @@ public class DbPro {
 	}
 	
 	/**
-	 * @see #paginate(String, int, int, String, Object...)
+	 * @see #paginate(String, int, int, String, String, Object...)
 	 */
-	public Page<Record> paginate(int pageNumber, int pageSize, String sql) {
-		return paginate(pageNumber, pageSize, sql, NULL_PARA_ARRAY);
+	public Page<Record> paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect) {
+		return paginate(pageNumber, pageSize, select, sqlExceptSelect, NULL_PARA_ARRAY);
 	}
 	
 	boolean save(Config config, Connection conn, String tableName, String primaryKey, Record record) throws SQLException {
@@ -799,34 +800,34 @@ public class DbPro {
 	
 	/**
 	 * Paginate by cache.
-	 * @see #paginate(int, int, String, Object...)
+	 * @see #paginate(int, int, String, String, Object...)
 	 * @return Page
 	 */
-	public Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String sql, Object... paras) {
+	public Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {
 		ICache cache = config.getCache();
 		Page<Record> result = cache.get(cacheName, key);
 		if (result == null) {
-			result = paginate(pageNumber, pageSize, sql, paras);
+			result = paginate(pageNumber, pageSize, select, sqlExceptSelect, paras);
 			cache.put(cacheName, key, result);
 		}
 		return result;
 	}
 	
-	public Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String[] selectAndSqlExceptSelect, Object... paras) {
+	public Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {
 		ICache cache = config.getCache();
 		Page<Record> result = cache.get(cacheName, key);
 		if (result == null) {
-			result = paginate(pageNumber, pageSize, selectAndSqlExceptSelect, paras);
+			result = paginate(pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);
 			cache.put(cacheName, key, result);
 		}
 		return result;
 	}
 	
 	/**
-	 * @see #paginateByCache(String, Object, int, int, String, Object...)
+	 * @see #paginateByCache(String, Object, int, int, String, String, Object...)
 	 */
-	public Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String sql) {
-		return paginateByCache(cacheName, key, pageNumber, pageSize, sql, NULL_PARA_ARRAY);
+	public Page<Record> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String select, String sqlExceptSelect) {
+		return paginateByCache(cacheName, key, pageNumber, pageSize, select, sqlExceptSelect, NULL_PARA_ARRAY);
 	}
 	
 	private int[] batch(Config config, Connection conn, String sql, Object[][] paras, int batchSize) throws SQLException {

+ 35 - 35
src/com/jfinal/plugin/activerecord/Model.java

@@ -275,16 +275,17 @@ public abstract class Model<M extends Model> implements Serializable {
 	 * Paginate.
 	 * @param pageNumber the page number
 	 * @param pageSize the page size
-	 * @param sql the sql statement 
+	 * @param select the select part of the sql statement
+	 * @param sqlExceptSelect the sql statement excluded select part
 	 * @param paras the parameters of sql
 	 * @return the Page object
 	 */
-	public Page<M> paginate(int pageNumber, int pageSize, String sql, Object... paras) {
+	public Page<M> paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {
 		Config config = getConfig();
 		Connection conn = null;
 		try {
 			conn = config.getConnection();
-			return paginate(config, conn, pageNumber, pageSize, sql, paras);
+			return paginate(config, conn, pageNumber, pageSize, select, sqlExceptSelect, paras);
 		} catch (Exception e) {
 			throw new ActiveRecordException(e);
 		} finally {
@@ -293,21 +294,18 @@ public abstract class Model<M extends Model> implements Serializable {
 	}
 	
 	/**
-	 * 支持 select 中带有嵌套 select 语句的 sql,避免正则解析拖慢性能
-	 * 将 sql 分成 select 部分与 非 select 部分来写,并传入 selectAndSqlExceptSelect 数组中
+	 * 指定分页 sql 最外层以是否含有 group by 语句
 	 * <pre>
 	 * 举例:
-	 * paginate(1, 10, new String[]{"select *", "from user where id>?"} , 123);
+	 * paginate(1, 10, true, "select *", "from user where id>? group by age", 123);
 	 * </pre>
 	 */
-	public Page<M> paginate(int pageNumber, int pageSize, String[] selectAndSqlExceptSelect, Object... paras) {
+	public Page<M> paginate(int pageNumber, int pageSize, boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {
 		Config config = getConfig();
 		Connection conn = null;
 		try {
-			String totalRowSql = "select count(*) " + config.dialect.replaceOrderBy(selectAndSqlExceptSelect[1]);
-			String sql = selectAndSqlExceptSelect[0] + " " + selectAndSqlExceptSelect[1];
 			conn = config.getConnection();
-			return doPaginate(config, conn, pageNumber, pageSize, totalRowSql, sql, paras);
+			return doPaginate(config, conn, pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);
 		} catch (Exception e) {
 			throw new ActiveRecordException(e);
 		} finally {
@@ -315,28 +313,30 @@ public abstract class Model<M extends Model> implements Serializable {
 		}
 	}
 	
-	private Page<M> paginate(Config config, Connection conn, int pageNumber, int pageSize, String sql, Object... paras) throws Exception {
-		Object[] actualSqlParas = new Object[2];
-		String totalRowSql = config.dialect.forTotalRow(actualSqlParas, sql, paras);
-		sql = (String)actualSqlParas[0];
-		paras = (Object[])actualSqlParas[1];
-		return doPaginate(config, conn, pageNumber, pageSize, totalRowSql, sql, paras);
+	private Page<M> paginate(Config config, Connection conn, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) throws Exception {
+		return doPaginate(config, conn, pageNumber, pageSize, null, select, sqlExceptSelect, paras);
 	}
 	
-	private Page<M> doPaginate(Config config, Connection conn, int pageNumber, int pageSize, String totalRowSql, String sql, Object... paras) throws Exception {
+	private Page<M> doPaginate(Config config, Connection conn, int pageNumber, int pageSize, Boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) throws Exception {
 		if (pageNumber < 1 || pageSize < 1) {
-			throw new ActiveRecordException("pageNumber and pageSize must be more than 0");
+			throw new ActiveRecordException("pageNumber and pageSize must more than 0");
 		}
 		if (config.dialect.isTakeOverModelPaginate()) {
-			return config.dialect.takeOverModelPaginate(conn, getUsefulClass(), pageNumber, pageSize, totalRowSql, sql, paras);
+			return config.dialect.takeOverModelPaginate(conn, getUsefulClass(), pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);
 		}
 		
-		long totalRow;
+		String totalRowSql = "select count(*) " + config.dialect.replaceOrderBy(sqlExceptSelect);
 		List result = Db.query(config, conn, totalRowSql, paras);
-		if (config.dialect.isGroupBySql(sql)) {
-			totalRow = result.size();
+		int size = result.size();
+		if (isGroupBySql == null) {
+			isGroupBySql = size > 1;
+		}
+		
+		long totalRow;
+		if (isGroupBySql) {
+			totalRow = size;
 		} else {
-			totalRow = (result.size() > 0) ? ((Number)result.get(0)).longValue() : 0;
+			totalRow = (size > 0) ? ((Number)result.get(0)).longValue() : 0;
 		}
 		if (totalRow == 0) {
 			return new Page<M>(new ArrayList<M>(0), pageNumber, pageSize, 0, 0);	// totalRow = 0;
@@ -352,16 +352,16 @@ public abstract class Model<M extends Model> implements Serializable {
 		}
 		
 		// --------
-		sql = config.dialect.forPaginate(pageNumber, pageSize, sql);
+		String sql = config.dialect.forPaginate(pageNumber, pageSize, select, sqlExceptSelect);
 		List<M> list = find(conn, sql, paras);
 		return new Page<M>(list, pageNumber, pageSize, totalPage, (int)totalRow);
 	}
 	
 	/**
-	 * @see #paginate(int, int, String, Object...)
+	 * @see #paginate(int, int, String, String, Object...)
 	 */
-	public Page<M> paginate(int pageNumber, int pageSize, String sql) {
-		return paginate(pageNumber, pageSize, sql, NULL_PARA_ARRAY);
+	public Page<M> paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect) {
+		return paginate(pageNumber, pageSize, select, sqlExceptSelect, NULL_PARA_ARRAY);
 	}
 	
 	/**
@@ -861,36 +861,36 @@ public abstract class Model<M extends Model> implements Serializable {
 	
 	/**
 	 * Paginate by cache.
-	 * @see #paginate(int, int, String, Object...)
+	 * @see #paginate(int, int, String, String, Object...)
 	 * @param cacheName the cache name
 	 * @param key the key used to get date from cache
 	 * @return Page
 	 */
-	public Page<M> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String sql, Object... paras) {
+	public Page<M> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {
 		ICache cache = getConfig().getCache();
 		Page<M> result = cache.get(cacheName, key);
 		if (result == null) {
-			result = paginate(pageNumber, pageSize, sql, paras);
+			result = paginate(pageNumber, pageSize, select, sqlExceptSelect, paras);
 			cache.put(cacheName, key, result);
 		}
 		return result;
 	}
 	
-	public Page<M> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String[] selectAndSqlExceptSelect, Object... paras) {
+	public Page<M> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {
 		ICache cache = getConfig().getCache();
 		Page<M> result = cache.get(cacheName, key);
 		if (result == null) {
-			result = paginate(pageNumber, pageSize, selectAndSqlExceptSelect, paras);
+			result = paginate(pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);
 			cache.put(cacheName, key, result);
 		}
 		return result;
 	}
 	
 	/**
-	 * @see #paginateByCache(String, Object, int, int, String, Object...)
+	 * @see #paginateByCache(String, Object, int, int, String, String, Object...)
 	 */
-	public Page<M> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String sql) {
-		return paginateByCache(cacheName, key, pageNumber, pageSize, sql, NULL_PARA_ARRAY);
+	public Page<M> paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String select, String sqlExceptSelect) {
+		return paginateByCache(cacheName, key, pageNumber, pageSize, select, sqlExceptSelect, NULL_PARA_ARRAY);
 	}
 	
 	/**

+ 29 - 13
src/com/jfinal/plugin/activerecord/dialect/AnsiSqlDialect.java

@@ -193,7 +193,7 @@ public class AnsiSqlDialect extends Dialect {
 	/**
 	 * SELECT * FROM subject t1 WHERE (SELECT count(*) FROM subject t2 WHERE t2.id < t1.id AND t2.key = '123') > = 10 AND (SELECT count(*) FROM subject t2 WHERE t2.id < t1.id AND t2.key = '123') < 20 AND t1.key = '123'
 	 */
-	public String forPaginate(int pageNumber, int pageSize, String sql) {
+	public String forPaginate(int pageNumber, int pageSize, String select, String sqlExceptSelect) {
 		throw new ActiveRecordException("Your should not invoke this method because takeOverDbPaginate(...) will take over it.");
 	}
 	
@@ -202,13 +202,19 @@ public class AnsiSqlDialect extends Dialect {
 	}
 	
 	@SuppressWarnings("rawtypes")
-	public Page<Record> takeOverDbPaginate(Connection conn, int pageNumber, int pageSize, String totalRowSql, String sql, Object... paras) throws SQLException {
-		long totalRow;
+	public Page<Record> takeOverDbPaginate(Connection conn, int pageNumber, int pageSize, Boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) throws SQLException {
+		String totalRowSql = "select count(*) " + replaceOrderBy(sqlExceptSelect);
 		List result = CPI.query(conn, totalRowSql, paras);
-		if (isGroupBySql(sql)) {
-			totalRow = result.size();
+		int size = result.size();
+		if (isGroupBySql == null) {
+			isGroupBySql = size > 1;
+		}
+		
+		long totalRow;
+		if (isGroupBySql) {
+			totalRow = size;
 		} else {
-			totalRow = (result.size() > 0) ? ((Number)result.get(0)).longValue() : 0;
+			totalRow = (size > 0) ? ((Number)result.get(0)).longValue() : 0;
 		}
 		if (totalRow == 0) {
 			return new Page<Record>(new ArrayList<Record>(0), pageNumber, pageSize, 0, 0);
@@ -222,7 +228,9 @@ public class AnsiSqlDialect extends Dialect {
 			return new Page<Record>(new ArrayList<Record>(0), pageNumber, pageSize, totalPage, (int)totalRow);
 		}
 		
-		PreparedStatement pst = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
+		StringBuilder sql = new StringBuilder();
+		sql.append(select).append(" ").append(sqlExceptSelect);
+		PreparedStatement pst = conn.prepareStatement(sql.toString(), ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
 		for (int i=0; i<paras.length; i++) {
 			pst.setObject(i + 1, paras[i]);
 		}
@@ -284,13 +292,19 @@ public class AnsiSqlDialect extends Dialect {
 	}
 	
 	@SuppressWarnings({"rawtypes", "unchecked"})
-	public Page<? extends Model> takeOverModelPaginate(Connection conn, Class<? extends Model> modelClass, int pageNumber, int pageSize, String totalRowSql, String sql, Object... paras) throws Exception {
-		long totalRow;
+	public Page<? extends Model> takeOverModelPaginate(Connection conn, Class<? extends Model> modelClass, int pageNumber, int pageSize, Boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) throws Exception {
+		String totalRowSql = "select count(*) " + replaceOrderBy(sqlExceptSelect);
 		List result = CPI.query(conn, totalRowSql, paras);
-		if (isGroupBySql(sql)) {
-			totalRow = result.size();
+		int size = result.size();
+		if (isGroupBySql == null) {
+			isGroupBySql = size > 1;
+		}
+		
+		long totalRow;
+		if (isGroupBySql) {
+			totalRow = size;
 		} else {
-			totalRow = (result.size() > 0) ? ((Number)result.get(0)).longValue() : 0;
+			totalRow = (size > 0) ? ((Number)result.get(0)).longValue() : 0;
 		}
 		if (totalRow == 0) {
 			return new Page(new ArrayList(0), pageNumber, pageSize, 0, 0);	// totalRow = 0;
@@ -305,7 +319,9 @@ public class AnsiSqlDialect extends Dialect {
 		}
 		
 		// --------
-		PreparedStatement pst = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
+		StringBuilder sql = new StringBuilder();
+		sql.append(select).append(" ").append(sqlExceptSelect);
+		PreparedStatement pst = conn.prepareStatement(sql.toString(), ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
 		for (int i=0; i<paras.length; i++) {
 			pst.setObject(i + 1, paras[i]);
 		}

+ 3 - 60
src/com/jfinal/plugin/activerecord/dialect/Dialect.java

@@ -22,7 +22,6 @@ import java.sql.SQLException;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import com.jfinal.plugin.activerecord.Model;
 import com.jfinal.plugin.activerecord.Page;
@@ -36,7 +35,7 @@ public abstract class Dialect {
 	
 	// Methods for common
 	public abstract String forTableBuilderDoBuild(String tableName);
-	public abstract String forPaginate(int pageNumber, int pageSize, String sql);
+	public abstract String forPaginate(int pageNumber, int pageSize, String select, String sqlExceptSelect);
 	
 	// Methods for Model
 	public abstract String forModelFindById(Table table, String columns);
@@ -58,7 +57,7 @@ public abstract class Dialect {
 		return false;
 	}
 	
-	public Page<Record> takeOverDbPaginate(Connection conn, int pageNumber, int pageSize, String totalRowSql, String sql, Object... paras) throws SQLException {
+	public Page<Record> takeOverDbPaginate(Connection conn, int pageNumber, int pageSize, Boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) throws SQLException {
 		throw new RuntimeException("You should implements this method in " + getClass().getName());
 	}
 	
@@ -67,7 +66,7 @@ public abstract class Dialect {
 	}
 	
 	@SuppressWarnings("rawtypes")
-	public Page takeOverModelPaginate(Connection conn, Class<? extends Model> modelClass, int pageNumber, int pageSize, String totalRowSql, String sql, Object... paras) throws Exception {
+	public Page takeOverModelPaginate(Connection conn, Class<? extends Model> modelClass, int pageNumber, int pageSize, Boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) throws Exception {
 		throw new RuntimeException("You should implements this method in " + getClass().getName());
 	}
 	
@@ -116,67 +115,11 @@ public abstract class Dialect {
 		private static final Pattern ORDER_BY_PATTERN = Pattern.compile(
 			"order\\s+by\\s+[^,\\s]+(\\s+asc|\\s+desc)?(\\s*,\\s*[^,\\s]+(\\s+asc|\\s+desc)?)*",
 			Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
-		
-		// "(^\\s*select\\s+[\\s\\S]+?(\\s+|\\)))from\\b";
-		private static final Pattern SELECT_PATTERN = Pattern.compile(
-			"(^\\s*select\\s+[\\s\\S]+?(\\s+|\\)))from",
-			Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
-		
-		private static final Pattern GROUP_BY_PATTERN = Pattern.compile(
-			".+?\\s+group\\s+by\\s+.+?",
-			Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
 	}
 	
 	public String replaceOrderBy(String sql) {
 		return Holder.ORDER_BY_PATTERN.matcher(sql).replaceAll("");
 	}
-	
-	public String forTotalRow(Object[] actualSqlParas, String sql, Object... paras) {
-		String sqlExceptSelect = getSqlExceptSelect(sql);
-		if (sqlExceptSelect != null) {
-			actualSqlParas[0] = sql;
-			actualSqlParas[1] = paras;
-			return "select count(*) " + replaceOrderBy(sqlExceptSelect);
-		}
-		
-		// Compatible with paginate(1, 10, "select *", "from ...", a, b);
-		if (paras != null && paras.length > 0 && paras[0] instanceof String) {
-			sqlExceptSelect = (String)paras[0];
-			actualSqlParas[0] = sql + " " + sqlExceptSelect;
-			
-			// Compatible with paginate(1, 10, "select *", "from ...", paras.toArray());
-			if (paras.length == 2 && paras[1] instanceof Object[]) {
-				actualSqlParas[1] = (Object[])paras[1];
-			}
-			else {
-				Object[] newParas = new Object[paras.length - 1];
-				for (int i=1; i<paras.length; i++) {
-					newParas[i-1] = paras[i];
-				}
-				actualSqlParas[1] = newParas;
-			}
-			return "select count(*) " + replaceOrderBy(sqlExceptSelect);
-		}
-		
-		throw new RuntimeException("Sql error : " + sql);
-	}
-	
-	public String getSqlExceptSelect(String sql) {
-		Matcher matcher = Holder.SELECT_PATTERN.matcher(sql);
-		if (matcher.find()) {
-			return sql.substring(matcher.end(1));
-		} else {
-			return null;
-		}
-	}
-	
-	/**
-	 * 判断 sql 中是否带有 group by 子句
-	 */
-	public boolean isGroupBySql(String sql) {
-		Matcher matcher = Holder.GROUP_BY_PATTERN.matcher(sql);
-		return matcher.find();
-	}
 }
 
 

+ 2 - 2
src/com/jfinal/plugin/activerecord/dialect/MysqlDialect.java

@@ -194,10 +194,10 @@ public class MysqlDialect extends Dialect {
 		}
 	}
 	
-	public String forPaginate(int pageNumber, int pageSize, String sql) {
+	public String forPaginate(int pageNumber, int pageSize, String select, String sqlExceptSelect) {
 		int offset = pageSize * (pageNumber - 1);
 		StringBuilder ret = new StringBuilder();
-		ret.append(sql);
+		ret.append(select).append(" ").append(sqlExceptSelect);
 		ret.append(" limit ").append(offset).append(", ").append(pageSize);	// limit can use one or two '?' to pass paras
 		return ret.toString();
 	}

+ 4 - 4
src/com/jfinal/plugin/activerecord/dialect/OracleDialect.java

@@ -194,14 +194,14 @@ public class OracleDialect extends Dialect {
 		}
 	}
 	
-	public String forPaginate(int pageNumber, int pageSize, String sql) {
-		int start = (pageNumber - 1) * pageSize + 1;
+	public String forPaginate(int pageNumber, int pageSize, String select, String sqlExceptSelect) {
+		int start = (pageNumber - 1) * pageSize;
 		int end = pageNumber * pageSize;
 		StringBuilder ret = new StringBuilder();
 		ret.append("select * from ( select row_.*, rownum rownum_ from (  ");
-		ret.append(sql);
+		ret.append(select).append(" ").append(sqlExceptSelect);
 		ret.append(" ) row_ where rownum <= ").append(end).append(") table_alias");
-		ret.append(" where table_alias.rownum_ >= ").append(start);
+		ret.append(" where table_alias.rownum_ > ").append(start);
 		return ret.toString();
 	}
 	

+ 3 - 2
src/com/jfinal/plugin/activerecord/dialect/PostgreSqlDialect.java

@@ -20,6 +20,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+
 import com.jfinal.plugin.activerecord.Record;
 import com.jfinal.plugin.activerecord.Table;
 
@@ -191,10 +192,10 @@ public class PostgreSqlDialect extends Dialect {
 		}
 	}
 	
-	public String forPaginate(int pageNumber, int pageSize, String sql) {
+	public String forPaginate(int pageNumber, int pageSize, String select, String sqlExceptSelect) {
 		int offset = pageSize * (pageNumber - 1);
 		StringBuilder ret = new StringBuilder();
-		ret.append(sql);
+		ret.append(select).append(" ").append(sqlExceptSelect);
 		ret.append(" limit ").append(pageSize).append(" offset ").append(offset);
 		return ret.toString();
 	}

+ 2 - 2
src/com/jfinal/plugin/activerecord/dialect/SqlServerDialect.java

@@ -179,7 +179,7 @@ public class SqlServerDialect extends Dialect {
 	/**
 	 * sql.replaceFirst("(?i)select", "") 正则中带有 "(?i)" 前缀,指定在匹配时不区分大小写
 	 */
-	public String forPaginate(int pageNumber, int pageSize, String sql) {
+	public String forPaginate(int pageNumber, int pageSize, String select, String sqlExceptSelect) {
 		int end = pageNumber * pageSize;
 		if (end <= 0) {
 			end = pageSize;
@@ -191,7 +191,7 @@ public class SqlServerDialect extends Dialect {
 		StringBuilder ret = new StringBuilder();
 		ret.append("SELECT * FROM ( SELECT row_number() over (order by tempcolumn) temprownumber, * FROM ");
 		ret.append(" ( SELECT TOP ").append(end).append(" tempcolumn=0,");
-		ret.append(sql.replaceFirst("(?i)select", ""));
+		ret.append(select.replaceFirst("(?i)select", "")).append(" ").append(sqlExceptSelect);
 		ret.append(")vip)mvp where temprownumber>").append(begin);
 		return ret.toString();
 	}

+ 3 - 2
src/com/jfinal/plugin/activerecord/dialect/Sqlite3Dialect.java

@@ -20,6 +20,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+
 import com.jfinal.plugin.activerecord.Record;
 import com.jfinal.plugin.activerecord.Table;
 
@@ -176,10 +177,10 @@ public class Sqlite3Dialect extends Dialect {
 		}
 	}
 	
-	public String forPaginate(int pageNumber, int pageSize, String sql) {
+	public String forPaginate(int pageNumber, int pageSize, String select, String sqlExceptSelect) {
 		int offset = pageSize * (pageNumber - 1);
 		StringBuilder ret = new StringBuilder();
-		ret.append(sql);
+		ret.append(select).append(" ").append(sqlExceptSelect);
 		ret.append(" limit ").append(offset).append(", ").append(pageSize);
 		return ret.toString();
 	}