All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.scudata.dw.Cursor Maven / Gradle / Ivy

Go to download

SPL(Structured Process Language) A programming language specially for structured data computing.

There is a newer version: 20241126
Show newest version
package com.scudata.dw;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.scudata.array.IArray;
import com.scudata.array.ObjectArray;
import com.scudata.common.MessageManager;
import com.scudata.common.RQException;
import com.scudata.dm.BaseRecord;
import com.scudata.dm.Context;
import com.scudata.dm.DataStruct;
import com.scudata.dm.ObjectReader;
import com.scudata.dm.Record;
import com.scudata.dm.Sequence;
import com.scudata.dm.Table;
import com.scudata.dm.cursor.ICursor;
import com.scudata.dm.op.New;
import com.scudata.dm.op.Operation;
import com.scudata.dm.op.Select;
import com.scudata.dm.op.Switch;
import com.scudata.expression.Constant;
import com.scudata.expression.CurrentElement;
import com.scudata.expression.CurrentSeq;
import com.scudata.expression.ElementRef;
import com.scudata.expression.Expression;
import com.scudata.expression.FieldRef;
import com.scudata.expression.Function;
import com.scudata.expression.IParam;
import com.scudata.expression.Moves;
import com.scudata.expression.Node;
import com.scudata.expression.UnknownSymbol;
import com.scudata.expression.fn.Between;
import com.scudata.expression.fn.gather.Top;
import com.scudata.expression.mfn.sequence.Contain;
import com.scudata.expression.mfn.sequence.Find;
import com.scudata.expression.mfn.sequence.PFind;
import com.scudata.expression.mfn.serial.Sbs;
import com.scudata.expression.operator.And;
import com.scudata.expression.operator.Assign;
import com.scudata.expression.operator.Comma;
import com.scudata.expression.operator.DotOperator;
import com.scudata.expression.operator.Equals;
import com.scudata.expression.operator.Greater;
import com.scudata.expression.operator.Not;
import com.scudata.expression.operator.NotEquals;
import com.scudata.expression.operator.NotGreater;
import com.scudata.expression.operator.NotSmaller;
import com.scudata.expression.operator.Or;
import com.scudata.expression.operator.Smaller;
import com.scudata.resources.EngineMessage;
import com.scudata.util.Variant;

/**
 * ?д???????α???
 * @author runqian
 *
 */
public class Cursor extends IDWCursor {
	private ColPhyTable table;//ԭ??
	private String []fields;//ȡ???ֶ?
	protected DataStruct ds;//???ݽṹ
	private String []sortedFields;//?????ֶ?
	private Expression filter;//???˱???ʽ
	
	// K:T	??K:T?????ϻ?????????K=T.find(K)??K??????ѡ???ֶ?
	private String []fkNames;
	private Sequence []codes;
	private String []opts;
	
	private IFilter []filters;//??????
	protected FindFilter []findFilters; // ??????switch???ֶ?
	private int []seqs; // colReaders??Ӧ???ֶκţ??????ֶο??ܲ?ѡ??
	
	private ColumnMetaData []columns;//?õ?????
	private BlockLinkReader rowCountReader;
	private BlockLinkReader []colReaders;
	private ObjectReader []segmentReaders;
	
	private int startBlock; // ????
	private int endBlock = -1; // ??????
	private int curBlock = 0;
	protected Sequence cache;
	
	private long prevRecordSeq = 0; // ǰһ????¼?????
	private int []findex; // ѡ???ֶζ?Ӧ???ֶκ?
	private ArrayList modifyRecords;
	private int mindex = 0;
	private int mcount = 0;
	
	// ͬ???ֶ?ʱ??Ҫ??????һ?ε?һ???????ڱ??εIJ???
	private Sequence appendData;
	private int appendIndex = 0;
	
	private boolean isClosed = false;
	private boolean isFirstSkip = true;
	private boolean isSegment = false;
	private Expression []exps;//????ʽ?ֶ?
	private Expression []expsBakup;
	private String []names;//ȡ????
	private TableGather []gathers;//??????????ȡ
	private boolean isField[];//true,???ֶΣ?false???DZ???ʽ
	private DataStruct tempDs;
	
	public Cursor() {
	}
	
	public Cursor(ColPhyTable table) {
		this(table, null);
	}
	
	public Cursor(ColPhyTable table, String []fields) {
		this(table, fields, null, null);
	}
	
	public Cursor(ColPhyTable table, String []fields, Expression filter, Context ctx) {
		this.table = table;
		this.fields = fields;
		this.filter = filter;
		this.ctx = ctx;
		
		init();
	}
	
	public Cursor(ColPhyTable table, String []fields, Expression filter, String []fkNames, 
			Sequence []codes, String []opts, Context ctx) {
		this.table = table;
		this.fields = fields;
		this.filter = filter;
		this.fkNames = fkNames;
		this.codes = codes;
		this.opts = opts;
		this.ctx = ctx;
		
		init();
	}
	
	public Cursor(ColPhyTable table, Expression []exps, String []names, Expression filter, Context ctx) {
		this.table = table;
		this.filter = filter;
		this.names = names;
		this.ctx = ctx;
		
		if (exps == null && names != null) {
			this.fields = names;
			this.names = null;
		}
		
		initExps(exps);
		init();
	}
	
	public Cursor(ColPhyTable table, Expression []exps, String []names, Expression filter, 
			String []fkNames, Sequence []codes, String []opts, Context ctx) {
		this.table = table;
		this.filter = filter;
		this.fkNames = fkNames;
		this.codes = codes;
		this.opts = opts;
		this.names = names;
		this.ctx = ctx;
		
		if (exps == null && names != null) {
			this.fields = names;
			this.names = null;
		}
		
		initExps(exps);		
		init();
	}
	
	public PhyTable getTableMetaData() {
		return table;
	}

	/**
	 * ???÷ֶ?startBlock??????endBlock??????
	 */
	public void setSegment(int startBlock, int endBlock) {
		isSegment = true;
		this.startBlock = startBlock;
		this.curBlock = startBlock;
		this.endBlock = endBlock;
		
		if (startBlock == 0 || startBlock >= endBlock) {
			return;
		}
		
		ColumnMetaData []columns = this.columns;
		BlockLinkReader rowCountReader = this.rowCountReader;
		int colCount = columns.length;
		long prevRecordSeq = 0;
		
		try {
			if (filters == null) {
				BlockLinkReader []colReaders = this.colReaders;
				ObjectReader []segmentReaders = new ObjectReader[colCount];
				for (int i = 0; i < colCount; ++i) {
					if (columns[i] != null) {
						segmentReaders[i] = columns[i].getSegmentReader();
					}
				}
				
				for (int i = 0; i < startBlock; ++i) {
					prevRecordSeq += rowCountReader.readInt32();
					for (int f = 0; f < colCount; ++f) {
						if (segmentReaders[f] != null) {
							segmentReaders[f].readLong40();
							if (columns[f].hasMaxMinValues()) {
								segmentReaders[f].skipObject();
								segmentReaders[f].skipObject();
								segmentReaders[f].skipObject();
							}
						}
					}
				}
				
				for (int f = 0; f < colCount; ++f) {
					if (segmentReaders[f] != null) {
						long pos = segmentReaders[f].readLong40();
						colReaders[f].seek(pos);
					}
				}
			} else {
				ObjectReader []segmentReaders = this.segmentReaders;
				for (int i = 0; i < startBlock; ++i) {
					prevRecordSeq += rowCountReader.readInt32();
					for (int f = 0; f < colCount; ++f) {
						if (segmentReaders[f] != null) {
							segmentReaders[f].readLong40();
							if (columns[f].hasMaxMinValues()) {
								segmentReaders[f].skipObject();
								segmentReaders[f].skipObject();
								segmentReaders[f].skipObject();
							}
						}
					}
				}
			}
			
			this.prevRecordSeq = prevRecordSeq;
			if (prevRecordSeq > 0 && mcount > 0) {
				// ????ҲҪ??Ӧ?????ֶ?
				ArrayList modifyRecords = this.modifyRecords;
				int mindex = 0;
				for (ModifyRecord r : modifyRecords) {
					if (r.getRecordSeq() <= prevRecordSeq) {
						mindex++;
					} else {
						break;
					}
				}
				
				this.mindex = mindex;
			}
			
			if (gathers != null) {
				for (TableGather gather : gathers) {
					if (gather != null) {
						gather.setSegment(startBlock, endBlock);
					}
				}
			}
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		}
	}
	
	/**
	 *  ͬ???ֶ?ʱ??Ҫ??????һ?ε?һ???????ڱ??εIJ???
	 */
	public void setAppendData(Sequence seq) {
		this.appendData = (Sequence) seq;
		if (seq != null && seq.length() > 0) {
			appendIndex = 1;
		}
	}
	
	public Sequence getAppendData() {
		return appendData;
	}
	
	/**
	 * ?ӱ???ʽ????ȡ?漰??????
	 * @param table
	 * @param node
	 * @return
	 */
	private static ColumnMetaData getColumn(ColPhyTable table, Node node) {
		if (node instanceof UnknownSymbol) {
			/**
			 * ֱ?Ӿ????ֶ?
			 */
			String keyName = ((UnknownSymbol)node).getName();
			return table.getColumn(keyName);
		} else if (node instanceof DotOperator && node.getLeft() instanceof CurrentElement && 
				node.getRight() instanceof FieldRef) {
			/**
			 *  ~.key??ʽ??
			 */
			FieldRef fieldNode = (FieldRef)node.getRight();
			String keyName = fieldNode.getName();
			return table.getColumn(keyName);
		} else if (node instanceof DotOperator && node.getRight() instanceof Sbs) {
			/**
			 * ?ź?k.sbs()
			 */
			Node left = node.getLeft();
			return getColumn(table, left);
		} else if (node instanceof com.scudata.expression.fn.math.And) {
			ColumnMetaData col = getColumn(table, ((Function) node).getParam().getSub(0).getLeafExpression().getHome());
			if (col == null) {
				col = getColumn(table, ((Function) node).getParam().getSub(1).getLeafExpression().getHome());
			}
			return col;
		} else {
			return null;
		}
	}
	
	private static Object combineAnd(Node node, Object left, Object right) {
		/*if (left instanceof ColumnsOr && right instanceof ColumnsOr) {
			return node;
		}
		if (left instanceof ColumnsOr) {
			left = ((ColumnsOr) left).getNode();
		}
		if (right instanceof ColumnsOr) {
			right = ((ColumnsOr) right).getNode();
		}*/
		
		if (left instanceof IFilter) {
			if (right instanceof IFilter) {
				IFilter f1 = (IFilter)left;
				IFilter f2 = (IFilter)right;
				if (f1.isSameColumn(f2)) {
					return new LogicAnd(f1,f2);
				} else {
					ArrayList filterList = new ArrayList();
					filterList.add(f1);
					filterList.add(f2);
					return filterList;
				}
			} else if (right instanceof ArrayList) {
				IFilter filter = (IFilter)left;
				ArrayList filterList = (ArrayList)right;
				for (int i = 0, size = filterList.size(); i < size; ++i) {
					Object obj = filterList.get(i);
					if (obj instanceof IFilter && filter.isSameColumn((IFilter)obj)) {
						LogicAnd and = new LogicAnd(filter, (IFilter)obj);
						filterList.set(i, and);
						return filterList;
					}
				}
				
				filterList.add(filter);
				return filterList;
			} else {
				ArrayList filterList = new ArrayList();
				filterList.add(left);
				filterList.add(right);
				return filterList;
			}
		} else if (left instanceof ArrayList) {
			ArrayList filterList = (ArrayList)left;
			if (right instanceof IFilter) {
				IFilter filter = (IFilter)right;
				for (int i = 0, size = filterList.size(); i < size; ++i) {
					Object obj = filterList.get(i);
					if (obj instanceof IFilter && filter.isSameColumn((IFilter)obj)) {
						LogicAnd and = new LogicAnd(filter, (IFilter)obj);
						filterList.set(i, and);
						return filterList;
					}
				}
				
				filterList.add(filter);
				return filterList;
			} else if (right instanceof ArrayList) {
				ArrayList filterList2 = (ArrayList)right;
				int size = filterList.size();
				
				Next:
				for (int i = 0, size2 = filterList2.size(); i < size2; ++i) {
					Object obj = filterList2.get(i);
					if (obj instanceof IFilter) {
						IFilter filter = (IFilter)obj;
						for (int j = 0; j < size; ++j) {
							obj = filterList.get(j);
							if (obj instanceof IFilter && filter.isSameColumn((IFilter)obj)) {
								LogicAnd and = new LogicAnd((IFilter)obj, filter);
								filterList.set(j, and);
								continue Next;
							}
						}
						
						filterList.add(filter);
					} else {
						filterList.add(obj);
					}
				}
				
				return filterList;
			} else {
				filterList.add(right);
				return filterList;
			}
		} else {
			if (right instanceof IFilter) {
				ArrayList filterList = new ArrayList();
				filterList.add(left);
				filterList.add(right);
				return filterList;
			} else if (right instanceof ArrayList) {
				ArrayList filterList = (ArrayList)right;
				filterList.add(left);
				return filterList;
			} else {
				return node;
			}
		}
	}
	
	private static Object combineOr(Node node, Object left, Object right) {
		if (left instanceof IFilter) {
			if (right instanceof IFilter) {
				IFilter f1 = (IFilter)left;
				IFilter f2 = (IFilter)right;
				if (f1.isSameColumn(f2)) {
					return new LogicOr(f1,f2);
				} else {
					ColumnsOr colsOr = new ColumnsOr();
					colsOr.addFilter(f1);
					colsOr.addFilter(f2);
					colsOr.setNode(node);
					return colsOr;
				}
			} else if (right instanceof ColumnsOr) {
				IFilter f1 = (IFilter)left;
				ColumnsOr colsOr = (ColumnsOr)right;
				colsOr.addFilter(f1);
				colsOr.setNode(node);
				return colsOr;
			} else {
				return node;
			}
		} else if (left instanceof ColumnsOr) {
			if (right instanceof IFilter) {
				ColumnsOr colsOr = (ColumnsOr)left;
				IFilter f2 = (IFilter)right;
				colsOr.addFilter(f2);
				colsOr.setNode(node);
				return colsOr;
			} else if (right instanceof ColumnsOr) {
				ColumnsOr colsOr1 = (ColumnsOr)left;
				ColumnsOr colsOr2 = (ColumnsOr)right;
				colsOr1.combineColumnsOr(colsOr2);
				colsOr1.setNode(node);
				return colsOr1;
			} else {
				return node;
			}
		} else {
			return node;
		}
	}

	private void parseSwitch(ColPhyTable table, Context ctx) {
		ArrayList mrecords = table.getModifyRecords();
		if (mrecords != null && mrecords.size() > 0) {
			int fkCount = fkNames.length;
			for (int i = 0; i < fkCount; i ++) {
				String[] fkn = new String[] {fkNames[i]};
				Sequence[] code = new Sequence[] {codes[i]};
				String opt = null;
				Expression exps[] = null;
				if (opts[i] != null && opts[i].indexOf("#") != -1) {
					exps = new Expression[] {new Expression("#")};
				} else if (opts[i] != null && opts[i].indexOf("null") != -1) {
					opt = "d";
				} else {
					opt = "i";
				}
				Switch op = new Switch(fkn, code, exps, opt);
				addOperation(op, ctx);
			}
			
			// ???fkNames???Ƿ???????û??ѡ?????ֶΣ??????????????뵽ѡ???ֶ???
			if (fields != null) {
				ArrayList selectList = new ArrayList();
				for (String name : fields) {
					selectList.add(name);
				}
				
				for (String name : fkNames) {
					if (!selectList.contains(name) && table.getColumn(name) != null) {
						selectList.add(name);
					}
				}
				
				int oldLen = fields.length;
				if (selectList.size() > oldLen) {
					String []newFields = new String[selectList.size()];
					selectList.toArray(newFields);
					Expression []newExps = new Expression[oldLen];
					for (int i = 1; i <= oldLen; ++i) {
						newExps[i - 1] = new Expression("#" + i);
					}
					
					int newLen = selectList.size();
					if (exps != null) {
						exps = Arrays.copyOf(exps, newLen);
						for (int i = oldLen; i < newLen; ++i) {
							exps[i] = new Expression(newFields[i]);
						}
					}
					String []newNames = null;
					if (names != null) {
						newNames = names;
						names = null;
					} else {
						newNames = fields;
					}
					
					New newOp = new New(newExps, newNames, null);
					addOperation(newOp, ctx);
					fields = newFields;
				}
			}
		} else {
			int fcount = fkNames.length;
			ArrayList filterList = new ArrayList();
			ArrayList findFilterList = new ArrayList();
			if (filters != null) {
				for (IFilter filter : filters) {
					filterList.add(filter);
					findFilterList.add(null);
				}
			}
			
			int fltCount = filterList.size();
			
			Next:
			for (int f = 0; f < fcount; ++f) {
				ColumnMetaData column = table.getColumn(fkNames[f]);
				if (column == null) {
					MessageManager mm = EngineMessage.get();
					throw new RQException(fkNames[f] + mm.getMessage("ds.fieldNotExist"));
				}
				
				int pri = table.getColumnFilterPriority(column);
				FindFilter find;
				if (opts[f] != null && opts[f].indexOf("#") != -1) {
					find = new MemberFilter(column, pri, codes[f], null);
				} else if (opts[f] != null && opts[f].indexOf("null") != -1) {
					find = new NotFindFilter(column, pri, codes[f], null);
				} else {
					find = new FindFilter(column, pri, codes[f], null);
				}
				for (int i = 0; i < fltCount; ++i) {
					IFilter filter = filterList.get(i);
					if (filter.isSameColumn(find)) {
						LogicAnd and = new LogicAnd(filter, find);
						filterList.set(i, and);
						findFilterList.set(i, find);
						continue Next;
					}
				}
				
				filterList.add(find);
				findFilterList.add(find);
			}
			
			int total = filterList.size();
			filters = new IFilter[total];
			findFilters = new FindFilter[total];
			filterList.toArray(filters);
			findFilterList.toArray(findFilters);
		}
	}
	
	private void parseFilter() {
		Object obj = parseFilter(table, filter, ctx);
		Expression unknownFilter = null;
		
		if (obj instanceof IFilter) {
			filters = new IFilter[] {(IFilter)obj};
		} else if (obj instanceof ArrayList) {
			ArrayList list = (ArrayList)obj;
			ArrayList filterList = new ArrayList();
			Node node = null;
			boolean hasOr = false;
			
			for (Object f : list) {
				if (f instanceof IFilter) {
					filterList.add((IFilter)f);
				} else if (f instanceof ColumnsOr) {
					hasOr = true;
					IFilter []orFilters = ((ColumnsOr)f).toArray();
					for (IFilter filter : orFilters) {
						filterList.add(filter);
					}
				} else {
					if (node == null) {
						node = (Node)f;
					} else {
						And and = new And();
						and.setLeft(node);
						and.setRight((Node)f);
						node = and;
					}
				}
			}
			
			int size = filterList.size();
			if (size > 0) {
				filters = new IFilter[size];
				filterList.toArray(filters);
				
				if (!hasOr) {
					Arrays.sort(filters);
				}
				
				if (node != null) {
					unknownFilter = new Expression(node);
				}
			} else {
				unknownFilter = filter;
			}
		} else if (obj instanceof ColumnsOr) {
			ArrayList modifyRecords = table.getModifyRecords();
			if (modifyRecords != null || exps != null) {
				unknownFilter = filter;
			} else {
				//Ŀǰֻ?Ż?û?в?????û?б???ʽ?????
				filters = ((ColumnsOr)obj).toArray();
			}
		} else if (obj instanceof Top) {
			//do nothing
		} else {
			unknownFilter = filter;
		}
		
		if (unknownFilter != null) {
			Select select = new Select(unknownFilter, "o");
			addOperation(select, ctx);
			
			// ??鲻??ʶ??ı???ʽ???Ƿ???????û??ѡ?????ֶΣ??????????????뵽ѡ???ֶ???
			ArrayList nameList = new ArrayList();
			unknownFilter.getUsedFields(ctx, nameList);
			if (nameList.size() > 0 && fields != null) {
				ArrayList selectList = new ArrayList();
				for (String name : fields) {
					selectList.add(name);
				}
				
				for (String name : nameList) {
					if (!selectList.contains(name) && table.getColumn(name) != null) {
						selectList.add(name);
					}
				}
				
				int oldLen = fields.length;
				if (selectList.size() > oldLen) {
					String []newFields = new String[selectList.size()];
					selectList.toArray(newFields);
					Expression []newExps = new Expression[oldLen];
					for (int i = 1; i <= oldLen; ++i) {
						newExps[i - 1] = new Expression("#" + i);
					}
					
					int newLen = selectList.size();
					if (exps != null) {
						exps = Arrays.copyOf(exps, newLen);
						for (int i = oldLen; i < newLen; ++i) {
							exps[i] = new Expression(newFields[i]);
						}
					}
					String []newNames = null;
					if (names != null) {
						newNames = names;
						names = null;
					} else {
						newNames = fields;
					}
					
					New newOp = new New(newExps, newNames, null);
					addOperation(newOp, ctx);
					fields = newFields;
				}
			}
		}
	}
	
	private static Object parseTop(ColPhyTable table, Top top, Context ctx) {
		top.prepare(ctx);
		String col = top.getExp().getIdentifierName();
		ColumnMetaData column = table.getColumn(col);
		if (column == null) {
			return top;
		}
		
		int pri = table.getColumnFilterPriority(column);
		return new TopFilter(column, pri, top);
	}
	
	private static Object parseBetween(ColPhyTable table, Between bt, Context ctx) {
		IParam sub0 = bt.getParam().getSub(0);
		IParam sub1 = bt.getParam().getSub(1);
		if (sub0 == null || sub1 == null) {
			return bt;
		}
		
		Expression field = sub0.getLeafExpression();
		ColumnMetaData column = table.getColumn(field.getIdentifierName());
		if (column == null) {
			return bt;
		}
		
		int pri = table.getColumnFilterPriority(column);
		IParam startParam = sub1.getSub(0);
		IParam endParam = sub1.getSub(1);
		IFilter s = null, e = null;
		if (startParam != null) {
			Object value = startParam.getLeafExpression().calculate(ctx);
			s = new ColumnFilter(column, pri, IFilter.GREATER_EQUAL, value);
		}
		if (endParam != null) {
			Object value = endParam.getLeafExpression().calculate(ctx);
			e = new ColumnFilter(column, pri, IFilter.LESS_EQUAL, value);
		}
		
		if (s == null && e != null)
			return e;
		if (e == null && s != null)
			return s;
		if (s != null && e != null) 
			return combineAnd(bt, s, e);

		return bt;
	}
	
	private static Object parseSeriesMember(ColPhyTable table, ElementRef sm, Context ctx) {
		ColumnMetaData column = table.getColumn(sm.getParamString());
		if (column == null) {
			return sm;
		}
		
		try {
			Object val = sm.getLeft().calculate(ctx);
			if (val instanceof Sequence) {
				int pri = table.getColumnFilterPriority(column);
				return new MemberFilter(column, pri, (Sequence)val, null);
			} else {
				return sm;
			}
		} catch (Exception e) {
			return sm;
		}
	}
	
	private static Object parseAssign(ColPhyTable table, Node node, Context ctx, boolean isFilter) {
		Node unknown = node.getLeft();
		Node dotoperator = node.getRight();
		if (unknown instanceof UnknownSymbol && dotoperator instanceof DotOperator) {
			Node left = dotoperator.getLeft();
			Node right = dotoperator.getRight();
			if (right instanceof Find) {
				Find find = (Find)right;
				IParam param = find.getParam();
				if (param == null || !param.isLeaf()) {
					return node;
				}
				
				ColumnMetaData column = getColumn(table, param.getLeafExpression().getHome());
				if (column == null) {
					return node;
				}
				
				try {
					Object val = left.calculate(ctx);
					if (val instanceof Sequence) {
						int pri = table.getColumnFilterPriority(column);
						return new FindsFilter(column, pri, (Sequence)val, dotoperator, false, isFilter);
					} else {
						return node;
					}
				} catch (Exception e) {
					return node;
				}
			} else if (right instanceof PFind) {
				PFind find = (PFind)right;
				IParam param = find.getParam();
				if (param == null || !param.isLeaf()) {
					return node;
				}
				
				ColumnMetaData column = getColumn(table, param.getLeafExpression().getHome());
				if (column == null) {
					return node;
				}
				
				try {
					Object val = left.calculate(ctx);
					if (val instanceof Sequence) {
						int pri = table.getColumnFilterPriority(column);
						return new FindsFilter(column, pri, (Sequence)val, dotoperator, true, isFilter);
					} else {
						return node;
					}
				} catch (Exception e) {
					return node;
				}
			}
		}
		return null;
	}
	
	private static void parseComma(ColPhyTable table, Node node, Context ctx, List out) {
		Node left = node.getLeft();
		if (left instanceof Comma) {
			parseComma(table, left, ctx, out);
		} else {
			if (left instanceof Assign) {
				Object obj = parseAssign(table, left, ctx, false);
				if (obj == null)
					throw new RuntimeException();
				else 
					out.add(obj);
			} else {
				throw new RuntimeException();
			}
		}
		
		Node right = node.getRight();
		if (right instanceof Assign) {
			Object obj = parseAssign(table, right, ctx, false);
			if (obj == null)
				throw new RuntimeException();
			else 
				out.add(obj);
			return;
		}

		if (right instanceof Constant) {
			if (Variant.isTrue(right.calculate(ctx))) {
				return;
			}
		} else {
			out.add(right);
		}
	}
	
	private static IFilter createFindFilter(ColumnMetaData column, int pri, Sequence data, boolean isNot) {
		if (data.length() > ContainFilter.BINARYSEARCH_COUNT) {
			if (isNot) {
				return new NotFindFilter(column, pri, data, null);
			} else {
				return new FindFilter(column, pri, data, null);
			}
		} else {
			// Ԫ??????????ʱ???ñ????????ң???Ϊ?ַ?????ϣ????
			data = data.getPKeyValues();
			if (isNot) {
				return new NotContainFilter(column, pri, data, null, null);
			} else {
				return new ContainFilter(column, pri, data, null, null);
			}
		}
	}
	
	private static Object parseContain(ColPhyTable table, Node node, Context ctx, Context filterCtx) {
		if (node instanceof DotOperator) {
			if (node.getRight() instanceof Contain) {
				Contain contain = (Contain)node.getRight();
				IParam param = contain.getParam();
				if (param == null || !param.isLeaf()) {
					return node;
				}
				
				ColumnMetaData column = getColumn(table, param.getLeafExpression().getHome());
				if (column == null) {
					return node;
				}
				
				try {
					Object val = node.getLeft().calculate(ctx);
					if (val instanceof Sequence) {
						int pri = table.getColumnFilterPriority(column);
						return new ContainFilter(column, pri, (Sequence)val, contain.getOption());
					} else {
						return node;
					}
				} catch (Exception e) {
					return node;
				}
			} else if (node.getRight() instanceof Find) {
				Find find = (Find)node.getRight();
				IParam param = find.getParam();
				if (param == null || !param.isLeaf()) {
					return node;
				}
				
				ColumnMetaData column = getColumn(table, param.getLeafExpression().getHome());
				if (column == null) {
					return node;
				}
				
				try {
					Object val = node.getLeft().calculate(ctx);
					if (val instanceof Sequence) {
						int pri = table.getColumnFilterPriority(column);
						return createFindFilter(column, pri, (Sequence)val, false);
					} else {
						return node;
					}
				} catch (Exception e) {
					return node;
				}
			}
		} else if (node instanceof Not && node.getRight() instanceof DotOperator) {
			DotOperator dotNode = (DotOperator)node.getRight();
			if (dotNode.getRight() instanceof Contain) {
				Contain contain = (Contain)dotNode.getRight();
				IParam param = contain.getParam();
				if (param == null || !param.isLeaf()) {
					return node;
				}
				
				ColumnMetaData column = getColumn(table, param.getLeafExpression().getHome());
				if (column == null) {
					return node;
				}
				
				try {
					Object val = dotNode.getLeft().calculate(ctx);
					if (val instanceof Sequence) {
						int pri = table.getColumnFilterPriority(column);
						return new NotContainFilter(column, pri, (Sequence)val, contain.getOption(), node);
					} else {
						return node;
					}
				} catch (Exception e) {
					return node;
				}
			} else if (dotNode.getRight() instanceof Find) {
				Find find = (Find)dotNode.getRight();
				IParam param = find.getParam();
				if (param == null || !param.isLeaf()) {
					return node;
				}
				
				ColumnMetaData column = getColumn(table, param.getLeafExpression().getHome());
				if (column == null) {
					return node;
				}
				
				try {
					Object val = dotNode.getLeft().calculate(ctx);
					if (val instanceof Sequence) {
						int pri = table.getColumnFilterPriority(column);
						return createFindFilter(column, pri, (Sequence)val, true);
					} else {
						return node;
					}
				} catch (Exception e) {
					return node;
				}
			}
		}else if (node instanceof Assign) {
			//ki=wi
			Object obj = parseAssign(table, node, ctx, true);
			if (obj != null) 
				return obj;
		} else if (node instanceof Comma) {
			//(ki=wi,????,w)
			ArrayList list = new ArrayList();
			try {
				parseComma(table, node, ctx, list);
				return list;
			} catch (Exception e) {
				return node;
			}
		}
		
		return parseFieldExp(table, node, ctx, filterCtx);
	}
	
	
	// ???node?ǵ??ֶα???ʽ??ת??NodeFilter
	private static Object parseFieldExp(ColPhyTable table, Node node, Context ctx, Context filterCtx) {
		ArrayList fieldList = new ArrayList();
		node.getUsedFields(ctx, fieldList);
		ColumnMetaData column = null;
		
		for (String field : fieldList) {
			if (column == null) {
				column = table.getColumn(field);
			} else if (table.getColumn(field) != null) {
				return node;
			}
		}
		
		if (column != null) {
			int pri = table.getColumnFilterPriority(column);
			return new NodeFilter(column, pri, node, filterCtx);
		} else {
			return node;
		}
	}
	
	public static Object parseFilter(ColPhyTable table, Expression filter, Context ctx) {
		// ΪIFilter?½??????ģ??е?IFilter??ҪΪ?????????ӱ????????????ֶ?ֵ
		// ???߳?ʱҲ??Ҫ???Լ?????????
		Context filterCtx = new Context(ctx);
		
		// ???Ʊ???ʽ???е?IFilter??ҪΪ?????????ӱ????????????ֶ?ֵ
		// UnknownSymbol????ʱ?Ỻ???????????????α깲??һ??????ʽ?????Ӱ??
		filter = filter.newExpression(ctx);
		
		Node node = filter.getHome();
		return parseFilter(table, node, ctx, filterCtx);
	}
	
	private static Object parseFilter(ColPhyTable table, Node node, Context ctx, Context filterCtx) {
		if (node instanceof And) {
			Object left = parseFilter(table, node.getLeft(), ctx, filterCtx);
			Object right = parseFilter(table, node.getRight(), ctx, filterCtx);
			return combineAnd(node, left, right);
		} else if (node instanceof Or) {
			Object left = parseFilter(table, node.getLeft(), ctx, filterCtx);
			Object right = parseFilter(table, node.getRight(), ctx, filterCtx);
			return combineOr(node, left, right);
		} else if (node instanceof Top) {
			return parseTop(table, (Top)node, ctx);
		} else if (node instanceof Between) {
			return parseBetween(table, (Between)node, ctx);
		} else if (node instanceof ElementRef) {
			return parseSeriesMember(table, (ElementRef)node, ctx);
		} else {
			int operator;
			if (node instanceof Equals) {
				operator = IFilter.EQUAL;
			} else if (node instanceof Greater) {
				operator = IFilter.GREATER;
			} else if (node instanceof NotSmaller) {
				operator = IFilter.GREATER_EQUAL;
			} else if (node instanceof Smaller) {
				operator = IFilter.LESS;
			} else if (node instanceof NotGreater) {
				operator = IFilter.LESS_EQUAL;
			} else if (node instanceof NotEquals) {
				operator = IFilter.NOT_EQUAL;
			} else {
				return parseContain(table, node, ctx, filterCtx);
			}
			
			Node left = node.getLeft();
			ColumnMetaData column = getColumn(table, left);
			if (column != null) {
				try {
					Object value = node.getRight().calculate(ctx);
					int pri = table.getColumnFilterPriority(column);
					
					if (left instanceof com.scudata.expression.fn.math.And) {
						Expression expr = ((Function) left).getParam().getSub(0).getLeafExpression();
						if (expr.getHome() instanceof UnknownSymbol) {
							expr = ((Function) left).getParam().getSub(1).getLeafExpression();
						}
						return new AndFilter(column, pri, operator, expr.calculate(ctx), value);
					} else {
						return new ColumnFilter(column, pri, operator, value);
					}
				} catch(Exception e) {
					return node;
				}
			}
			
			Node right = node.getRight();
			column = getColumn(table, right);
			if (column != null) {
				try {
					Object value = left.calculate(ctx);
					int pri = table.getColumnFilterPriority(column);
					operator = IFilter.getInverseOP(operator);
					return new ColumnFilter(column, pri, operator, value);
				} catch(Exception e) {
					return node;
				}
			}

			return parseFieldExp(table, node, ctx, filterCtx);
		}
	}
	
	private void init() {
		try {
			table.appendCache();
		} catch (IOException e) {
			throw new RQException(e);
		}
		
		// ???????˱???ʽ
		if (filter != null) {
			parseFilter();
		}
		if (fkNames != null) {
			parseSwitch(table, ctx);
		}
		
		//??filters???ki=wi?ŵ?FindFilters??
		if (filters != null) {
			int len = filters.length;
			for (int i = 0; i < len; i++) {
				if (filters[i] instanceof FindsFilter) {
					if (findFilters == null) {
						findFilters = new FindFilter[len];
					}
					findFilters[i] = (FindsFilter) filters[i];
				}
			}
		}
		
		endBlock = table.getDataBlockCount();
		ColumnMetaData []columns;
		ArrayList expColumns = null;
		
		//?????ӱ????????Ĺ?ͬ?ͼ̳?
		if (fields == null) {
			columns = table.getColumns();
			fields = table.getColNames();
		} else {
			if (exps != null) {
				columns = table.getColumns(exps);
				expColumns = table.getExpColumns(exps);
			} else {
				columns = table.getColumns(fields);
			}
		}
		
		ds = new DataStruct(fields);
		setDataStruct(ds);
		
		rowCountReader = table.getSegmentReader();
		int colCount = columns.length;
		
		if (expColumns != null) {
			ArrayList list = new ArrayList();
			for (ColumnMetaData col : columns) {
				list.add(col);
			}
			for (ColumnMetaData col : expColumns) {
				if (!list.contains(col)) {
					list.add(col);
				}
			}
			colCount = list.size();
			columns = new ColumnMetaData[colCount];
			list.toArray(columns);
		}
		
		if (filters == null) {
			colReaders = new BlockLinkReader[colCount];
			this.columns = columns;
			
			for (int i = 0; i < colCount; ++i) {
				if (columns[i] != null) {
					colReaders[i] = columns[i].getColReader(true);
				}
			}
		} else {
			ArrayList list = new ArrayList();
			for (IFilter filter : filters) {
				list.add(filter.getColumn());
			}
			
			for (ColumnMetaData col : columns) {
				if (col == null) {
					list.add(col);
				} else if (!list.contains(col)) {
					list.add(col);
				}
			}
			
			colCount = list.size();
			colReaders = new BlockLinkReader[colCount];
			segmentReaders = new ObjectReader[colCount];
			seqs = new int [colCount];
			this.columns = new ColumnMetaData[colCount];
			list.toArray(this.columns);
			
			for (int i = 0; i < colCount; ++i) {
				ColumnMetaData col = list.get(i);
				if (col != null) {
					colReaders[i] = col.getColReader(true);
					segmentReaders[i] = col.getSegmentReader();
					seqs[i] = ds.getFieldIndex(col.getColName());
				} else {
					seqs[i] = -1;
				}
			}
		}

		modifyRecords = table.getModifyRecords();
		if (filter != null && modifyRecords != null) {
			ArrayList list = new ArrayList();
			for (ModifyRecord mr : modifyRecords) {
				if (mr.isDelete()) {
					list.add(mr);
					continue;
				}
				Record sr = mr.getRecord();
				if (Variant.isTrue(sr.calc(filter, ctx))) {
					list.add(mr);
				} else {
					if (mr.isUpdate()) {
						list.add(new ModifyRecord(mr.getRecordSeq()));
					}
				}
			}
			if (list.size() == 0) {
				modifyRecords = null;
			} else {
				modifyRecords = list;
			}
		}
		
		if (modifyRecords != null) {
			mcount = modifyRecords.size();
			DataStruct srcDs = table.getDataStruct();
			findex = new int[fields.length];
			for (int i = 0; i < fields.length; ++i) {
				findex[i] = srcDs.getFieldIndex(fields[i]);
			}
		}
		
		/**
		 * ??exps??ĸ???????ʽ??ʼ??
		 * T.f(x),T{}
		 */
		if (exps != null) {
			int size  = exps.length;
			gathers = new TableGather[size];
			for (int i = 0; i < size; i++) {
				if (exps[i] != null) {
					if (exps[i].getHome() instanceof DotOperator) {
						Node right = exps[i].getHome().getRight();
						if (!(right instanceof Sbs)) {
							gathers[i] = new TableGather(table, exps[i], ctx);
							exps[i] = null;
						}
					} else if (exps[i].getHome() instanceof UnknownSymbol) {
						exps[i] = null;
					} else if (exps[i].getHome() instanceof Moves) {
						Node left = exps[i].getHome().getLeft();
						if (left instanceof UnknownSymbol) {
							if (table.isSubTable(((UnknownSymbol) left).getName())) {
								gathers[i] = new TableGather(table, exps[i], ctx);
								exps[i] = null;
							}
						}
					} else if (exps[i].getHome() instanceof CurrentSeq) {
						gathers[i] = new TableSeqGather();
						exps[i] = null;
						if (names == null) {
							names = new String[size];
							names[i] = "#";
						} else if (names[i] == null) {
							names[i] = "#";
						}
					}
				}
			}
			
			isField = new boolean[colCount];
			String dsName[] = new String[colCount];
			for (int f = 0; f < colCount; ++f) {
				if (colReaders[f] != null) {
					isField[f] = true;
					dsName[f] = this.columns[f].getColName();
				}
			}
			tempDs = new DataStruct(dsName);
			for (int i = 0; i < colCount; ++i) {
				ColumnMetaData col = this.columns[i];
				if (col != null && colReaders[i] == null) {
					colReaders[i] = col.getColReader(true);
					segmentReaders[i] = col.getSegmentReader();
					seqs[i] = ds.getFieldIndex(col.getColName());
				}
			}
		}
		
		if (names != null) {
			int len = names.length;
			for (int i = 0; i < len; i++) {
				if (names[i] == null) {
					names[i] = ds.getFieldName(i);
				}
			}
			ds = new DataStruct(names);
			setDataStruct(ds);
		}
		
		if (table.hasPrimaryKey()) {
			// ???????????????????????ѡ????????ݽṹ????????
			String []keys = table.getAllKeyColNames();
			String []sortedCols = table.getAllSortedColNames();
			ArrayList pkeyList = new ArrayList();
			ArrayList sortedFieldList = new ArrayList();
			DataStruct temp;
			if (fields != null) {
				temp = new DataStruct(fields);
			} else {
				temp = ds;
			}
			
			boolean signKey = true;
			for (String key : keys) {
				int idx = temp.getFieldIndex(key);
				if (idx == -1) {
					signKey = false;
					break;
				} else {
					pkeyList.add(ds.getFieldName(idx));
				}
			}
			for (String col : sortedCols) {
				int idx = temp.getFieldIndex(col);
				if (idx == -1) {
					break;
				} else {
					sortedFieldList.add(ds.getFieldName(idx));
				}
			}
			
			if (signKey) {
				//??????
				int size = pkeyList.size();
				String[] pkeys = new String[size];
				pkeyList.toArray(pkeys);
				if (table.getGroupTable().hasTimeKey())
					ds.setPrimary(pkeys, "t");
				else
					ds.setPrimary(pkeys);
			}

			int size = sortedFieldList.size();
			if (size > 0) {
				//?????ֶ?
				sortedFields = new String[size];
				sortedFieldList.toArray(sortedFields);
			}
		} else if (table.isSorted) {
			// ???????????????֯?????ֶ?
			String []keys = table.getAllSortedColNames();
			ArrayList sortedFieldList = new ArrayList();
			DataStruct temp;
			if (fields != null) {
				temp = new DataStruct(fields);
			} else {
				temp = ds;
			}
			for (String key : keys) {
				int idx = temp.getFieldIndex(key);
				if (idx == -1) {
					break;
				} else {
					sortedFieldList.add(ds.getFieldName(idx));
				}
			}
			int size = sortedFieldList.size();
			if (size > 0) {
				//?????ֶ?
				sortedFields = new String[size];
				sortedFieldList.toArray(sortedFields);
			}
		}
	}
	
	protected int getInitSize(int n) {
		if (n != MAXSIZE) {
			return n;
		}
		
		long total = table.getTotalRecordCount() + mcount;
		int count;
		if (total > MAXSIZE) {
			count = MAXSIZE;
		} else {
			count = (int)total;
		}
		
		if (curBlock == 0 && endBlock == table.getDataBlockCount() && filters == null && codes == null) {
			return count;
		} else if (count > INITSIZE){
			return INITSIZE;
		} else {
			return count;
		}
	}
	
	protected Sequence get(int n) {
		// ?޸???ͬ???ֶΣ?ͬ???ֶ?ʱ????ֶε????ڿ???ij????¼????ʹ??appendData??????һ????Ҫ???ӵļ?¼
		isFirstSkip = false;
		Sequence seq;
		if (gathers == null) {
			seq = getData(n);
		} else {
			seq = getData2(n);
		}
		
		if (seq != null && seq.length() > n) {
			Sequence result = seq.split(1, n);
			cache = seq;
			return result;
		}
		
		if (appendIndex < 1) {
			return seq;
		} else {
			if (seq == null) {
				DataStruct ds = this.ds;
				Sequence appendData = this.appendData;
				int len = appendData.length();
				if (n >= len - appendIndex + 1) {
					Table table = new Table(ds, len - appendIndex + 1);
					IArray mems = table.getMems();
					for (int i = appendIndex; i <= len; ++i) {
						Record r = (Record)appendData.getMem(i);
						r.setDataStruct(ds);
						mems.add(r);
					}
					
					appendIndex = 0;
					return table;
				} else {
					Table table = new Table(ds, n);
					IArray mems = table.getMems();
					int appendIndex = this.appendIndex;
					for (int i = 0; i < n; ++i, ++appendIndex) {
						Record r = (Record)appendData.getMem(appendIndex);
						r.setDataStruct(ds);
						mems.add(r);
					}
					
					this.appendIndex = appendIndex;
					return table;
				}
			} else if (seq.length() == n) {
				return seq;
			} else {
				int diff = n - seq.length();
				DataStruct ds = this.ds;
				Sequence appendData = this.appendData;
				int len = appendData.length();
				int rest = len - appendIndex + 1;
				if (diff >= rest) {
					IArray mems = seq.getMems();
					for (int i = appendIndex; i <= len; ++i) {
						Record r = (Record)appendData.getMem(i);
						r.setDataStruct(ds);
						mems.add(r);
					}
					
					appendIndex = 0;
					return seq;
				} else {
					IArray mems = seq.getMems();
					int appendIndex = this.appendIndex;
					for (int i = 0; i < diff; ++i, ++appendIndex) {
						Record r = (Record)appendData.getMem(appendIndex);
						r.setDataStruct(ds);
						mems.add(r);
					}
					
					this.appendIndex = appendIndex;
					return seq;
				}
			}
		}
	}
	
	protected Sequence getData(int n) {
		if (isClosed || n < 1) {
			return null;
		}
		
		if (hasModify()) {
			return getModify(n);
		}
		
		Sequence cache = this.cache;
		if (cache != null) {
			int len = cache.length();
			if (len > n) {
				this.cache = (Sequence) cache.split(n + 1);
				return cache;
			} else if (len == n) {
				this.cache = null;
				return cache;
			}
		} else {
			cache = new Table(ds, getInitSize(n));
		}
		
		int curBlock = this.curBlock;
		int endBlock = this.endBlock;
		BlockLinkReader rowCountReader = this.rowCountReader;
		BlockLinkReader []colReaders = this.colReaders;
		int colCount = colReaders.length;
		BufferReader []bufReaders = new BufferReader[colCount];
		DataStruct ds = this.ds;
		IFilter []filters = this.filters;
		long prevRecordSeq = this.prevRecordSeq;
		
		IArray mems = cache.getMems();
		this.cache = null;

		try {
			if (filters == null) {
				while (curBlock < endBlock) {
					curBlock++;
					int recordCount = rowCountReader.readInt32();

					for (int f = 0; f < colCount; ++f) {
						bufReaders[f] = colReaders[f].readBlockData(recordCount);
					}
					
					int diff = n - cache.length();
					if (recordCount > diff) {
						int i = 0;
						for (; i < diff; ++i) {
							ComTableRecord r = new ComTableRecord(ds);
							for (int f = 0; f < colCount; ++f) {
								r.setNormalFieldValue(f, bufReaders[f].readObject());
							}
							r.setRecordSeq(++prevRecordSeq);
							mems.add(r);
						}
						
						Table tmp = new Table(ds, ICursor.FETCHCOUNT);
						this.cache = tmp;
						mems = tmp.getMems();
						
						for (; i < recordCount; ++i) {
							ComTableRecord r = new ComTableRecord(ds);
							for (int f = 0; f < colCount; ++f) {
								r.setNormalFieldValue(f, bufReaders[f].readObject());
							}
							r.setRecordSeq(++prevRecordSeq);
							mems.add(r);
						}
						
						break;
					} else {
						for (int i = 0; i < recordCount; ++i) {
							ComTableRecord r = new ComTableRecord(ds);
							for (int f = 0; f < colCount; ++f) {
								r.setNormalFieldValue(f, bufReaders[f].readObject());
							}
							r.setRecordSeq(++prevRecordSeq);
							mems.add(r);
						}
						
						if (diff == recordCount) {
							break;
						}
					}
				}
			} else if (filters.length == 1) {
				FindFilter findFilter = null;
				if (findFilters != null) {
					findFilter = findFilters[0];
				}
				
				ColumnMetaData []columns = this.columns;
				int []seqs = this.seqs;
				ObjectReader []segmentReaders = this.segmentReaders;
				long []positions = new long[colCount];
				IFilter filter = filters[0];
				
				while (curBlock < endBlock) {
					curBlock++;
					int recordCount = rowCountReader.readInt32();
					
					for (int f = 1; f < colCount; ++f) {
						positions[f] = segmentReaders[f].readLong40();
						if (columns[f].hasMaxMinValues()) {
							segmentReaders[f].skipObject();
							segmentReaders[f].skipObject();
							segmentReaders[f].skipObject();
						}
					}
					
					positions[0] = segmentReaders[0].readLong40();
					if (columns[0].hasMaxMinValues()) {
						Object minValue = segmentReaders[0].readObject();
						Object maxValue = segmentReaders[0].readObject();
						segmentReaders[0].skipObject();
						if (!filter.match(minValue, maxValue)) {
							continue;
						}
					}
					
					int nextRow = 0; // ??ͨ????һ??Ҫ?????У??????û????ǰҪ????????????
					BufferReader filterReader = colReaders[0].readBlockData(positions[0], recordCount);
					for (int f = 1; f < colCount; ++f) {
						bufReaders[f] = null;
					}
					
					for (int i = 0; i < recordCount; ++i) {
						// ????¼??ѭ????????е?BufferReaderû?в????????????????ǰҪ??????
						Object val = filterReader.readObject();
						if (!filter.match(val)) {
							continue;
						}
						
						Record r = new Record(ds);
						mems.add(r);
						if (seqs[0] != -1) {
							if (findFilter == null) {
								r.setNormalFieldValue(seqs[0], val);
							} else {
								r.setNormalFieldValue(seqs[0], findFilter.getFindResult());
							}
						}
						
						for (int f = 1; f < colCount; ++f) {
							if (bufReaders[f] == null) {
								bufReaders[f] = colReaders[f].readBlockData(positions[f], recordCount);
							}
							
							for (int j = nextRow; j < i; ++j) {
								bufReaders[f].skipObject();
							}
							
							if (seqs[f] != -1) {
								r.setNormalFieldValue(seqs[f], bufReaders[f].readObject());
							} else {
								bufReaders[f].skipObject();
							}
						}
						
						nextRow = i + 1;
					}
					
					int diff = n - cache.length();
					if (diff < 0) {
						this.cache = (Sequence) cache.split(n + 1);
						break;
					} else if (diff == 0) {
						break;
					}
				}
			} else {
				FindFilter []findFilters = this.findFilters;
				ColumnMetaData []columns = this.columns;
				int []seqs = this.seqs;
				ObjectReader []segmentReaders = this.segmentReaders;
				int filterCount = filters.length;
				long []positions = new long[colCount];
				
				while (curBlock < endBlock) {
					curBlock++;
					int recordCount = rowCountReader.readInt32();
					boolean sign = true;
					int f = 0;
					for (; f < filterCount; ++f) {
						positions[f] = segmentReaders[f].readLong40();
						if (columns[f].hasMaxMinValues()) {
							Object minValue = segmentReaders[f].readObject();
							Object maxValue = segmentReaders[f].readObject();
							segmentReaders[f].skipObject();
							if (!filters[f].match(minValue, maxValue)) {
								++f;
								sign = false;
								break;
							}
						}
					}
					
					for (; f < colCount; ++f) {
						positions[f] = segmentReaders[f].readLong40();
						if (columns[f].hasMaxMinValues()) {
							segmentReaders[f].skipObject();
							segmentReaders[f].skipObject();
							segmentReaders[f].skipObject();
						}
					}
					
					if (!sign) {
						continue;
					}
					
					int []nextRows = new int[colCount]; // ÿ??bufReaders??һ??Ҫ???????У??????û????ǰҪ????????????
					Object []fvalues = new Object[colCount]; // ??ǰ???????ֶε?ֵ

					for (f = 0; f < colCount; ++f) {
						bufReaders[f] = null;
					}
					
					Next:
					for (int i = 0; i < recordCount; ++i) {
						// ????¼??ѭ????????е?BufferReaderû?в????????????????ǰҪ??????
						for (f = 0; f < filterCount; ++f) {
							if (bufReaders[f] == null) 
							
							{
								bufReaders[f] = colReaders[f].readBlockData(positions[f], recordCount);
							}
							
							for (int j = nextRows[f]; j < i; ++j) {
								bufReaders[f].skipObject();
							}
							
							nextRows[f] = i + 1;
							fvalues[f] = bufReaders[f].readObject();
							if (!filters[f].match(fvalues[f])) {
								continue Next;
							}
						}
						
						Record r = new Record(ds);
						mems.add(r);
						for (f = 0; f < filterCount; ++f) {
							if (seqs[f] != -1) {
								if (findFilters == null || findFilters[f] == null) {
									r.setNormalFieldValue(seqs[f], fvalues[f]);
								} else {
									r.setNormalFieldValue(seqs[f], findFilters[f].getFindResult());
								}
							}
						}
						
						for (; f < colCount; ++f) {
							if (bufReaders[f] == null) {
								bufReaders[f] = colReaders[f].readBlockData(positions[f], recordCount);
							}
							
							for (int j = nextRows[f]; j < i; ++j) {
								bufReaders[f].skipObject();
							}
							
							nextRows[f] = i + 1;
							if (seqs[f] != -1) {
								r.setNormalFieldValue(seqs[f], bufReaders[f].readObject());
							} else {
								bufReaders[f].skipObject();
							}
						}
					}
					
					int diff = n - cache.length();
					if (diff < 0) {
						this.cache = (Sequence) cache.split(n + 1);
						break;
					} else if (diff == 0) {
						break;
					}
				}
			}
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		}
		
		this.curBlock = curBlock;
		this.prevRecordSeq = prevRecordSeq;
		if (cache.length() > 0) {
			return cache;
		} else {
			return null;
		}
	}
	
	//???ֶα???ʽʱ?????
	private Sequence getData2(int n) {
		if (isClosed || n < 1) {
			return null;
		}
		
		if (hasModify()) {
			return getModify2(n);
		}
		
		Sequence cache = this.cache;
		if (cache != null) {
			int len = cache.length();
			if (len > n) {
				this.cache = (Sequence) cache.split(n + 1);
				return cache;
			} else if (len == n) {
				this.cache = null;
				return cache;
			}
		} else {
			cache = new Table(ds, getInitSize(n));
		}
		
		int curBlock = this.curBlock;
		int endBlock = this.endBlock;
		BlockLinkReader rowCountReader = this.rowCountReader;
		BlockLinkReader []colReaders = this.colReaders;
		int colCount = colReaders.length;
		BufferReader []bufReaders = new BufferReader[colCount];
		DataStruct ds = this.ds;
		IFilter []filters = this.filters;
		long prevRecordSeq = this.prevRecordSeq;
		
		IArray mems = cache.getMems();
		this.cache = null;

		TableGather []gathers = this.gathers;
		boolean isField[] = this.isField;
		int retColCount = exps.length;
		Record temp = new Record(this.tempDs);
		Expression []exps = this.exps;
		Context ctx = this.ctx;
		
		try {
			if (filters == null) {
				while (curBlock < endBlock) {
					curBlock++;
					int recordCount = rowCountReader.readInt32();

					for (int f = 0; f < colCount; ++f) {
						if (isField[f]) {
							bufReaders[f] = colReaders[f].readBlockData(recordCount);
						}
					}
					
					for (TableGather gather : gathers) {
						if (gather != null) {
							gather.loadData();
						}
					}
					
					int diff = n - cache.length();
					if (recordCount > diff) {
						int i = 0;
						for (; i < diff; ++i) {
							for (int f = 0; f < colCount; ++f) {
								if (isField[f]) {
									temp.setNormalFieldValue(f, bufReaders[f].readObject());
								}
							}
							ComTableRecord r = new ComTableRecord(ds);
							for (int f = 0; f < retColCount; ++f) {
								if (exps[f] != null) {
									r.setNormalFieldValue(f, temp.calc(exps[f], ctx));
								} else if (isField[f]) {
									r.setNormalFieldValue(f, temp.getFieldValue(f));
								} else {
									if (gathers[f] != null)
										r.setNormalFieldValue(f, gathers[f].getNextBySeq(prevRecordSeq + 1));
								}
							}
							r.setRecordSeq(++prevRecordSeq);
							mems.add(r);
						}
						
						Table tmp = new Table(ds, ICursor.FETCHCOUNT);
						this.cache = tmp;
						mems = tmp.getMems();
						
						for (; i < recordCount; ++i) {
							for (int f = 0; f < colCount; ++f) {
								if (isField[f]) {
									temp.setNormalFieldValue(f, bufReaders[f].readObject());
								}
							}
							ComTableRecord r = new ComTableRecord(ds);
							for (int f = 0; f < retColCount; ++f) {
								if (exps[f] != null) {
									r.setNormalFieldValue(f, temp.calc(exps[f], ctx));
								} else if (isField[f]) {
									r.setNormalFieldValue(f, temp.getFieldValue(f));
								} else {
									if (gathers[f] != null)
										r.setNormalFieldValue(f, gathers[f].getNextBySeq(prevRecordSeq + 1));
								}
							}
							r.setRecordSeq(++prevRecordSeq);
							mems.add(r);
						}
						
						break;
					} else {
						for (int i = 0; i < recordCount; ++i) {
							for (int f = 0; f < colCount; ++f) {
								if (isField[f]) {
									temp.setNormalFieldValue(f, bufReaders[f].readObject());
								}
							}
							ComTableRecord r = new ComTableRecord(ds);
							for (int f = 0; f < retColCount; ++f) {
								if (exps[f] != null) {
									r.setNormalFieldValue(f, temp.calc(exps[f], ctx));
								} else if (isField[f]) {
									r.setNormalFieldValue(f, temp.getFieldValue(f));
								} else {
									if (gathers[f] != null)
										r.setNormalFieldValue(f, gathers[f].getNextBySeq(prevRecordSeq + 1));
								}
							}
							r.setRecordSeq(++prevRecordSeq);
							mems.add(r);
						}
						
						if (diff == recordCount) {
							break;
						}
					}
				}
			} else {
				FindFilter []findFilters = this.findFilters;
				ColumnMetaData []columns = this.columns;
				int []seqs = this.seqs;
				ObjectReader []segmentReaders = this.segmentReaders;
				int filterCount = filters.length;
				long []positions = new long[colCount];
				Object [][]filterValues = new Object[filterCount][];
				
				while (curBlock < endBlock) {
					curBlock++;
					int recordCount = rowCountReader.readInt32();
					boolean sign = true;
					int f = 0;
					for (; f < filterCount; ++f) {
						positions[f] = segmentReaders[f].readLong40();
						if (columns[f].hasMaxMinValues()) {
							Object minValue = segmentReaders[f].readObject();
							Object maxValue = segmentReaders[f].readObject();
							segmentReaders[f].skipObject();
							if (!filters[f].match(minValue, maxValue)) {
								++f;
								sign = false;
								break;
							}
						}
					}
					
					for (; f < colCount; ++f) {
						if (!isField[f]) continue;
						positions[f] = segmentReaders[f].readLong40();
						if (columns[f].hasMaxMinValues()) {
							segmentReaders[f].skipObject();
							segmentReaders[f].skipObject();
							segmentReaders[f].skipObject();
						}
					}
					
					if (!sign) {
						prevRecordSeq += recordCount;
						for (TableGather gather : gathers) {
							if (gather != null) {
								gather.skip();
							}
						}
						continue;
					}
					
					boolean []matchs = new boolean[recordCount];
					int matchCount = recordCount;
					for (int i = 0; i < recordCount; ++i) {
						matchs[i] = true;
					}

					for (f = 0; f < filterCount && matchCount > 0; ++f) {
						FindFilter findFilter = null;
						if (findFilters != null) {
							findFilter = findFilters[f];
						}
						
						Object []curValues = new Object[recordCount];
						filterValues[f] = curValues;
						IFilter filter = filters[f];
						BufferReader reader = colReaders[f].readBlockData(positions[f], recordCount);
						for (int i = 0; i < recordCount; ++i) {
							if (matchs[i]) {
								curValues[i] = reader.readObject();
								if (!filter.match(curValues[i])) {
									matchs[i] = false;
									matchCount--;
									if (matchCount == 0) {
										break;
									}
								} else if (findFilter != null) {
									curValues[i] = findFilter.getFindResult();
								}
							} else {
								reader.skipObject();
							}
						}
					}
					
					if (matchCount < 1) {
						prevRecordSeq += recordCount;
						for (TableGather gather : gathers) {
							if (gather != null) {
								gather.skip();
							}
						}
						continue;
					}
					for (TableGather gather : gathers) {
						if (gather != null) {
							gather.loadData();
						}
					}
					
					for (; f < colCount; ++f) {
						if (isField[f])
							bufReaders[f] = colReaders[f].readBlockData(positions[f], recordCount);
					}
					
					for (int i = 0; i < recordCount && matchCount > 0; ++i) {
						if (matchs[i]) {
							matchCount--;
							
							Record r = new Record(ds);
							for (f = 0; f < filterCount; ++f) {
								temp.setNormalFieldValue(f, filterValues[f][i]);
								if (seqs[f] >= 0) {
									r.setNormalFieldValue(seqs[f], filterValues[f][i]);
								}
							}
							for (; f < colCount; ++f) {
								if (isField[f]) {
									Object obj = bufReaders[f].readObject();
									if (seqs[f] >= 0) {
										r.setNormalFieldValue(seqs[f], obj);
									}
									temp.setNormalFieldValue(f, obj);
								}
							}
							
							for (f = 0; f < retColCount; ++f) {
								if (exps[f] != null) {
									r.setNormalFieldValue(f, temp.calc(exps[f], ctx));
								} else {
									if (gathers[f] != null)
										r.setNormalFieldValue(f, gathers[f].getNextBySeq(prevRecordSeq + i + 1));
								}
							}
							
							
							mems.add(r);
						} else {
							for (f = filterCount; f < colCount; ++f) {
								if (isField[f]) {
									bufReaders[f].skipObject();
								}
							}
						}
					}
					prevRecordSeq += recordCount;
					
					int diff = n - cache.length();
					if (diff < 0) {
						this.cache = (Sequence) cache.split(n + 1);
						break;
					} else if (diff == 0) {
						break;
					}
				}
			}
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		}
		
		this.curBlock = curBlock;
		this.prevRecordSeq = prevRecordSeq;
		if (cache.length() > 0) {
			return cache;
		} else {
			return null;
		}
	}
	
	private int getModifyRecord(int mindex, long endRecordSeq, Sequence result) {
		ArrayList modifyRecords = this.modifyRecords;
		int []findex = this.findex;
		DataStruct ds = this.ds;
		int colCount = findex.length;
		int mcount = this.mcount;
		
		for (; mindex < mcount; ++mindex) {
			ModifyRecord mr = modifyRecords.get(mindex);
			if (mr.getRecordSeq() <= endRecordSeq) {
				if (!mr.isDelete()) {
					Record sr = mr.getRecord();
					if (Variant.isTrue(sr.calc(filter, ctx))) {
						Record r = new Record(ds);
						for (int f = 0; f < colCount; ++f) {
							r.setNormalFieldValue(f, sr.getNormalFieldValue(findex[f]));
						}
						
						result.add(r);
					}
				}
			} else {
				break;
			}
		}
		
		return mindex;
	}
	
	protected Sequence getModify(int n) {
		Sequence cache = this.cache;
		if (cache != null) {
			int len = cache.length();
			if (len > n) {
				this.cache = (Sequence) cache.split(n + 1);
				return cache;
			} else if (len == n) {
				this.cache = null;
				return cache;
			}
		} else {
			cache = new Table(ds, getInitSize(n));
		}
		
		int curBlock = this.curBlock;
		int endBlock = this.endBlock;
		BlockLinkReader rowCountReader = this.rowCountReader;
		BlockLinkReader []colReaders = this.colReaders;
		int colCount = colReaders.length;
		BufferReader []bufReaders = new BufferReader[colCount];
		DataStruct ds = this.ds;
		IFilter []filters = this.filters;
		
		IArray mems = cache.getMems();
		this.cache = null;
		long prevRecordSeq = this.prevRecordSeq;
		ArrayList modifyRecords = this.modifyRecords;
		int []findex = this.findex;
		int findexLen = findex.length;
		int mindex = this.mindex;
		int mcount = this.mcount;
		
		ModifyRecord mr = modifyRecords.get(mindex);
		long mseq = mr.getRecordSeq();
				
		try {
			if (filters == null) {
				while (curBlock < endBlock) {
					curBlock++;
					int recordCount = rowCountReader.readInt32();
					for (int f = 0; f < colCount; ++f) {
						bufReaders[f] = colReaders[f].readBlockData(recordCount);
					}
					
					for (int i = 0; i < recordCount; ++i) {
						prevRecordSeq++;
						if (prevRecordSeq != mseq) {
							ComTableRecord r = new ComTableRecord(ds);
							for (int f = 0; f < colCount; ++f) {
								r.setNormalFieldValue(f, bufReaders[f].readObject());
							}
							
							r.setRecordSeq(prevRecordSeq);
							mems.add(r);
						} else {
							// ???ܲ??????
							boolean isInsert = true;
							while (true) {
								if (mr.isDelete()) {
									isInsert = false;
								} else {
									if (mr.isUpdate()) {
										isInsert = false;
									}
									
									Record sr = mr.getRecord();
									ComTableRecord r = new ComTableRecord(ds);
									for (int f = 0; f < findexLen; ++f) {
										r.setNormalFieldValue(f, sr.getNormalFieldValue(findex[f]));
									}
									
									r.setRecordSeq(-mseq);
									mems.add(r);
								}
								
								mindex++;
								if (mindex < mcount) {
									mr = modifyRecords.get(mindex);
									mseq = mr.getRecordSeq();
									if (prevRecordSeq != mseq) {
										break;
									}
								} else {
									mseq = -1;
									break;
								}
							}
							
							if (isInsert) {
								ComTableRecord r = new ComTableRecord(ds);
								for (int f = 0; f < colCount; ++f) {
									r.setNormalFieldValue(f, bufReaders[f].readObject());
								}
								
								r.setRecordSeq(prevRecordSeq);
								mems.add(r);
							} else {
								for (int f = 0; f < colCount; ++f) {
									bufReaders[f].skipObject();
								}
							}
						}
					}
					
					if (curBlock == endBlock && endBlock == table.getDataBlockCount()) {
						for (; mindex < mcount; ++mindex) {
							// ???ܴ????ڴ?׷?ӵļ?¼?ڲ???
							mr = modifyRecords.get(mindex);
							mseq = mr.getRecordSeq();
							Record sr = mr.getRecord();
							ComTableRecord r = new ComTableRecord(ds);
							for (int f = 0; f < findexLen; ++f) {
								r.setNormalFieldValue(f, sr.getNormalFieldValue(findex[f]));
							}
							
							r.setRecordSeq(-mseq);
							mems.add(r);
						}
					}
					
					int diff = n - cache.length();
					if (diff < 0) {
						this.cache = (Sequence) cache.split(n + 1);
						break;
					} else if (diff == 0) {
						break;
					}
				}
				
				if (table.getDataBlockCount() == 0 && startBlock == 0 && endBlock == 0) {
					// ???л?û??????????ʱ?п????ڲ?????????
					for (; mindex < mcount; ++mindex) {
						// ???ܴ????ڴ?׷?ӵļ?¼?ڲ???
						mr = modifyRecords.get(mindex);
						mseq = mr.getRecordSeq();
						Record sr = mr.getRecord();
						ComTableRecord r = new ComTableRecord(ds);
						for (int f = 0; f < findexLen; ++f) {
							r.setNormalFieldValue(f, sr.getNormalFieldValue(findex[f]));
						}
						
						r.setRecordSeq(-mseq);
						mems.add(r);
					}
					
					int diff = n - cache.length();
					if (diff < 0) {
						this.cache = (Sequence) cache.split(n + 1);
					}
				}
			} else {
				ColumnMetaData []columns = this.columns;
				int []seqs = this.seqs;
				FindFilter[] findFilters = this.findFilters;
				ObjectReader []segmentReaders = this.segmentReaders;
				int filterCount = filters.length;
				long []positions = new long[colCount];
				Object [][]filterValues = new Object[filterCount][];
				
				while (curBlock < endBlock) {
					curBlock++;
					int recordCount = rowCountReader.readInt32();
					boolean sign = true;
					int f = 0;
					for (; f < filterCount; ++f) {
						positions[f] = segmentReaders[f].readLong40();
						if (columns[f].hasMaxMinValues()) {
							Object minValue = segmentReaders[f].readObject();
							Object maxValue = segmentReaders[f].readObject();
							segmentReaders[f].skipObject();
							if (!filters[f].match(minValue, maxValue)) {
								++f;
								sign = false;
								break;
							}
						}
					}
					
					for (; f < colCount; ++f) {
						positions[f] = segmentReaders[f].readLong40();
						if (columns[f].hasMaxMinValues()) {
							segmentReaders[f].skipObject();
							segmentReaders[f].skipObject();
							segmentReaders[f].skipObject();
						}
					}
					
					if (!sign) {
						prevRecordSeq += recordCount;
						mindex = getModifyRecord(mindex, prevRecordSeq, cache);
						if (mindex < mcount) {
							mr = modifyRecords.get(mindex);
							mseq = mr.getRecordSeq();
						} else {
							mr = null;
							mseq = -1;
						}
						continue;
					}
					
					boolean []matchs = new boolean[recordCount];
					int matchCount = recordCount;
					for (int i = 0; i < recordCount; ++i) {
						matchs[i] = true;
					}
					
					for (f = 0; f < filterCount && matchCount > 0; ++f) {
						Object []curValues = new Object[recordCount];
						filterValues[f] = curValues;
						IFilter filter = filters[f];
						BufferReader reader = colReaders[f].readBlockData(positions[f], recordCount);
						for (int i = 0; i < recordCount; ++i) {
							if (matchs[i]) {
								curValues[i] = reader.readObject();
								if (!filter.match(curValues[i])) {
									matchs[i] = false;
									matchCount--;
									if (matchCount == 0) {
										break;
									}
								} else {
									if (seqs[f] != -1 && findFilters != null && findFilters[f] != null) {
										curValues[i] = findFilters[f].getFindResult();
									}
								}
							} else {
								reader.skipObject();
							}
						}
					}
					
					if (matchCount < 1) {
						prevRecordSeq += recordCount;
						mindex = getModifyRecord(mindex, prevRecordSeq, cache);
						if (mindex < mcount) {
							mr = modifyRecords.get(mindex);
							mseq = mr.getRecordSeq();
						} else {
							mr = null;
							mseq = -1;
						}
						continue;
					}
					
					for (; f < colCount; ++f) {
						bufReaders[f] = colReaders[f].readBlockData(positions[f], recordCount);
					}
					
					for (int i = 0; i < recordCount; ++i) {
						prevRecordSeq++;
						boolean isInsert = true;
						
						if (prevRecordSeq == mseq) {
							while (true) {
								if (mr.isDelete()) {
									isInsert = false;
								} else {
									if (mr.isUpdate()) {
										isInsert = false;
									}
									
									Record sr = mr.getRecord();
									if (Variant.isTrue(sr.calc(filter, ctx))) {
										Record r = new Record(ds);
										for (f = 0; f < findexLen; ++f) {
											r.setNormalFieldValue(f, sr.getNormalFieldValue(findex[f]));
										}
										
										mems.add(r);
									}
								}
								
								mindex++;
								if (mindex < mcount) {
									mr = modifyRecords.get(mindex);
									mseq = mr.getRecordSeq();
									if (prevRecordSeq != mseq) {
										break;
									}
								} else {
									mseq = -1;
									break;
								}
							}
						}
						
						if (isInsert && matchs[i]) {
							matchCount--;
							Record r = new Record(ds);
							for (f = 0; f < filterCount; ++f) {								
								if (seqs[f] != -1) {
									r.setNormalFieldValue(seqs[f], filterValues[f][i]);
								}
							}
							
							for (; f < colCount; ++f) {
								r.setNormalFieldValue(seqs[f], bufReaders[f].readObject());
							}
							
							mems.add(r);
						} else if (matchCount > 0) {
							for (f = filterCount; f < colCount; ++f) {
								bufReaders[f].skipObject();
							}
						}
					}
					
					if (curBlock == endBlock && endBlock == table.getDataBlockCount()) {
						for (; mindex < mcount; ++mindex) {
							// ???ܴ????ڴ?׷?ӵļ?¼?ڲ???
							mr = modifyRecords.get(mindex);
							Record sr = mr.getRecord();
							if (Variant.isTrue(sr.calc(filter, ctx))) {
								Record r = new Record(ds);
								for (f = 0; f < findexLen; ++f) {
									r.setNormalFieldValue(f, sr.getNormalFieldValue(findex[f]));
								}
								
								mems.add(r);
							}
						}
					}
					
					int diff = n - cache.length();
					if (diff < 0) {
						this.cache = (Sequence) cache.split(n + 1);
						break;
					} else if (diff == 0) {
						break;
					}
				}
				
				if (table.getDataBlockCount() == 0 && startBlock == 0 && endBlock == 0) {
					// ???л?û??????????ʱ?п????ڲ?????????
					for (; mindex < mcount; ++mindex) {
						// ???ܴ????ڴ?׷?ӵļ?¼?ڲ???
						mr = modifyRecords.get(mindex);
						Record sr = mr.getRecord();
						if (Variant.isTrue(sr.calc(filter, ctx))) {
							Record r = new Record(ds);
							for (int f = 0; f < findexLen; ++f) {
								r.setNormalFieldValue(f, sr.getNormalFieldValue(findex[f]));
							}
							
							mems.add(r);
						}
					}
					
					int diff = n - cache.length();
					if (diff < 0) {
						this.cache = (Sequence) cache.split(n + 1);
					}
				}
			}
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		}
		
		this.curBlock = curBlock;
		this.prevRecordSeq = prevRecordSeq;
		this.mindex = mindex;
				
		if (cache.length() > 0) {
			return cache;
		} else {
			return null;
		}
	}
	
	private Sequence getModify2(int n) {
		Sequence cache = this.cache;
		if (cache != null) {
			int len = cache.length();
			if (len > n) {
				this.cache = (Sequence) cache.split(n + 1);
				return cache;
			} else if (len == n) {
				this.cache = null;
				return cache;
			}
		} else {
			cache = new Table(ds, getInitSize(n));
		}
		
		int curBlock = this.curBlock;
		int endBlock = this.endBlock;
		BlockLinkReader rowCountReader = this.rowCountReader;
		BlockLinkReader []colReaders = this.colReaders;
		int colCount = colReaders.length;
		BufferReader []bufReaders = new BufferReader[colCount];
		DataStruct ds = this.ds;
		IFilter []filters = this.filters;
		
		IArray mems = cache.getMems();
		this.cache = null;
		long prevRecordSeq = this.prevRecordSeq;
		ArrayList modifyRecords = this.modifyRecords;
		int []findex = this.findex;
		int mindex = this.mindex;
		int mcount = this.mcount;
		
		ModifyRecord mr = modifyRecords.get(mindex);
		long mseq = mr.getRecordSeq();
		
		TableGather []gathers = this.gathers;
		boolean isField[] = this.isField;
		int retColCount = exps.length;
		Record temp = new Record(this.tempDs);
		Expression []exps = this.exps;
		Context ctx = this.ctx;
		
		try {
			if (filters == null) {
				while (curBlock < endBlock) {
					curBlock++;
					int recordCount = rowCountReader.readInt32();
					for (int f = 0; f < colCount; ++f) {
						if (isField[f]) {
							bufReaders[f] = colReaders[f].readBlockData(recordCount);
						}
					}
					
					for (TableGather gather : gathers) {
						if (gather != null) {
							gather.loadData();
						}
					}

					for (int i = 0; i < recordCount; ++i) {
						prevRecordSeq++;
						if (prevRecordSeq != mseq) {
							ComTableRecord r = new ComTableRecord(ds);
							for (int f = 0; f < colCount; ++f) {
								if (isField[f]) {
									temp.setNormalFieldValue(f, bufReaders[f].readObject());
								}
							}
							for (int f = 0; f < retColCount; ++f) {
								if (exps[f] != null) {
									r.setNormalFieldValue(f, temp.calc(exps[f], ctx));
								} else if (isField[f]) {
									r.setNormalFieldValue(f, temp.getFieldValue(f));
								} else {
									if (gathers[f] != null)
										r.setNormalFieldValue(f, gathers[f].getNextBySeq(prevRecordSeq));
								}
							}

							r.setRecordSeq(prevRecordSeq);
							mems.add(r);
						} else {
							// ???ܲ??????
							boolean isInsert = true;
							while (true) {
								if (mr.isDelete()) {
									isInsert = false;
								} else {
									if (mr.isUpdate()) {
										isInsert = false;
									}
									
									Record sr = mr.getRecord();
									ComTableRecord r = new ComTableRecord(ds);
									for (int f = 0; f < colCount; ++f) {
										if (exps[f] != null) {
											r.setNormalFieldValue(f, sr.calc(exps[f], ctx));
										} else if (isField[f]) {
											r.setNormalFieldValue(f, sr.getNormalFieldValue(findex[f]));
										} else {
											if (gathers[f] != null) {
												if (isInsert) {
													r.setNormalFieldValue(f, gathers[f].getNextBySeq(-(mindex + 1)));
												} else {
													r.setNormalFieldValue(f, gathers[f].getNextBySeq(prevRecordSeq));
												}
											}
										}
									}
									
									r.setRecordSeq(-mseq);
									mems.add(r);
								}
								
								mindex++;
								if (mindex < mcount) {
									mr = modifyRecords.get(mindex);
									mseq = mr.getRecordSeq();
									if (prevRecordSeq != mseq) {
										break;
									}
								} else {
									mseq = -1;
									break;
								}
							}
							
							if (isInsert) {
								ComTableRecord r = new ComTableRecord(ds);
								for (int f = 0; f < colCount; ++f) {
									if (isField[f]) {
										temp.setNormalFieldValue(f, bufReaders[f].readObject());
									}
								}
								for (int f = 0; f < retColCount; ++f) {
									if (exps[f] != null) {
										r.setNormalFieldValue(f, temp.calc(exps[f], ctx));
									} else if (isField[f]) {
										r.setNormalFieldValue(f, temp.getFieldValue(f));
									} else {
										if (gathers[f] != null)
											r.setNormalFieldValue(f, gathers[f].getNextBySeq(prevRecordSeq));
									}
								}
								r.setRecordSeq(prevRecordSeq);
								mems.add(r);
							} else {
								for (int f = 0; f < colCount; ++f) {
									if (isField[f]) {
										bufReaders[f].skipObject();
									}
								}
							}
						}
					}
					
					if (curBlock == endBlock && endBlock == table.getDataBlockCount()) {
						for (; mindex < mcount; ++mindex) {
							// ???ܴ????ڴ?׷?ӵļ?¼?ڲ???
							mr = modifyRecords.get(mindex);
							Record sr = mr.getRecord();
							ComTableRecord r = new ComTableRecord(ds);
							for (int f = 0; f < colCount; ++f) {
								if (exps[f] != null) {
									r.setNormalFieldValue(f, sr.calc(exps[f], ctx));
								} else if (isField[f]) {
									r.setNormalFieldValue(f, sr.getNormalFieldValue(findex[f]));
								} else {
									if (gathers[f] != null) {
										r.setNormalFieldValue(f, gathers[f].getNextBySeq(-(mindex + 1)));
									}
								}
							}
							
							r.setRecordSeq(-mseq);
							mems.add(r);
						}
					}
					
					int diff = n - cache.length();
					if (diff < 0) {
						this.cache = (Sequence) cache.split(n + 1);
						break;
					} else if (diff == 0) {
						break;
					}
				}
				
				if (table.getDataBlockCount() == 0 && startBlock == 0 && endBlock == 0) {
					// ???л?û??????????ʱ?п????ڲ?????????
					for (; mindex < mcount; ++mindex) {
						// ???ܴ????ڴ?׷?ӵļ?¼?ڲ???
						mr = modifyRecords.get(mindex);
						Record sr = mr.getRecord();
						ComTableRecord r = new ComTableRecord(ds);
						for (int f = 0; f < colCount; ++f) {
							if (exps[f] != null) {
								r.setNormalFieldValue(f, sr.calc(exps[f], ctx));
							} else if (isField[f]) {
								r.setNormalFieldValue(f, sr.getNormalFieldValue(findex[f]));
							} else {
								if (gathers[f] != null) {
									r.setNormalFieldValue(f, gathers[f].getNextBySeq(-(mindex + 1)));
								}
							}
						}
						
						r.setRecordSeq(-mseq);
						mems.add(r);
					}
				}
			} else {
				ColumnMetaData []columns = this.columns;
				int []seqs = this.seqs;
				ObjectReader []segmentReaders = this.segmentReaders;
				int filterCount = filters.length;
				long []positions = new long[colCount];
				Object [][]filterValues = new Object[filterCount][];
				
				while (curBlock < endBlock) {
					curBlock++;
					int recordCount = rowCountReader.readInt32();
					boolean sign = true;
					int f = 0;
					for (; f < filterCount; ++f) {
						positions[f] = segmentReaders[f].readLong40();
						if (columns[f].hasMaxMinValues()) {
							Object minValue = segmentReaders[f].readObject();
							Object maxValue = segmentReaders[f].readObject();
							segmentReaders[f].skipObject();
							if (!filters[f].match(minValue, maxValue)) {
								++f;
								sign = false;
								break;
							}
						}
					}
					
					for (; f < colCount; ++f) {
						if (!isField[f]) continue;
						positions[f] = segmentReaders[f].readLong40();
						if (columns[f].hasMaxMinValues()) {
							segmentReaders[f].skipObject();
							segmentReaders[f].skipObject();
							segmentReaders[f].skipObject();
						}
					}
					
					if (!sign) {
						prevRecordSeq += recordCount;
						mindex = getModifyRecord(mindex, prevRecordSeq, cache);
						if (mindex < mcount) {
							mr = modifyRecords.get(mindex);
							mseq = mr.getRecordSeq();
						} else {
							mr = null;
							mseq = -1;
						}
						for (TableGather gather : gathers) {
							if (gather != null) {
								gather.skip();
							}
						}
						continue;
					}
					
					boolean []matchs = new boolean[recordCount];
					int matchCount = recordCount;
					for (int i = 0; i < recordCount; ++i) {
						matchs[i] = true;
					}
					
					for (f = 0; f < filterCount && matchCount > 0; ++f) {
						Object []curValues = new Object[recordCount];
						filterValues[f] = curValues;
						IFilter filter = filters[f];
						BufferReader reader = colReaders[f].readBlockData(positions[f], recordCount);
						for (int i = 0; i < recordCount; ++i) {
							if (matchs[i]) {
								curValues[i] = reader.readObject();
								if (!filter.match(curValues[i])) {
									matchs[i] = false;
									matchCount--;
									if (matchCount == 0) {
										break;
									}
								}
							} else {
								reader.skipObject();
							}
						}
					}
					
					if (matchCount < 1) {
						prevRecordSeq += recordCount;
						mindex = getModifyRecord(mindex, prevRecordSeq, cache);
						if (mindex < mcount) {
							mr = modifyRecords.get(mindex);
							mseq = mr.getRecordSeq();
						} else {
							mr = null;
							mseq = -1;
						}
						for (TableGather gather : gathers) {
							if (gather != null) {
								gather.skip();
							}
						}
						continue;
					}
					for (TableGather gather : gathers) {
						if (gather != null) {
							gather.loadData();
						}
					}

					for (; f < colCount; ++f) {
						if (isField[f])
							bufReaders[f] = colReaders[f].readBlockData(positions[f], recordCount);
					}
					
					for (int i = 0; i < recordCount; ++i) {
						prevRecordSeq++;
						boolean isInsert = true;
						
						if (prevRecordSeq == mseq) {
							while (true) {
								if (mr.isDelete()) {
									isInsert = false;
								} else {
									if (mr.isUpdate()) {
										isInsert = false;
									}
									
									Record sr = mr.getRecord();
									if (Variant.isTrue(sr.calc(filter, ctx))) {
										Record r = new Record(ds);
//										for (f = 0; f < colCount; ++f) {
//											if (isField[f]) {
//												r.setNormalFieldValue(f, sr.getNormalFieldValue(findex[f]));
//											}
//										}
										for (f = 0; f < retColCount; ++f) {
											if (findex[f] >= 0) {
												r.setNormalFieldValue(f, sr.getNormalFieldValue(findex[f]));
											} else if (exps[f] != null) {
												r.setNormalFieldValue(f, sr.calc(exps[f], ctx));
											} else {
												if (gathers[f] != null) {
													if (isInsert) {
														r.setNormalFieldValue(f, gathers[f].getNextBySeq(-(mindex + 1)));
													} else {
														r.setNormalFieldValue(f, gathers[f].getNextBySeq(prevRecordSeq));
													}
												}
											}
										}
										mems.add(r);
									}
								}
								
								mindex++;
								if (mindex < mcount) {
									mr = modifyRecords.get(mindex);
									mseq = mr.getRecordSeq();
									if (prevRecordSeq != mseq) {
										break;
									}
								} else {
									mseq = -1;
									break;
								}
							}
						}
						
						if (isInsert && matchs[i]) {
							matchCount--;
							Record r = new Record(ds);
							for (f = 0; f < filterCount; ++f) {
								temp.setNormalFieldValue(f, filterValues[f][i]);
								if (seqs[f] >= 0) {
									r.setNormalFieldValue(seqs[f], filterValues[f][i]);
								}
							}
							for (; f < colCount; ++f) {
								if (isField[f]) {
									Object obj = bufReaders[f].readObject();
									if (seqs[f] >= 0) {
										r.setNormalFieldValue(seqs[f], obj);
									}
									temp.setNormalFieldValue(f, obj);
								}
							}
							
							for (f = 0; f < retColCount; ++f) {
								if (exps[f] != null) {
									r.setNormalFieldValue(f, temp.calc(exps[f], ctx));
								} else {
									if (gathers[f] != null)
										r.setNormalFieldValue(f, gathers[f].getNextBySeq(prevRecordSeq));
								}
							}

							mems.add(r);
						} else if (matchCount > 0) {
							for (f = filterCount; f < colCount; ++f) {
								if (isField[f]) {
									bufReaders[f].skipObject();
								}
							}
						}
					}
					
					if (curBlock == endBlock && endBlock == table.getDataBlockCount()) {
						for (; mindex < mcount; ++mindex) {
							// ???ܴ????ڴ?׷?ӵļ?¼?ڲ???
							mr = modifyRecords.get(mindex);
							Record sr = mr.getRecord();
							if (Variant.isTrue(sr.calc(filter, ctx))) {
								Record r = new Record(ds);
								for (f = 0; f < retColCount; ++f) {
									if (findex[f] >= 0) {
										r.setNormalFieldValue(f, sr.getNormalFieldValue(findex[f]));
									} else if (exps[f] != null) {
										r.setNormalFieldValue(f, sr.calc(exps[f], ctx));
									} else {
										if (gathers[f] != null) {
											r.setNormalFieldValue(f, gathers[f].getNextBySeq(-(mindex + 1)));
										}
									}
								}
								
								mems.add(r);
							}
						}
					}
					
					int diff = n - cache.length();
					if (diff < 0) {
						this.cache = (Sequence) cache.split(n + 1);
						break;
					} else if (diff == 0) {
						break;
					}
				}
				
				if (table.getDataBlockCount() == 0 && startBlock == 0 && endBlock == 0) {
					// ???л?û??????????ʱ?п????ڲ?????????
					for (; mindex < mcount; ++mindex) {
						// ???ܴ????ڴ?׷?ӵļ?¼?ڲ???
						mr = modifyRecords.get(mindex);
						Record sr = mr.getRecord();
						if (Variant.isTrue(sr.calc(filter, ctx))) {
							Record r = new Record(ds);
							for (int f = 0; f < retColCount; ++f) {
								if (findex[f] >= 0) {
									r.setNormalFieldValue(f, sr.getNormalFieldValue(findex[f]));
								} else if (exps[f] != null) {
									r.setNormalFieldValue(f, sr.calc(exps[f], ctx));
								} else {
									if (gathers[f] != null) {
										r.setNormalFieldValue(f, gathers[f].getNextBySeq(-(mindex + 1)));
									}
								}
							}
							
							mems.add(r);
						}
					}
				}
			}
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		}
		
		this.curBlock = curBlock;
		this.prevRecordSeq = prevRecordSeq;
		this.mindex = mindex;
				
		if (cache.length() > 0) {
			return cache;
		} else {
			return null;
		}
	}
	
	protected long skipOver(long n) {
		if (isClosed) {
			return 0;
		} else if (isFirstSkip && n == MAXSKIPSIZE && filter == null && fkNames == null && !isSegment) {
			return table.getActualRecordCount();
		}
		
		boolean isFirstSkip = this.isFirstSkip;
		this.isFirstSkip = false;
		long count = 0;
		
		// ?Ե??????????н????Ż????????ɼ?¼????
		if (gathers == null && mcount < 1 && n == MAXSKIPSIZE) {
			if (cache != null) {
				count = cache.length();
			}
			
			int curBlock = this.curBlock;
			int endBlock = this.endBlock;
			BlockLinkReader rowCountReader = this.rowCountReader;
			IFilter []filters = this.filters;
			int colCount = colReaders.length;
			
			try {
				if (filters == null) {
					while (curBlock < endBlock) {
						curBlock++;
						count += rowCountReader.readInt32();
					}
				} else if (filters.length == 1) {
					ColumnMetaData column = columns[0];
					ObjectReader segmentReader = segmentReaders[0];
					IFilter filter = filters[0];
					
					while (curBlock < endBlock) {
						curBlock++;
						int recordCount = rowCountReader.readInt32();
						
						long position = segmentReader.readLong40();
						if (column.hasMaxMinValues()) {
							Object minValue = segmentReader.readObject();
							Object maxValue = segmentReader.readObject();
							segmentReader.skipObject();
							if (!filter.match(minValue, maxValue)) {
								continue;
							}
						}
						
						BufferReader filterReader = colReaders[0].readBlockData(position, recordCount);
						for (int i = 0; i < recordCount; ++i) {
							// ????¼??ѭ????????е?BufferReaderû?в????????????????ǰҪ??????
							Object val = filterReader.readObject();
							if (filter.match(val)) {
								count++;
							}
						}
					}
				} else {
					int filterCount = filters.length;
					BlockLinkReader []colReaders = this.colReaders;
					BufferReader []bufReaders = new BufferReader[filterCount];
					ColumnMetaData []columns = this.columns;
					ObjectReader []segmentReaders = this.segmentReaders;
					long []positions = new long[colCount];
					
					while (curBlock < endBlock) {
						curBlock++;
						int recordCount = rowCountReader.readInt32();
						boolean sign = true;
						int f = 0;
						for (; f < filterCount; ++f) {
							positions[f] = segmentReaders[f].readLong40();
							if (columns[f].hasMaxMinValues()) {
								Object minValue = segmentReaders[f].readObject();
								Object maxValue = segmentReaders[f].readObject();
								segmentReaders[f].skipObject();
								if (!filters[f].match(minValue, maxValue)) {
									++f;
									sign = false;
									break;
								}
							}
						}
						
						for (; f < colCount; ++f) {
							positions[f] = segmentReaders[f].readLong40();
							if (columns[f].hasMaxMinValues()) {
								segmentReaders[f].skipObject();
								segmentReaders[f].skipObject();
								segmentReaders[f].skipObject();
							}
						}
						
						if (!sign) {
							continue;
						}
						
						int []nextRows = new int[filterCount]; // ÿ??bufReaders??һ??Ҫ???????У??????û????ǰҪ????????????
						for (f = 0; f < filterCount; ++f) {
							bufReaders[f] = null;
						}
						
						Next:
						for (int i = 0; i < recordCount; ++i) {
							// ????¼??ѭ????????е?BufferReaderû?в????????????????ǰҪ??????
							for (f = 0; f < filterCount; ++f) {
								if (bufReaders[f] == null) {
									bufReaders[f] = colReaders[f].readBlockData(positions[f], recordCount);
								}
								
								for (int j = nextRows[f]; j < i; ++j) {
									bufReaders[f].skipObject();
								}
								
								nextRows[f] = i + 1;
								if (!filters[f].match(bufReaders[f].readObject())) {
									continue Next;
								}
							}
							
							count++;
						}
					}
				}
			} catch (IOException e) {
				throw new RQException(e.getMessage(), e);
			}
			
			if (appendData != null) {
				count += appendData.length();
			}
			
			this.curBlock = curBlock;
			return count;
		} else if (filters == null && !hasModify() && isFirstSkip  && !isSegment && gathers == null && appendData == null) {
			//??û?й??˵?????Ż?
			
			//????cache
			Sequence cache = this.cache;
			if (cache != null) {
				int len = cache.length();
				if (n <= len) {
					get((int) n);
					return n;
				} else {
					get(len);
					count += len;
				}
			}
			
			//????
			int curBlock = this.curBlock;
			int endBlock = this.endBlock;
			BlockLinkReader rowCountReader = this.rowCountReader;
			BlockLinkReader []colReaders = this.colReaders;
			int colCount = colReaders.length;
			BufferReader []bufReaders = new BufferReader[colCount];
			ColumnMetaData []columns = this.columns;
			ObjectReader []segmentReaders = new ObjectReader[colCount];
			for (int i = 0; i < colCount; ++i) {
				segmentReaders[i] = columns[i].getSegmentReader();
			}
			
			long[] positions = new long[colCount];
			try {
				while (curBlock < endBlock) {
					curBlock++;
					int recordCount = rowCountReader.readInt32();
					for (int i = 0; i < colCount; i++) {
						positions[i] = segmentReaders[i].readLong40();
						if (columns[i].hasMaxMinValues()) {
							segmentReaders[i].skipObject();
							segmentReaders[i].skipObject();
							segmentReaders[i].skipObject();
						}
					}
					
					if (count + recordCount == n) {
						for (int f = 0; f < colCount; ++f) {
							colReaders[f].readBlockData(positions[f], recordCount);
						}
						this.curBlock = curBlock;
						return n;
					} else if (count + recordCount > n) {
						//cache = new Table(ds, recordCount);
						//IArray mems = cache.getMems();
						
						long diff = n - count;
						for (int f = 0; f < colCount; ++f) {
							bufReaders[f] = colReaders[f].readBlockData(positions[f], recordCount);
						}

						int i = 0;
						for (; i < diff; ++i) {
							for (int f = 0; f < colCount; ++f) {
								bufReaders[f].skipObject();
							}
							++prevRecordSeq;
						}
						
						Table tmp = new Table(ds, ICursor.FETCHCOUNT);
						this.cache = tmp;
						IArray mems = tmp.getMems();
						
						for (; i < recordCount; ++i) {
							ComTableRecord r = new ComTableRecord(ds);
							for (int f = 0; f < colCount; ++f) {
								r.setNormalFieldValue(f, bufReaders[f].readObject());
							}
							r.setRecordSeq(++prevRecordSeq);
							mems.add(r);
						}
						this.curBlock = curBlock;
						return n;
					}
					count += recordCount;
				}
				this.curBlock = curBlock;
				return count;
			} catch (IOException e) {
				throw new RQException(e.getMessage(), e);
			}
			
		} else {
			Sequence data;
			long rest = n;
			while (rest != 0) {
				if (rest > FETCHCOUNT) {
					data = get(FETCHCOUNT);
				} else {
					data = get((int)rest);
				}
				
				if (data == null) {
					break;
				} else {
					count += data.length();
				}
				
				rest -= data.length();
			}
			return count;
		}
	}
	
	public void close() {
		if (isClosed) {
			return;
		}
		
		super.close();
		isClosed = true;
		cache = null;
		
		try {
			if (segmentReaders != null) {
				for (ObjectReader reader : segmentReaders) {
					if (reader != null) {
						reader.close();
					}
				}
			}
		} catch (Exception e) {
			throw new RQException(e.getMessage(), e);
		} finally {
			rowCountReader = null;
			colReaders = null;
			segmentReaders = null;
		}
	}
	
	public boolean reset() {
		close();
		
		isClosed = false;
		curBlock = 0;
		int endBlock = this.endBlock;
		prevRecordSeq = 0;
		mindex = 0;
		isFirstSkip = true;
		exps = Operation.dupExpressions(expsBakup, ctx);
		if (appendData != null && appendData.length() > 0) {
			appendIndex = 1;
		}
		
		init();
		if (isSegment) {
			setSegment(startBlock, endBlock);
		}
		return true;
	}
	
	public void setSegment(boolean isSegment) {
		this.isSegment = isSegment;
	}

	public boolean isSegment() {
		return isSegment;
	}
	
	public boolean hasModify() {
		return mindex < mcount;
	}
	
	public void setCache(Sequence cache) {
		if (this.cache != null) {
			cache.addAll(this.cache);
			this.cache = (Sequence) cache;
		} else {
			this.cache = (Sequence) cache;	
		}
	}
	
	public Sequence getCache() {
		return cache;
	}

	public String[] getSortFields() {
		return sortedFields;
	}
	
	private void initExps(Expression exps[]) {
		if (exps != null) {
			int colCount = exps.length;
			fields = new String[colCount];
			int cnt = 0;
			for (int i = 0; i < colCount; ++i) {
				if (exps[i] == null) {
					exps[i] = Expression.NULL;
				}

				if (exps[i].getHome() instanceof UnknownSymbol) {
					fields[i] = exps[i].getIdentifierName();
					cnt++;
				}
			}
			if (cnt == colCount) {
				exps = null;
			}
		}
		
		if (exps != null) {
			this.exps = Operation.dupExpressions(exps, ctx);
			expsBakup = Operation.dupExpressions(exps, ctx);
		}
	}

	public int getCurBlock() {
		return curBlock;
	}

	public void setCurBlock(int curBlock) {
		this.curBlock = curBlock;
	}
	
	public int getStartBlock() {
		return startBlock;
	}

	public int getEndBlock() {
		return endBlock;
	}

	public void setEndBlock(int endBlock) {
		this.endBlock = endBlock;
	}

	public BlockLinkReader getRowCountReader() {
		return rowCountReader;
	}

	public void setRowCountReader(BlockLinkReader rowCountReader) {
		this.rowCountReader = rowCountReader;
	}

	public BlockLinkReader [] getColReaders() {
		return colReaders;
	}

	public void setColReaders(BlockLinkReader [] colReaders) {
		this.colReaders = colReaders;
	}

	public IFilter [] getFilters() {
		return filters;
	}

	public void setFilters(IFilter [] filters) {
		this.filters = filters;
	}

	public FindFilter [] getFindFilters() {
		return findFilters;
	}

	public void setFindFilters(FindFilter [] findFilters) {
		this.findFilters = findFilters;
	}

	public ColumnMetaData [] getColumns() {
		return columns;
	}

	public void setColumns(ColumnMetaData [] columns) {
		this.columns = columns;
	}

	public int [] getSeqs() {
		return seqs;
	}

	public void setSeqs(int [] seqs) {
		this.seqs = seqs;
	}

	public ObjectReader [] getSegmentReaders() {
		return segmentReaders;
	}

	public void setSegmentReaders(ObjectReader [] segmentReaders) {
		this.segmentReaders = segmentReaders;
	}

	public boolean isClosed() {
		return isClosed;
	}
	
	public boolean canSkipBlock() {
		if (filters != null)
			return true;
		else
			return false;
	}
	
	public IArray[] getSkipBlockInfo(String key) {
		int curBlock = this.curBlock;
		int endBlock = this.endBlock;
		int initSize = endBlock - curBlock + 1;
		
		IFilter []filters = this.filters;
		int filterCount = filters.length;
		ColumnMetaData []columns = this.columns;
		int colCount = columns.length;
		
		int keyIndex = -1;
		for (int i = 0; i < colCount; i++) {
			if (columns[i].getColName().equals(key)) {
				keyIndex = i;
			}
		}
		
		ObjectArray minArray = new ObjectArray(initSize);
		ObjectArray maxArray = new ObjectArray(initSize);
		if (cache != null) {
			DataStruct tempDs = new DataStruct(fields);
			int idx = tempDs.getFieldIndex(key);
			Sequence cacheData = this.cache;
			int len = cacheData.length();
			minArray.add(((BaseRecord)cacheData.get(1)).getNormalFieldValue(idx));
			maxArray.add(((BaseRecord)cacheData.get(len)).getNormalFieldValue(idx));
		}
		
		//??¡?ֶ?reader
		ObjectReader[] segmentReaders = new ObjectReader[colCount];
		for (int i = 0; i < colCount; i++) {
			ObjectReader segmentReader = new ObjectReader(this.segmentReaders[i]);
			BlockLinkReader reader = (BlockLinkReader) segmentReader.getInputStream();
			segmentReader.setInputStream(new BlockLinkReader(reader));
			segmentReaders[i] = segmentReader;
		}
		
		boolean hasSkip = false;
		try {
			Object keyMinValue = null;
			Object keyMaxValue = null;
			while (curBlock < endBlock) {
				curBlock++;
				boolean sign = true;
				int f = 0;
				for (; f < filterCount; ++f) {
					segmentReaders[f].readLong40();
					if (columns[f].hasMaxMinValues()) {
						Object minValue = segmentReaders[f].readObject();
						Object maxValue = segmentReaders[f].readObject();
						segmentReaders[f].skipObject();
						if (f == keyIndex) {
							keyMinValue = minValue;
							keyMaxValue = maxValue;
						}
						if (!filters[f].match(minValue, maxValue)) {
							++f;
							sign = false;
							break;
						}
					}
				}
				
				for (; f < colCount; ++f) {
					if (f == keyIndex) {
						segmentReaders[f].readLong40();
						if (columns[f].hasMaxMinValues()) {
							keyMinValue = segmentReaders[f].readObject();
							keyMaxValue = segmentReaders[f].readObject();
							segmentReaders[f].skipObject();
						}
					} else {
						segmentReaders[f].readLong40();
						if (columns[f].hasMaxMinValues()) {
							segmentReaders[f].skipObject();
							segmentReaders[f].skipObject();
							segmentReaders[f].skipObject();
						}
					}
				}
				
				if (sign) {
					//û????
					minArray.add(keyMinValue);
					maxArray.add(keyMaxValue);
				} else {
					hasSkip = true;
				}
			}
			
			for (int i = 0; i < colCount; i++) {
				segmentReaders[i].close();
			}
			
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		}
		
		if (!hasSkip) {
			//???û?????Σ???û??????
			return null;
		}
		
		if (appendData != null) {
			DataStruct tempDs = new DataStruct(fields);
			int idx = tempDs.getFieldIndex(key);
			Sequence appendData = this.appendData;
			int len = appendData.length();
			minArray.add(((BaseRecord)appendData.get(1)).getNormalFieldValue(idx));
			maxArray.add(((BaseRecord)appendData.get(len)).getNormalFieldValue(idx));
		}
		
		if (minArray.size() == 0) {
			//????????????жΣ???û??????
			return null;
		}
		
		IArray[] result = new IArray[] {minArray, maxArray};
		return result;
	}
	
	/**
	 * ???α?????Ϊ????key???? ??pjoinʱʹ?ã?
	 * ???ú??α?ᰴ??values???ֵ???????顣
	 * @param key ά?ֶ???
	 * @param values [minValue, maxValue] 
	 */
	public void setSkipBlockInfo(String key, IArray[] values) {
		if (values == null || key == null) {
			return;
		}
		int idx = ds.getFieldIndex(key);
		if (idx < 0) {
			MessageManager mm = EngineMessage.get();
			throw new RQException(key + mm.getMessage("ds.fieldNotExist"));
		}
		
		ColumnMetaData column = table.getColumn(key); 
		IFilter filter = new BlockFilter(column, values);

		if (filters == null) {
			filters = new IFilter[] { filter };
			
			//??ά???ᵽ??ǰ??
			ColumnMetaData []columns = this.columns;
			ColumnMetaData tempCol = columns[0];
			columns[0] = columns[idx];
			columns[idx] = tempCol;
			
			BlockLinkReader[] columnReaders = this.colReaders;
			BlockLinkReader temp = columnReaders[0];
			columnReaders[0] = columnReaders[idx];
			columnReaders[idx] = temp;

			int colCount = columnReaders.length;
			ObjectReader []segmentReaders = new ObjectReader[colCount];
			for (int i = 0; i < colCount; ++i) {
				if (columns[i] != null) {
					segmentReaders[i] = columns[i].getSegmentReader();
				}
			}
			seqs = new int [colCount];
			DataStruct ds = new DataStruct(fields);
			for (int i = 0; i < colCount; ++i) {
				ColumnMetaData col = columns[i];
				if (col != null) {
					seqs[i] = ds.getFieldIndex(col.getColName());
				} else {
					seqs[i] = -1;
				}
			}
			
			int startBlock = this.startBlock;
			long prevRecordSeq = 0;
			BlockLinkReader rowCountReader = this.rowCountReader;
			
			try {
				for (int i = 0; i < startBlock; ++i) {
					prevRecordSeq += rowCountReader.readInt32();
					for (int f = 0; f < colCount; ++f) {
						if (segmentReaders[f] != null) {
							segmentReaders[f].readLong40();
							if (columns[f].hasMaxMinValues()) {
								segmentReaders[f].skipObject();
								segmentReaders[f].skipObject();
								segmentReaders[f].skipObject();
							}
						}
					}
				}
				this.segmentReaders = segmentReaders;
				this.prevRecordSeq = prevRecordSeq;
			} catch (IOException e) {
				throw new RQException(e.getMessage(), e);
			}
		} else {
			int size = filters.length;
			
			//??????Ժϲ???????filter
			for (int i = 0; i < size; i++) {
				IFilter f = filters[i];
				if (f.isSameColumn(filter)) {
					filters[i] = new LogicAnd(f, filter);
					return;
				}
			}
			
			//?ҵ?Ŀǰ??λ??
			ColumnMetaData []columns = this.columns;
			BlockLinkReader []columnReaders = this.colReaders;
			int len = columnReaders.length;
			String colName = key;
			for (int i = 0; i < len; i++) {
				if (columns[i].getColName().equals(colName)) {
					idx = i;
					break;
				}
			}
			
			//???뵽filters??
			IFilter[] filters = this.filters;
			FindFilter[] findFilters = this.findFilters;
			IFilter[] newFilters = new IFilter[size + 1];
			FindFilter[] newFindFilters = null;
			if (findFilters != null) {
				newFindFilters = new FindFilter[size + 1];
			}
			
			for (int i = 0; i < size; i++) {
				if (newFindFilters != null) {
					newFindFilters[i + 1] = findFilters[i];
				}
				newFilters[i + 1] = filters[i];				
			}
			newFilters[0] = filter;
			
			this.filters = newFilters;
			this.findFilters = newFindFilters;
			
			//?????е?λ??
			BlockLinkReader temp = columnReaders[idx];
			System.arraycopy(columnReaders, 0, columnReaders, 1, idx);
			columnReaders[0] = temp;
			
			ColumnMetaData tempCol = columns[idx];
			System.arraycopy(columns, 0, columns, 1, idx);
			columns[0] = tempCol;
			
			ObjectReader []segmentReaders = this.segmentReaders;
			ObjectReader tempReader = segmentReaders[idx];
			System.arraycopy(segmentReaders, 0, segmentReaders, 1, idx);
			segmentReaders[0] = tempReader;
			
			DataStruct ds = new DataStruct(fields);
			int colCount = columns.length;
			int[] seqs = new int [colCount];
			for (int i = 0; i < colCount; ++i) {
				seqs[i] = ds.getFieldIndex(columns[i].getColName());
			}
			this.seqs = seqs;
		}
	}
	
	protected Sequence getStartBlockData(int n) {
		// ֻȡ??һ??ļ?¼???????һ??û???????????ľͷ???
		if (startBlock >= endBlock) {
			Sequence result = appendData;
			appendData = null;
			appendIndex = 0;
			return result;
		}
		
		int startBlock = this.startBlock;
		int endBlock = this.endBlock;
		try {
			setEndBlock(startBlock + 1);
			
			Sequence seq;
			if (gathers == null) {
				seq = getData(n);
			} else {
				seq = getData2(n);
			}
			isFirstSkip = false;
			
			return seq;
		} finally {
			setEndBlock(endBlock);
		}
	}
	
	public TableGather[] getGathers() {
		return gathers;
	}
}