package org.nutz.dao.pager;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;

import org.nutz.dao.sql.SqlContext;

/**
 * 遍历 RersultSet
 * 
 * @author zozoh(zozohtnt@gmail.com)
 */
public abstract class ResultSetLooping {

	protected List<Object> list;

	private int index;

	public ResultSetLooping() {
		list = new LinkedList<Object>();
		index = -1;
	}

	public void doLoop(ResultSet rs, SqlContext context) throws SQLException {
		Pager pager = context.getPager();
		if (null == rs)
			return;
		/**
		 * 如果没有设置 Pager 或者 rs 的类型是 ResultSet.TYPE_FORWARD_ONLY，那么<br>
		 * 无法利用 游标的滚动 来计算结果集合大小。这比较高效，但是如果使用者希望得到页数量，<br>
		 * 需要为 Pager 另行计算 总体的结果集大小。
		 * <p>
		 * 一般的，为特殊数据建立的 Pager，生成的 ResultSet 类型应该是 TYPE_FORWARD_ONLY
		 */
		if (null == pager
			|| ResultSet.TYPE_FORWARD_ONLY == rs.getType()
			|| pager.getPageNumber() <= 0) {
			// 根据 Pager 设定 Fetch Size
			if (null != pager && pager.getPageSize() > 0)
				rs.setFetchSize(pager.getPageSize());

			// 循环调用
			while (rs.next()) {
				createObject(++index, rs, context, -1);
			}
		}
		/**
		 * 如果进行到了这个分支，则表示，整个查询的 Pager 是不区分数据库类型的。 <br>
		 * 并且 ResultSet 的游标是可以来回滚动的。
		 * <p>
		 * 所以我就会利用游标的滚动，为你计算整个结果集的大小。比较低效，在很小<br>
		 * 数据量的时候 还是比较有用的
		 */
		else if (rs.last()) {
			// 设置结果集合的 FetchSize
			if (pager.getPageSize() <= 0)
				rs.setFetchSize(Pager.DEFAULT_PAGE_SIZE);
			else if (pager.getPageSize() > Pager.MAX_FETCH_SIZE)
				rs.setFetchSize(Pager.MAX_FETCH_SIZE);
			else
				rs.setFetchSize(pager.getPageSize());

			// 开始循环
			int rowCount = rs.getRow();
			LoopScope ls = LoopScope.eval(pager, rowCount);
			if (rs.absolute(ls.start + 1))
				for (int i = ls.start; i < ls.max; i++) {
					createObject(++index, rs, context, rowCount);
					if (!rs.next())
						break;
				}
		}
	}

	/**
	 * @return 当前获取的 List
	 */
	public List<Object> getList() {
		return list;
	}

	/**
	 * 获得最后一次回调被调用时的下标。 index 的值初始为 -1，每次调用回调前都会自增
	 * 
	 * @return 当前循环的下标，下标由 0 开始
	 */
	public int getIndex() {
		return index;
	}

	/**
	 * 子类需要实现的函数
	 * 
	 * @param index
	 *            当前下标
	 * @param rs
	 *            结果集
	 * @param context
	 *            Sql 上下文
	 * @param rowCount
	 *            总记录数，如果是原生分页语句，则会为 -1
	 * @return 是否成功的创建了对象
	 */
	protected abstract boolean createObject(int index,
											ResultSet rs,
											SqlContext context,
											int rowCount);

}

@@ -955,24 +955,79 @@
 ch Size%0D%0A%09%09%09
+// by wendal: %E8%AE%BE%E7%BD%AE%E4%B8%8E%E5%90%A6,%E5%BD%B1%E5%93%8D%E4%B8%8D%E5%A4%A7%E7%9A%84,%E8%80%8C%E4%B8%94%E6%97%A7%E7%89%88%E6%9C%AC%E7%9A%84Oracle%E4%BC%9A%E5%87%BA%E9%97%AE%E9%A2%98,%E6%95%85,%E6%B3%A8%E9%87%8A%E6%8E%89%E4%BA%86%0D%0A%09%09%09//
 if (null != 
@@ -1056,32 +1056,34 @@
 Size() %3E 0)%0D%0A%09%09%09
+//
 %09rs.setFetchSize

fix issue #172