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

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

Go to download

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

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

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;

import com.scudata.array.IArray;
import com.scudata.common.MessageManager;
import com.scudata.common.RQException;
import com.scudata.dm.ComputeStack;
import com.scudata.dm.Context;
import com.scudata.dm.DataStruct;
import com.scudata.dm.Env;
import com.scudata.dm.FileObject;
import com.scudata.dm.LongArray;
import com.scudata.dm.ObjectReader;
import com.scudata.dm.ObjectWriter;
import com.scudata.dm.RandomObjectWriter;
import com.scudata.dm.RandomOutputStream;
import com.scudata.dm.Record;
import com.scudata.dm.Sequence;
import com.scudata.dm.Table;
import com.scudata.dm.cursor.*;
import com.scudata.expression.*;
import com.scudata.expression.fn.string.Like;
import com.scudata.expression.mfn.sequence.Contain;
import com.scudata.expression.operator.*;
import com.scudata.resources.EngineMessage;
import com.scudata.util.EnvUtil;
import com.scudata.util.Variant;

/**
 * ????????
 * @author runqian
 *
 */
public class PhyTableIndex implements ITableIndex {
	private static final int NULL = -1;
	private static final int EQ = 0; // ????
	private static final int GE = 1; // ???ڵ???
	private static final int GT = 2; // ????
	private static final int LE = 3; // С?ڵ???
	private static final int LT = 4; // С??
	private static final int LIKE = 5;
	
	protected static final int BUFFER_SIZE = 1024;
	protected static final int BLOCK_START = -1;
	protected static final int BLOCK_END = -2;
	
	public static final int MAX_LEAF_BLOCK_COUNT = 1000;//Ҷ?ӽ???????¼??
	public static final int MAX_INTER_BLOCK_COUNT = 1000;//?м????????¼??
	public static final int MAX_ROOT_BLOCK_COUNT = 1000;//
	public static final int MAX_SEC_RECORD_COUNT = 100000;//max count of index2
	
	public static final int FETCH_SIZE = 20;//һ??ȡ20?????
	
	protected long recordCount = 0; // Դ??¼??
	protected long index1RecordCount = 0; // ????1??¼??
	protected long index1EndPos = 0; // ????1????ʱԴ?ļ???¼????λ??
	protected String []ifields; // ?????ֶ?????
	
	protected String name;
	protected PhyTable srcTable;
	protected FileObject indexFile;
	
	// ????ʱʹ??
	protected Object []rootBlockMaxVals; // ÿһ??????ֵ
	protected long []rootBlockPos; // ÿһ???λ??	
	protected long internalBlockCount = 0;
	protected Object [][]internalAllBlockMaxVals; // ?м?ڵ????п?????ֵ
	protected long [][]internalAllBlockPos; // ?м?ڵ????п??λ?õĻ???

	protected Object []rootBlockMaxVals2; // ÿһ??????ֵ
	protected long []rootBlockPos2; // ÿһ???λ??	
	protected long internalBlockCount2 = 0;
	protected Object [][]internalAllBlockMaxVals2; // ?м?ڵ????п?????ֵ
	protected long [][]internalAllBlockPos2; // ?м?ڵ????п??λ??
	
	protected long rootItPos = 0;//1st root node pos
	protected long rootItPos2 = 0;// sec root node pos
	protected long indexPos = 0;//sec index pos
	protected long indexPos2 = 0;//sec index pos
	
	//?????㻺??󣬲???????internalAllBlockPos??Ҫ?????
	protected transient byte [][][]cachedBlockReader;
	protected transient byte [][][]cachedBlockReader2;
	protected transient boolean isPrimaryKey;//?Ƿ????????????????
	protected transient int maxRecordLen;
	protected Expression filter;
	
	protected int positionCount;//ÿһ????????¼?ĵ?ַ???????д???0???д??????1???д渽????2

	private class FieldFilter {
		private Object startVal;
		private Object endVal;
		private int startSign = NULL;
		private int endSign = NULL;
	}
	
	private class BlockInfo {
		private Object []internalBlockMaxVals;
		private long []internalBlockPos;
	}
	
	/**
	 * ???ڽ???????ʱȡ????α?ţ???????????
	 * @author runqian
	 *
	 */
	protected class CTableCursor extends ICursor {
		public static final String POS_FIELDNAME = "rq_file_pos_";
		private ColPhyTable table;
		private String []fields;
		private Expression filter;
		
		DataStruct ds;
		private BlockLinkReader rowCountReader;
		private BlockLinkReader []colReaders;
		private ObjectReader []segmentReaders;
		private ColumnMetaData []columns;
		
		private int dataBlockCount;
		private int curBlock = 0;
		private Sequence cache;
		private boolean isClosed = false;
		
		private long curNum = 0;//ȫ?ּ?¼??
		
		public CTableCursor(PhyTable table, String []fields, Context ctx, Expression filter) {
			this.table = (ColPhyTable) table;
			this.fields = fields;
			this.ctx = ctx;
			this.filter = filter;
			
			init();
		}
		
		private void init() {
			dataBlockCount = table.getDataBlockCount();

			if (fields == null) {
				fields = table.getColNames();
			}
			
			//??????????ʽʱҪȡ??????
			if (filter != null) {
				columns = table.getColumns();
			} else {
				columns = table.getColumns(fields);
			}
			
			String []fields = Arrays.copyOf(this.fields, this.fields.length + 1);
			fields[this.fields.length] = POS_FIELDNAME;
			ds = new DataStruct(fields);
			int colCount = columns.length;
			
			rowCountReader = table.getSegmentReader();
			colReaders = new BlockLinkReader[colCount];
			
			for (int i = 0; i < colCount; ++i) {
				colReaders[i] = columns[i].getColReader(true);
			}
			segmentReaders = new ObjectReader[colCount];
			for (int i = 0; i < colCount; ++i) {
				segmentReaders[i] = columns[i].getSegmentReader();
			}
		}
		
		protected Sequence get(int n) {
			if (isClosed || n < 1) {
				return null;
			}
			
			Sequence cache = this.cache;
			if (cache != null) {
				int len = cache.length();
				if (len > n) {
					this.cache = cache.split(n + 1);
					return cache;
				} else if (len == n) {
					this.cache = null;
					return cache;
				}
			} else {
				cache = new Table(ds, n);
			}
			
			int curBlock = this.curBlock;
			int dataBlockCount = this.dataBlockCount;
			BlockLinkReader rowCountReader = this.rowCountReader;
			BlockLinkReader []colReaders = this.colReaders;
			int colCount = colReaders.length;
			BufferReader []bufReaders = new BufferReader[colCount];
			DataStruct ds = this.ds;
			
			IArray mems = cache.getMems();
			this.cache = null;
			
			ComputeStack stack = null;
			Expression filter = this.filter;
			DataStruct fullDs = null;
			String []fields = this.fields;
			int fieldsLen = fields.length;
			int []fieldsIndex = new int[fieldsLen];
			
			if (filter != null) {
				stack = ctx.getComputeStack();
				String[] fullFields = table.getColNames();
				fullDs = new DataStruct(fullFields);
				for (int i = 0; i < fieldsLen; ++i) {
					fieldsIndex[i] = fullDs.getFieldIndex(fields[i]);
				}
			}
			try {
				while (curBlock < dataBlockCount) {
					curBlock++;

					if (filter != null) {
						int recordCount = rowCountReader.readInt32();
						for (int f = 0; f < colCount; ++f) {
							bufReaders[f] = colReaders[f].readBlockData(recordCount);
						}
						
						int i;
						for (i = 0; i < recordCount; ++i) {
							Record r = new Record(ds);
							Record cmpr = new Record(fullDs);
							++curNum;
							for (int f = 0; f < colCount; ++f) {
								cmpr.setNormalFieldValue(f, bufReaders[f].readObject());
							}
							stack.push(cmpr);
							Object b = filter.calculate(ctx);
							if (Variant.isTrue(b)) {
								for (int f = 0; f < fieldsLen; ++f) {
									r.setNormalFieldValue(f, cmpr.getFieldValue(fieldsIndex[f]));
								}
								r.setNormalFieldValue(fieldsLen, new Long(curNum));
								mems.add(r);
							}
							stack.pop();
							if (mems.size() == n) {
								i++;
								break;
							}
						}
						if (mems.size() == n) {
							Table tmp = new Table(ds, ICursor.FETCHCOUNT);
							this.cache = tmp;
							mems = tmp.getMems();
							for (; i < recordCount; ++i) {
								Record r = new Record(ds);
								Record cmpr = new Record(fullDs);
								++curNum;
								for (int f = 0; f < colCount; ++f) {
									cmpr.setNormalFieldValue(f, bufReaders[f].readObject());
								}
								stack.push(cmpr);
								Object b = filter.calculate(ctx);
								if (Variant.isTrue(b)) {
									for (int f = 0; f < fieldsLen; ++f) {
										r.setNormalFieldValue(f, cmpr.getFieldValue(fieldsIndex[f]));
									}
									r.setNormalFieldValue(fieldsLen, new Long(curNum));
									mems.add(r);
								}
								stack.pop();
								if (mems.size() == n) {
									i++;
									break;
								}
							}
							if (mems.size() == 0) this.cache = null;
							break;
						}
						continue;
					}
					
					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) {
							Record r = new Record(ds);
							for (int f = 0; f < colCount; ++f) {
								r.setNormalFieldValue(f, bufReaders[f].readObject());
							}
							r.setNormalFieldValue(colCount, new Long(++curNum));
							mems.add(r);
						}
						
						Table tmp = new Table(ds, ICursor.FETCHCOUNT);
						this.cache = tmp;
						mems = tmp.getMems();
						
						for (; i < recordCount; ++i) {
							Record r = new Record(ds);
							for (int f = 0; f < colCount; ++f) {
								r.setNormalFieldValue(f, bufReaders[f].readObject());
							}
							r.setNormalFieldValue(colCount, new Long(++curNum));
							mems.add(r);
						}
						
						break;
					} else {
						for (int i = 0; i < recordCount; ++i) {
							Record r = new Record(ds);
							for (int f = 0; f < colCount; ++f) {
								r.setNormalFieldValue(f, bufReaders[f].readObject());
							}
							r.setNormalFieldValue(colCount, new Long(++curNum));
							mems.add(r);
						}
						
						if (diff == recordCount) {
							break;
						}
					}
				}
			} catch (IOException e) {
				throw new RQException(e.getMessage(), e);
			}
			
			this.curBlock = curBlock;
			if (cache.length() > 0) {
				return cache;
			} else {
				return null;
			}
		}
		
		protected long skipOver(long n) {
			return 0;
		}
		public long seek(long n) {
			if (isClosed || n < 1) {
				return 0;
			}

			int curBlock = this.curBlock;
			int dataBlockCount = this.dataBlockCount;
			
			long skipCount = 0;
			if (cache != null) {
				skipCount = cache.length();
				if (skipCount > n) {
					this.cache = cache.split((int)n + 1);
					return n;
				} else if (skipCount == n) {
					this.cache = null;
					return n;
				} else {
					this.cache = null;
				}
			}

			BlockLinkReader rowCountReader = this.rowCountReader;
			BlockLinkReader []colReaders = this.colReaders;
			int colCount = colReaders.length;
			long pos;

			try {
				//seek to first block
				for(int i = 0; i < colCount; i++) {
					pos = segmentReaders[i].readLong40();
					if (columns[i].hasMaxMinValues()) {
						segmentReaders[i].skipObject();
						segmentReaders[i].skipObject();
						segmentReaders[i].skipObject();
					}
					colReaders[i].seek(pos);
				}
				
				while (curBlock < dataBlockCount) {
					curBlock++;
					int recordCount = rowCountReader.readInt32();
					long diff = n - skipCount;
					if (recordCount > diff) {
						//never run to here
						diff = diff / 0;
					} else {
						for(int i = 0; i < colCount; i++) {
							pos = segmentReaders[i].readLong40();
							if (columns[i].hasMaxMinValues()) {
								segmentReaders[i].skipObject();
								segmentReaders[i].skipObject();
								segmentReaders[i].skipObject();
							}
							colReaders[i].seek(pos);
						}
						skipCount += recordCount;
						if (diff == recordCount) {
							break;
						}
					}
				}
				
			} catch (IOException e) {
				throw new RQException(e.getMessage(), e);
			}
			
			curNum += skipCount;
			this.curBlock = curBlock;
			return skipCount;
		}
		
		public void close() {
			super.close();
			isClosed = true;
			cache = null;
			
			try {
				if (segmentReaders != null) {
					for (ObjectReader reader : segmentReaders) {
						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;
			return true;
		}

	}
	
	protected class RTableCursor extends ICursor {
		public static final String POS_FIELDNAME = "rq_file_pos_";
		public static final String SEQ_FIELDNAME = "rq_file_seq_";
		private long blockSize;
		private RowPhyTable table;
		private String []fields;
		private Expression filter;
		
		DataStruct ds;
		private BlockLinkReader rowReader;
		private ObjectReader segmentReader;
		private ObjectReader rowDataReader;
		
		private int dataBlockCount;
		private int curBlock = 0;
		private Sequence cache;
		private boolean isClosed = false;
		private boolean isPrimaryTable; // ?Ƿ?????
		
		private RTableCursor parentCursor;//?????α?
		private Record curPkey;
		private long pseq;
		
		private DataStruct fullDs;
		private int []fieldsIndex;
		private boolean []needRead;
		
		public RTableCursor(PhyTable table, String []fields, Context ctx, Expression filter) {
			this.table = (RowPhyTable) table;
			this.fields = fields;
			this.ctx = ctx;
			this.filter = filter;
			
			init();
		}
		//filter????ֶ?Ҫ??????
		private void parseFilter(Node node) {
			if (node == null) return;
			if (node instanceof UnknownSymbol) {
				String f = ((UnknownSymbol) node).getName();
				int id = fullDs.getFieldIndex(f);
				if (id >= 0) needRead[id] = true;
				return;
			}
			parseFilter(node.getLeft());
			parseFilter(node.getRight());
		}
		
		private void init() {
			dataBlockCount = table.getDataBlockCount();

			if (fields == null) {
				fields = table.getColNames();
			}
			
			rowReader = table.getRowReader(true);
			rowDataReader = new ObjectReader(rowReader, table.groupTable.getBlockSize() - ComTable.POS_SIZE);
			segmentReader = table.getSegmentObjectReader();
			blockSize = table.groupTable.getBlockSize() - ComTable.POS_SIZE;
			
			isPrimaryTable = table.parent == null;
			int len = this.fields.length;
			String []fields;
			if (isPrimaryTable) {
				len += 2;
				fields = Arrays.copyOf(this.fields, len);
				fields[len - 2] = SEQ_FIELDNAME;
				fields[len - 1] = POS_FIELDNAME;
			} else {
				len += 3;
				fields = Arrays.copyOf(this.fields, len);
				fields[len - 3] = SEQ_FIELDNAME;
				fields[len - 2] = POS_FIELDNAME + 0;
				fields[len - 1] = POS_FIELDNAME + 1;
			}
			
			ds = new DataStruct(fields);

			if (!isPrimaryTable) {
				String []field = Arrays.copyOf(table.parent.getSortedColNames(), 1);
				parentCursor = new RTableCursor(table.parent, field, ctx, null);
				Sequence pkeyData = parentCursor.fetch(1);
				curPkey = (Record) pkeyData.get(1);
				pseq = (Long) curPkey.getNormalFieldValue(1);
			}
			
			int colCount = this.fields.length;
			String[] fullFields = table.getAllColNames();
			fieldsIndex = new int[colCount];
			needRead = new boolean[fullFields.length];
			fullDs = new DataStruct(fullFields);
			for (int i = 0; i < colCount; ++i) {
				int id = fullDs.getFieldIndex(fields[i]);
				fieldsIndex[i] = id;
				if (id >= 0) needRead[id] = true;
			}
			
			if (filter != null) {
				parseFilter(filter.getHome());
			}
		}
		
		private long getParentPosition(long pseq) {
			 while (pseq != this.pseq) {
				Sequence pkeyData = parentCursor.fetch(1);
				if (pkeyData == null) {
					//????ȡ??????ˣ??????ﲻӦ?û??????ݣ????쳣
					MessageManager mm = EngineMessage.get();
					throw new RQException("index " + mm.getMessage("grouptable.invalidData"));
				}
				curPkey = (Record) pkeyData.get(1);
				this.pseq = (Long) curPkey.getNormalFieldValue(1);
			 }
			 return (Long) curPkey.getNormalFieldValue(2);
		}
		
		private long calcPosition(BlockLinkReader rowReader, ObjectReader rowDataReader) throws IOException {
			rowDataReader.hasNext();
			return rowReader.position() + (rowDataReader.position() % blockSize);
		}

		protected Sequence get(int n) {
			if (isClosed || n < 1) {
				return null;
			}
			
			Sequence cache = this.cache;
			if (cache != null) {
				int len = cache.length();
				if (len > n) {
					this.cache = cache.split(n + 1);
					return cache;
				} else if (len == n) {
					this.cache = null;
					return cache;
				}
			} else {
				cache = new Table(ds, n);
			}
			
			int curBlock = this.curBlock;
			int dataBlockCount = this.dataBlockCount;
			BlockLinkReader rowReader = this.rowReader;
			ObjectReader segmentReader = this.segmentReader;
			int colCount = this.fields.length;
			String[] fullFields = table.getAllColNames();
			int allCount = fullFields.length;
			int keyCount = table.getAllSortedColNamesLength();
			DataStruct ds = this.ds;
			
			IArray mems = cache.getMems();
			this.cache = null;
			
			ComputeStack stack = null;
			Expression filter = this.filter;
			DataStruct fullDs = this.fullDs;
			int []fieldsIndex = this.fieldsIndex;
			boolean needRead[] = this.needRead;
			Object []values = new Object[allCount];
			
			ObjectReader rowDataReader = this.rowDataReader;
			long pos;
			long seq;//α??
			long pseq = 0;//????α??
			boolean isPrimaryTable = this.isPrimaryTable;
			int startIndex;
			if (isPrimaryTable) {
				startIndex = 0;
			} else {
				startIndex = table.parent.getSortedColNames().length;
			}
			
			if (filter != null) {
				stack = ctx.getComputeStack();
			}
			try {
				while (curBlock < dataBlockCount) {
					curBlock++;
					rowDataReader.readInt32();
					if (filter != null) {
						int recordCount = segmentReader.readInt32();
						segmentReader.readLong40();
						for (int i = 0; i < keyCount; ++i) {
							segmentReader.skipObject();
							segmentReader.skipObject();
						}
						
						if (recordCount == 0) {
							rowDataReader.skipObject();
							continue;
						}
						
						int i;
						for (i = 0; i < recordCount; ++i) {
							Record r = new Record(ds);
							Record cmpr = new Record(fullDs);
							
							pos = calcPosition(rowReader, rowDataReader);
							seq = rowDataReader.readLong();
							if (!isPrimaryTable) {
								pseq = rowDataReader.readLong();//????
							}
							for (int f = startIndex; f < allCount; ++f) {
								if (needRead[f]) 
									cmpr.setNormalFieldValue(f, rowDataReader.readObject());
								else 
									rowDataReader.skipObject();
							}
							stack.push(cmpr);
							Object b = filter.calculate(ctx);
							if (Variant.isTrue(b)) {
								for (int f = 0; f < colCount; ++f) {
									r.setNormalFieldValue(f, cmpr.getFieldValue(fieldsIndex[f]));
								}
								r.setNormalFieldValue(colCount, seq);
								if (!isPrimaryTable) {
									r.setNormalFieldValue(colCount + 2, pos);
									r.setNormalFieldValue(colCount + 1, getParentPosition(pseq));
								} else {
									r.setNormalFieldValue(colCount + 1, pos);
								}
								mems.add(r);
							}
							stack.pop();
							if (mems.size() == n) {
								i++;
								break;
							}
						}
						if (mems.size() == n) {
							Table tmp = new Table(ds, ICursor.FETCHCOUNT);
							this.cache = tmp;
							mems = tmp.getMems();
							for (; i < recordCount; ++i) {
								Record r = new Record(ds);
								Record cmpr = new Record(fullDs);
								
								pos = calcPosition(rowReader, rowDataReader);
								seq = rowDataReader.readLong();
								if (!isPrimaryTable) {
									pseq = rowDataReader.readLong();//????????
								}
								for (int f = startIndex; f < allCount; ++f) {
									if (needRead[f]) 
										cmpr.setNormalFieldValue(f, rowDataReader.readObject());
									else 
										rowDataReader.skipObject();
								}
								stack.push(cmpr);
								Object b = filter.calculate(ctx);
								if (Variant.isTrue(b)) {
									for (int f = 0; f < colCount; ++f) {
										r.setNormalFieldValue(f, cmpr.getFieldValue(fieldsIndex[f]));
									}
									r.setNormalFieldValue(colCount, seq);
									if (!isPrimaryTable) {
										r.setNormalFieldValue(colCount + 2, pos);
										r.setNormalFieldValue(colCount + 1, getParentPosition(pseq));
									} else {
										r.setNormalFieldValue(colCount + 1, pos);
									}
									mems.add(r);
								}
								stack.pop();
								if (mems.size() == n) {
									i++;
									break;
								}
							}
							if (mems.size() == 0) this.cache = null;
							break;
						}
						continue;
					}
					
					int recordCount = segmentReader.readInt32();
					segmentReader.readLong40();
					for (int i = 0; i < keyCount; ++i) {
						segmentReader.skipObject();
						segmentReader.skipObject();
					}
					
					if (recordCount == 0) {
						rowDataReader.skipObject();
						continue;
					}

					int diff = n - cache.length();
					if (recordCount > diff) {
						int i = 0;
						for (; i < diff; ++i) {
							Record r = new Record(ds);
							pos = calcPosition(rowReader, rowDataReader);
							seq = rowDataReader.readLong();
							if (!isPrimaryTable) {
								pseq = rowDataReader.readLong();//????
							}
							for (int f = startIndex; f < allCount; ++f) {
								if (needRead[f]) 
									values[f] = rowDataReader.readObject();
								else 
									rowDataReader.skipObject();
							}
							for (int f = 0; f < colCount; ++f) {
								r.setNormalFieldValue(f, values[fieldsIndex[f]]);
							}
							r.setNormalFieldValue(colCount, seq);
							if (!isPrimaryTable) {
								r.setNormalFieldValue(colCount + 2, pos);
								r.setNormalFieldValue(colCount + 1, getParentPosition(pseq));
							} else {
								r.setNormalFieldValue(colCount + 1, pos);
							}
							mems.add(r);
						}
						
						Table tmp = new Table(ds, ICursor.FETCHCOUNT);
						this.cache = tmp;
						mems = tmp.getMems();
						
						for (; i < recordCount; ++i) {
							Record r = new Record(ds);
							pos = calcPosition(rowReader, rowDataReader);
							seq = rowDataReader.readLong();
							if (!isPrimaryTable) {
								pseq = rowDataReader.readLong();//????????
							}
							for (int f = startIndex; f < allCount; ++f) {
								if (needRead[f]) 
									values[f] = rowDataReader.readObject();
								else 
									rowDataReader.skipObject();
							}
							for (int f = 0; f < colCount; ++f) {
								r.setNormalFieldValue(f, values[fieldsIndex[f]]);
							}
							r.setNormalFieldValue(colCount, seq);
							if (!isPrimaryTable) {
								r.setNormalFieldValue(colCount + 2, pos);
								r.setNormalFieldValue(colCount + 1, getParentPosition(pseq));
							} else {
								r.setNormalFieldValue(colCount + 1, pos);
							}
							mems.add(r);
						}
						
						break;
					} else {
						for (int i = 0; i < recordCount; ++i) {
							Record r = new Record(ds);
							pos = calcPosition(rowReader, rowDataReader);
							seq = rowDataReader.readLong();
							if (!isPrimaryTable) {
								pseq = rowDataReader.readLong();//????
							}
							for (int f = startIndex; f < allCount; ++f) {
								if (needRead[f]) 
									values[f] = rowDataReader.readObject();
								else
									rowDataReader.skipObject();
							}
							for (int f = 0; f < colCount; ++f) {
								r.setNormalFieldValue(f, values[fieldsIndex[f]]);
							}
							r.setNormalFieldValue(colCount, seq);
							if (!isPrimaryTable) {
								r.setNormalFieldValue(colCount + 2, pos);
								r.setNormalFieldValue(colCount + 1, getParentPosition(pseq));
							} else {
								r.setNormalFieldValue(colCount + 1, pos);
							}
							mems.add(r);
						}
						
						if (diff == recordCount) {
							break;
						}
					}
				}
			} catch (IOException e) {
				throw new RQException(e.getMessage(), e);
			}
			
			this.curBlock = curBlock;
			if (cache.length() > 0) {
				return cache;
			} else {
				return null;
			}
		}
		
		protected long skipOver(long n) {
			if (isClosed || n < 1) {
				return 0;
			}
			
			boolean isPrimaryTable = this.isPrimaryTable;
			int curBlock = this.curBlock;
			int dataBlockCount = this.dataBlockCount;
			ObjectReader segmentReader = this.segmentReader;
			int allCount = table.getColNames().length;
			int keyCount = table.getAllSortedColNamesLength();

			int skipCount = 0;
			ObjectReader rowDataReader = this.rowDataReader;

			try {
				while (curBlock < dataBlockCount) {
					curBlock++;
					rowDataReader.readInt32();
					
					int recordCount = segmentReader.readInt32();
					segmentReader.readLong40();
					for (int i = 0; i < keyCount; ++i) {
						segmentReader.skipObject();
						segmentReader.skipObject();
					}
					
					if (recordCount == 0) {
						rowDataReader.skipObject();
						continue;
					}
					
					for (int i = 0; i < recordCount; ++i) {
						rowDataReader.readLong();
						if (!isPrimaryTable) {
							rowDataReader.readLong();//????
						}
						for (int f = 0; f < allCount; ++f) {
							rowDataReader.readObject();
						}
					}
					
					skipCount += recordCount;
					if (n == skipCount) {
						break;
					}
				}
				
			} catch (IOException e) {
				throw new RQException(e.getMessage(), e);
			}
			
			this.curBlock = curBlock;
			return skipCount;
		}
		
		public long seek(long n) {
			return skipOver(n);
		}
		
		public void close() {
			super.close();
			isClosed = true;
			cache = null;
			
			try {
				segmentReader.close();
			} catch (Exception e) {
				throw new RQException(e.getMessage(), e);
			} finally {
				rowReader = null;
			}
		}
		
		public boolean reset() {
			close();
			
			isClosed = false;
			curBlock = 0;
			return true;
		}
	}
	
	public PhyTableIndex(PhyTable table, String indexName) {
		table.getGroupTable().checkWritable();
		this.srcTable = table;
		this.name = indexName;

		String dir = table.getGroupTable().getFile().getAbsolutePath() + "_";
		indexFile = new FileObject(dir + table.getTableName() + "_" + indexName);
		if (srcTable instanceof ColPhyTable) {
			positionCount = 0;
		} else {
			if (srcTable.parent == null) {
				positionCount = 1;
			} else {
				positionCount = 2;
			}
		}
	}
	
	public PhyTableIndex(PhyTable table, FileObject indexFile) {
		this.srcTable = table;
		this.indexFile = indexFile;
		if (srcTable instanceof ColPhyTable) {
			positionCount = 0;
		} else {
			if (srcTable.parent == null) {
				positionCount = 1;
			} else {
				positionCount = 2;
			}
		}
	}

	protected void writeHeader(ObjectWriter writer) throws IOException {
		writer.write('r');
		writer.write('q');
		writer.write('d');
		writer.write('w');
		writer.write('i');
		writer.write('d');
		writer.write('x');

		writer.write(new byte[32]);
		writer.writeLong64(recordCount);
		writer.writeLong64(index1EndPos);
		writer.writeLong64(index1RecordCount);
		writer.writeLong64(rootItPos);// ָ??root1 info ??ʼλ??
		writer.writeLong64(rootItPos2);// ָ??root2 info ??ʼλ??
		writer.writeLong64(indexPos);// 1st index ??ʼλ??
		writer.writeLong64(indexPos2);// second index ??ʼλ??
		
		writer.writeStrings(ifields);
		if (filter != null) {
			writer.write(1);
			writer.writeUTF(filter.toString());
		} else {
			writer.write(0);
		}
	}

	protected void updateHeader(RandomObjectWriter writer) throws IOException {
		writer.position(39);
		writer.writeLong64(recordCount);
		writer.writeLong64(index1EndPos);
		writer.writeLong64(index1RecordCount);
		writer.writeLong64(rootItPos);// ָ??root1 info ??ʼλ??
		writer.writeLong64(rootItPos2);// ָ??root2 info ??ʼλ??
		writer.writeLong64(indexPos);// 1st index ??ʼλ??
		writer.writeLong64(indexPos2);// second index ??ʼλ??
	}
	
	protected void readHeader(ObjectReader reader) throws IOException {
		if (reader.read() != 'r' || reader.read() != 'q' || 
				reader.read() != 'd' || reader.read() != 'w' ||
				reader.read() != 'i' || reader.read() != 'd' || reader.read() != 'x') {
			MessageManager mm = EngineMessage.get();
			throw new RQException(mm.getMessage("license.fileFormatError"));
		}

		reader.readFully(new byte[32]);
		recordCount = reader.readLong64();
		index1EndPos = reader.readLong64();
		index1RecordCount = reader.readLong64();
		rootItPos = reader.readLong64();
		rootItPos2 = reader.readLong64();
		indexPos = reader.readLong64();
		indexPos2 = reader.readLong64();
		reader.readStrings();//ifields
		
		if (reader.read() != 0) {
			filter = new Expression(reader.readUTF());
		} else {
			filter = null;
		}
	}
	
	public void setFields(String[] ifields, String[] vfields) {
		this.ifields = ifields;
	}

	/**
	 * ????????
	 * ?ļ??ṹ????rqit?? + 8byte + Դ?ļ???¼?? + Դ?ļ?????λ?? + [?????ֶ?] + Դ?ļ??? + 
	 * BLOCK_START +[n + value + pos1,...,posn],... BLOCK_END + ?????? + ??????λ??
	 * @param fields
	 * @param opt
	 * @param ctx
	 * @param filter
	 */
	public void create(String []fields, String opt, Context ctx, Expression filter) {
		int icount = fields.length;
		boolean isAppend = false;//׷?ӻ????½?
		boolean isAdd = true;//?Ƿ???Ҫ??????????table
		boolean isReset = false;//?ؽ?
		
		if (indexFile.size() > 0) {
			if ((opt == null) ||(opt != null && opt.indexOf('a') == -1)) {
				MessageManager mm = EngineMessage.get();
				throw new RQException(name + " " + mm.getMessage("dw.indexNameAlreadyExist"));
			}
		}
		while (opt != null && opt.indexOf('a') != -1 && indexFile.size() > 0) {
			isAppend = true;
			isAdd = false;
			isReset = opt.indexOf('r') != -1;
			InputStream is = indexFile.getInputStream();
			ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);

			try {
				readHeader(reader);
				filter = this.filter;
				if (recordCount == 0) {
					isReset = true;//????ǿյģ???????append
				}
				if (recordCount - index1RecordCount > MAX_SEC_RECORD_COUNT || isReset) {
					isAppend = false;
					rootItPos2 = 0;
					indexPos2 = 0;
					rootItPos = 0;
					indexPos = 0;
					index1EndPos = 0;
					reader.close();
					indexFile.delete();
					break;
				}
				if ((fields.length != ifields.length) || (0 != Variant.compareArrays(fields, ifields))) {
					MessageManager mm = EngineMessage.get();
					throw new RQException("index" + mm.getMessage("engine.dsNotMatch"));
				}
				
				ArrayList  cursorList;
				if (srcTable instanceof RowPhyTable) {
					cursorList = sortRow(fields, ctx, filter);
				} else {
					cursorList = sortCol(fields, ctx, filter);
				}
				int size = cursorList.size();
				if (size == 0) {
					return;
				} else if (size == 1) {
					createIndexTable(cursorList.get(0), indexFile, true);
				} else {				
					ICursor []cursors = new ICursor[cursorList.size()];
					cursorList.toArray(cursors);					
					Expression []exps = new Expression[icount + 1];
					for (int i = 0; i < icount + 1; ++i) {
						exps[i] = new Expression(ctx, "#" + (i + 1));
					}
	
					ICursor cursor = new MergesCursor(cursors, exps, ctx);
					createIndexTable(cursor, indexFile, true);
				}
				srcTable.getTableMetaDataIndex(indexFile, null, false);//׷?Ӻ?Ҫ???cache
			} catch (IOException e) {
				throw new RQException(e.getMessage(), e);
			} finally {
				try {
					reader.close();
				} catch (IOException ie){};
			}
			
			break;
		} 
		if (!isAppend) {
			this.filter = filter;
			FileObject tmpFile;
			boolean needDelete = false;
			if (indexFile.isExists()) {
				String tmpFileName = indexFile.createTempFile("tmp");
				tmpFile = new FileObject(tmpFileName);
				tmpFile.delete();
				needDelete = true;
			} else {
				tmpFile = indexFile;
			}
			this.recordCount = 0;
			index1RecordCount = 0;
			
			ArrayList  cursorList;
			if (srcTable instanceof RowPhyTable) {
				cursorList = sortRow(fields, ctx, filter);
			} else {
				cursorList = sortCol(fields, ctx, filter);
			}
			
			int size = cursorList.size();
			if (size == 0) {
				createIndexTable(new MemoryCursor(null), tmpFile, false);
			} else if (size == 1) {
				createIndexTable(cursorList.get(0), tmpFile, false);
			} else {
				ICursor []cursors = new ICursor[size];
				cursorList.toArray(cursors);
				Expression []exps = new Expression[icount + 1];
				for (int i = 0; i < icount + 1; ++i) {
					exps[i] = new Expression(ctx, "#" + (i + 1));
				}

				ICursor cursor = new MergesCursor(cursors, exps, ctx);
				createIndexTable(cursor, tmpFile, false);
			}
			
			srcTable.getTableMetaDataIndex(indexFile, null, false);//׷?Ӻ?Ҫ???cache
			if (needDelete) {
				indexFile.delete();
				tmpFile.move(indexFile.getFileName(), null);
			}
			
			if (opt != null && opt.indexOf('U') != -1) {
				isAdd = false;
			}
			try {
				if (isAdd) {
					srcTable.addIndex(name, ifields, null);
				}
			} catch (IOException e) {
				throw new RQException(e.getMessage(), e);
			}
		}
	}

	/**
	 * ???mems????????ͬ????ĸ???
	 * @param mems
	 * @param from
	 * @param fcount
	 * @return
	 */
	protected int getGroupNum(IArray mems, int from, int fcount) {
		int len = mems.size();
		int count = 1;		
		Record r;
		r = (Record)mems.get(from);
		Object []firstVals = r.getFieldValues();
		
		for (int i = from + 1; i <= len; i++) {
			r = (Record)mems.get(i);
			Object []vals = r.getFieldValues();
			
			int cmp = Variant.compareArrays(firstVals, vals, fcount);
			if (cmp == 0) {
				count++;
			} else {
				break;
			}
		}
		return count;
	}
	
	protected void createIndexTable(ICursor cursor, FileObject indexFile, boolean isAppends) {
		RandomOutputStream os = indexFile.getRandomOutputStream(true);
		RandomObjectWriter writer = new RandomObjectWriter(os);

		long perCount = MAX_LEAF_BLOCK_COUNT;

		ArrayList maxValues = new ArrayList();
		Record []rootMaxValues;// root??????????ֵ
		long []positions; // internal?????????ļ??е???ʼλ??
		long []rootPositions; // root?????????ļ??е???ʼλ??
		int blockCount = 0; // ????????
		long itPos;
		int recCount = 0;
		
		int icount = ifields.length;
		int posCount = this.positionCount;
		Context ctx = new Context();
		Expression []ifs = new Expression[icount];
		for (int i = 0; i < icount; ++i) {
			ifs[i] = new Expression("#" + (i + 1));
		}
		
		//????Ƿ??Ƕ?????????????
		boolean isPrimaryKey = false;
		String[] keyNames = srcTable.getAllSortedColNames();
		if (srcTable.hasPrimaryKey && keyNames != null && ifields.length == keyNames.length) {
			isPrimaryKey = true;
			for (int i = 0, len = ifields.length; i < len; ++i) {
				if (!ifields[i].equals(keyNames[i])) {
					isPrimaryKey = false;
					break;
				}
			}
		}
		
		try {
			if (isAppends) {
				indexFile.setFileSize(indexPos2);
				writer.position(indexPos2);
			} else {
				writer.position(0);
				writeHeader(writer);				
			}
			Sequence table;
			Record r = null;
			
			if (isPrimaryKey) {
				table = cursor.fetch(MAX_LEAF_BLOCK_COUNT * FETCH_SIZE);
				if (table == null || table.length() == 0) {
					writer.position(0);
					updateHeader(writer);
					try {
						writer.close();
					} catch (IOException ie){};
					return;
				}
				
				while (table != null) {
					//ÿ??д20??
					IArray mems = table.getMems();
					int rest = mems.size();
					recCount += rest;
					if (rest == 0) break;
					int p = 1;
					for (int c = 0; c < FETCH_SIZE; c++) {
						writer.writeInt(BLOCK_START);
						int count = rest >= MAX_LEAF_BLOCK_COUNT ? MAX_LEAF_BLOCK_COUNT : rest;
						rest -= count;
						for (int j = 0; j < count; j++) {
							r = (Record)mems.get(p++);
							writer.writeInt(1);
							for (int f = 0; f <= icount; ++f) {
								writer.writeObject(r.getNormalFieldValue(f));
							}
							//?д?ʱ??Ҫ?ѵ?ַҲ??д????
							for (int i = 1; i <= posCount; ++i) {
								writer.writeObject(r.getNormalFieldValue(icount + i));
							}
						}
						blockCount++;
						maxValues.add(r);
						if (rest == 0) break;
					}
					table = cursor.fetch(MAX_LEAF_BLOCK_COUNT * FETCH_SIZE);
				}

				writer.writeInt(BLOCK_END);
			} else {
				table = cursor.fetchGroup(ifs, MAX_LEAF_BLOCK_COUNT * FETCH_SIZE, ctx);
				if (table == null) {
					writer.position(0);
					updateHeader(writer);
					try {
						writer.close();
					} catch (IOException ie){};
					return;
				}
				
				int p = 1;
				IArray mems = table.getMems();
				int length = table.length();
				while (table != null && length != 0) {
					writer.writeInt(BLOCK_START);
					int count = 0;
					while (count < perCount) {
						int len = getGroupNum(mems, p, icount);
						recCount += len;
						count += len;
						
						r = (Record)mems.get(p);
						writer.writeInt(len);
						for (int f = 0; f < icount; ++f) {
							writer.writeObject(r.getNormalFieldValue(f));
						}
						
						for (int i = 0; i < len; ++i) {
							r = (Record)mems.get(i + p);
							writer.writeObject(r.getNormalFieldValue(icount));
							//?д?ʱ??Ҫ?ѵ?ַҲ??д????
							for (int j = 1; j <= posCount; ++j) {
								writer.writeObject(r.getNormalFieldValue(icount + j));
							}
						}
						p += len;
						if (p > length) {
							table = cursor.fetchGroup(ifs, MAX_LEAF_BLOCK_COUNT * FETCH_SIZE, ctx);
							if (table == null || table.length() == 0) {
								length = 0;
								break;
							}
							p = 1;
							mems = table.getMems();
							length = table.length();
						}
						
					}
					blockCount++;
					maxValues.add(r);
				}

				writer.writeInt(BLOCK_END);
			}
			
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		} finally {
			try {
				writer.close();
			} catch (IOException ie){};
		}

		//????recCount????????
		this.recordCount = recCount + index1RecordCount;
		long srcRecordCount = recordCount;//?ݴ?һ?£???Ϊ???ļ?ͷʱ?ᱻ???¸?ֵ
		positions = new long[blockCount];
		InputStream is = indexFile.getInputStream();
		ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);
		
		try {
			readHeader(reader);
			if (isAppends) {
				reader.seek(indexPos2);
			} else {
				indexPos = reader.position();
			}
			reader.readInt();
			for (int i = 0; i < blockCount; ++i) {
				positions[i] = reader.position();
				while (true) {
					int count = reader.readInt();
					if (count < 1) break;
					
					for (int f = 0; f < icount; ++f) {
						reader.readObject();
					}
					
					for (int j = 0; j < count; ++j) {
						reader.readLong();
						//?д?ʱ??Ҫ?ѵ?ַҲ??????
						for (int c = 0; c < posCount; ++c) {
							reader.readLong();
						}
					}
				}
			}
			
			itPos = reader.position();//interBlock??ʼλ??
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		} finally {
			try {
				reader.close();
			} catch (IOException ie){};
		}

		os = indexFile.getRandomOutputStream(true);
		writer = new RandomObjectWriter(os);
		
		try {
			writer.position(itPos);
			for (int i = 0; i < blockCount; ++i) {
				if (i % MAX_INTER_BLOCK_COUNT == 0) {
					if (blockCount - i >= MAX_INTER_BLOCK_COUNT) {
						writer.writeInt(MAX_INTER_BLOCK_COUNT);
					} else {
						writer.writeInt(blockCount - i);
					}
				}
				for (int f = 0; f < icount; ++f) {
					writer.writeObject(maxValues.get(i).getNormalFieldValue(f));
				}

				writer.writeLong(positions[i]);
			}
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		} finally {
			try {
				writer.close();
			} catch (IOException ie){};
		}
		
		//???rootMaxValues 
		int rootBlockCount = (blockCount/MAX_INTER_BLOCK_COUNT);
		rootBlockCount += (blockCount % MAX_INTER_BLOCK_COUNT==0) ? 0 : 1;
		rootMaxValues = new Record[rootBlockCount];
		for (int i = 0; i < rootBlockCount - 1; i++) {
			rootMaxValues[i] = maxValues.get((i+1)*MAX_INTER_BLOCK_COUNT-1);
		}
		rootMaxValues[rootBlockCount - 1] = maxValues.get(blockCount - 1);
		
		//??? rootPositions
		rootPositions = new long[rootBlockCount];
		is = indexFile.getInputStream();
		reader = new ObjectReader(is, BUFFER_SIZE);
		try {
			reader.seek(itPos);//??λ??internalBlock start
			for (int i = 0; i < blockCount; ++i) {
				if (i % MAX_INTER_BLOCK_COUNT == 0){
					rootPositions[i/MAX_INTER_BLOCK_COUNT] = reader.position();
					reader.readInt();
				}

				for (int f = 0; f < icount; ++f) {
					reader.readObject();
				}
				reader.readLong();

			}
			
			itPos = reader.position();
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		} finally {
			try {
				reader.close();
			} catch (IOException ie){};
		}
		
		if (isAppends) {
			rootItPos2 = itPos;
			recordCount = srcRecordCount;
		} else {
			rootItPos = itPos;
			rootItPos2 = 0;
			recordCount = srcRecordCount;
			index1RecordCount = srcRecordCount;//1????ļ?¼?????????˺??
			index1EndPos = srcTable.getTotalRecordCount();//????1??ʱԴ??????????????DZ????????˺?ģ?Ҳ??????????
		}

		//дrootMaxValues rootPositions
		os = indexFile.getRandomOutputStream(true);
		writer = new RandomObjectWriter(os);
		try {
			writer.position(itPos);
			writer.writeInt(rootBlockCount);
			for (int i = 0; i < rootBlockCount; ++i) {
				for (int f = 0; f < icount; ++f) {
					writer.writeObject(rootMaxValues[i].getNormalFieldValue(f));
				}

				writer.writeLong(rootPositions[i]);
			}
			
			writer.writeLong64(blockCount);//internal????ܸ???
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		} finally {
			try {
				writer.close();
			} catch (IOException ie){};
		}
		
		if (!isAppends) {
			indexPos2 = indexFile.size();
		}
		//write fileHead
		os = indexFile.getRandomOutputStream(true);
		writer = new RandomObjectWriter(os);
		try {
			writer.position(0);
			updateHeader(writer);
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		} finally {
			try {
				writer.close();
			} catch (IOException ie){};
		}
	}
	
	protected ArrayList  sortCol(String []fields, Context ctx, Expression filter) {
		CTableCursor srcCursor = new CTableCursor(srcTable, fields, ctx, filter);
		
		try {			
			int icount = fields.length;
			DataStruct ds = srcTable.getDataStruct();
			ifields = new String[icount];
			boolean isPrimaryTable = srcTable.parent == null;
			String []keyNames = srcTable.groupTable.baseTable.getSortedColNames();
			ArrayList list = new ArrayList();
			if (keyNames != null) {
				for (String name : keyNames) {
					list.add(name);
				}
			}
			for (int i = 0; i < icount; ++i) {
				int id = ds.getFieldIndex(fields[i]);
				if (id == -1) {
					MessageManager mm = EngineMessage.get();
					throw new RQException(fields[i] + mm.getMessage("ds.fieldNotExist"));
				}
				
				if(!isPrimaryTable) {
					if (list.contains(fields[i])) {
						MessageManager mm = EngineMessage.get();
						throw new RQException(fields[i] + mm.getMessage("ds.fieldNotExist"));
					}
				}
				
				ifields[i] = fields[i];
			}
			//????Ƿ??Ƕ?????????????
			keyNames = srcTable.getAllSortedColNames();
			if (srcTable.isSorted && keyNames != null && keyNames.length >= fields.length) {
				boolean isKeyField = true;
				for (int i = 0, len = fields.length; i < len; ++i) {
					if (!fields[i].equals(keyNames[i])) {
						isKeyField = false;
						break;
					}
				}
				if (isKeyField) {
					if (index1EndPos > 0) {
						srcCursor.seek(index1EndPos);
					}
					ArrayList cursorList = new ArrayList();
					cursorList.add(srcCursor);
					srcCursor = null;
					return cursorList;
				}
			}
			
			//Runtime rt = Runtime.getRuntime();
			int baseCount = 100000;//ÿ??ȡ??????????
			boolean flag = false;//?Ƿ????????ʱ?ļ???С
			
			ArrayList cursorList = new ArrayList();
			Table table;
			int []sortFields = new int[icount + 1];
			for (int i = 0; i < icount + 1; ++i) {
				sortFields[i] = i;
			}

			if (index1EndPos > 0) {
				srcCursor.seek(index1EndPos);
			}
			
			while (true) {
				table = (Table) srcCursor.get(baseCount);
				if (table == null) break;
				if (table.length() <= 0) break;
				recordCount += table.length();
				if (table.length() < baseCount)
					break;
				table.sortFields(sortFields);
				FileObject tmp = FileObject.createTempFileObject();
				tmp.exportSeries(table, "b", null);
				BFileCursor bfc = new BFileCursor(tmp, null, "x", ctx);
				cursorList.add(bfc);
				table = null;
				if (!flag && tmp.size() < TEMP_FILE_SIZE) {
					baseCount = (int) (baseCount * (TEMP_FILE_SIZE / tmp.size()));
					flag = true;
				}
				//EnvUtil.runGC(rt);
			}
			
			//this.recordCount = recordCount + index1RecordCount;
			
			int size = cursorList.size();
			if (size == 0) {
				if (table != null && table.length() > 0) {
					table.sortFields(sortFields);
					MemoryCursor mc = new MemoryCursor(table);
					cursorList.add(mc);
				}
				return cursorList;
			}
			if (size > 1) {
				int bufSize = Env.getMergeFileBufSize(size);
				for (int i = 0; i < size; ++i) {
					BFileCursor bfc = (BFileCursor)cursorList.get(i);
					bfc.setFileBufferSize(bufSize);
				}
			}

			if (table != null && table.length() > 0) {
				table.sortFields(sortFields);
				MemoryCursor mc = new MemoryCursor(table);
				cursorList.add(mc);
			}
			
			return cursorList;
		} finally {
			if (srcCursor != null) 
			srcCursor.close();
		}
	}
	
	protected ArrayList  sortRow(String []fields, Context ctx, Expression filter) {
		RTableCursor srcCursor = new RTableCursor(srcTable, fields, ctx, filter);
		
		try {
			int icount = fields.length;
			DataStruct ds = srcTable.getDataStruct();
			ifields = new String[icount];
			boolean isPrimaryTable = srcTable.parent == null;
			String []keyNames = srcTable.groupTable.baseTable.getSortedColNames();
			ArrayList list = new ArrayList();
			if (keyNames != null) {
				for (String name : keyNames) {
					list.add(name);
				}
			}
			
			for (int i = 0; i < icount; ++i) {
				int id = ds.getFieldIndex(fields[i]);
				if (id == -1) {
					MessageManager mm = EngineMessage.get();
					throw new RQException(fields[i] + mm.getMessage("ds.fieldNotExist"));
				}
				
				if(!isPrimaryTable) {
					if (list.contains(fields[i])) {
						MessageManager mm = EngineMessage.get();
						throw new RQException(fields[i] + mm.getMessage("ds.fieldNotExist"));
					}
				}
				ifields[i] = fields[i];
			}
			
			//????Ƿ??Ƕ?????????????
			keyNames = srcTable.getSortedColNames();
			if (srcTable.isSorted && keyNames != null && keyNames.length >= fields.length) {
				boolean isKeyField = true;
				for (int i = 0, len = fields.length; i < len; ++i) {
					if (!fields[i].equals(keyNames[i])) {
						isKeyField = false;
						break;
					}
				}
				if (isKeyField) {
					if (index1EndPos > 0) {
						srcCursor.seek(index1EndPos);
					}
					ArrayList cursorList = new ArrayList();
					cursorList.add(srcCursor);
					srcCursor = null;
					return cursorList;
				}
			}

			//Runtime rt = Runtime.getRuntime();
			int baseCount = 100000;//ÿ??ȡ??????????
			boolean flag = false;//?Ƿ????????ʱ?ļ???С
			
			ArrayList cursorList = new ArrayList();
			Table table;
			long recordCount = 0;
			int []sortFields = new int[icount + 1];
			for (int i = 0; i < icount + 1; ++i) {
				sortFields[i] = i;
			}

			if (index1EndPos > 0) {
				srcCursor.seek(index1EndPos);
			}
			
			while (true) {
				table = (Table) srcCursor.get(baseCount);
				if (table == null) break;
				if (table.length() <= 0) break;
				recordCount += table.length();
				if (table.length() < baseCount)
					break;
				table.sortFields(sortFields);
				FileObject tmp = FileObject.createTempFileObject();
				tmp.exportSeries(table, "b", null);
				BFileCursor bfc = new BFileCursor(tmp, null, "x", ctx);
				cursorList.add(bfc);
				table = null;
				if (!flag && tmp.size() < TEMP_FILE_SIZE) {
					baseCount = (int) (baseCount * (TEMP_FILE_SIZE / tmp.size()));
					flag = true;
				}
				//EnvUtil.runGC(rt);
			}
			
			this.recordCount = recordCount + index1RecordCount;
			//this.endPos = reader.position();
			
			int size = cursorList.size();
			if (size > 1) {
				int bufSize = Env.getMergeFileBufSize(size);
				for (int i = 0; i < size; ++i) {
					BFileCursor bfc = (BFileCursor)cursorList.get(i);
					bfc.setFileBufferSize(bufSize);
				}
			}

			if (table.length() > 0) {
				table.sortFields(sortFields);
				MemoryCursor mc = new MemoryCursor(table);
				cursorList.add(mc);
			}
			
			return cursorList;
		} finally {
			if (srcCursor != null)
				srcCursor.close();
		}
	}
	
	private static int binarySearch(Object[] objs, Object key) {
		int low = 0;
		int high = objs.length - 1;
		while (low <= high) {
			int mid = (low + high) >> 1;
			int cmp = Variant.compare(objs[mid], key, true);

			if (cmp < 0)
				low = mid + 1;
			else if (cmp > 0)
				high = mid - 1;
			else
				return mid; // key found
		}
		
		if (low < objs.length) {
			return low;
		} else {
			return -1;
		}
	}

	private static int binarySearchArray(Object[][] objs, Object []keys, boolean isStart) {
		int keyCount = keys.length;
		int low = 0;
		int high = objs.length - 1;
		while (low <= high) {
			int mid = (low + high) >> 1;
			int cmp = Variant.compareArrays(objs[mid], keys, keyCount);

			if (cmp < 0) {
				low = mid + 1;
			} else if (cmp > 0) {
				high = mid - 1;
			} else {
				// ֻ?Բ????????ֶ???????ʱ???????ظ???
				if (isStart) { // ????ʼλ??
					for (int i = mid - 1; i >= 0; --i) {
						if (Variant.compareArrays(objs[i], keys, keyCount) == 0) {
							mid = i;
						} else {
							break;
						}
					}
				} else { // ?ҽ???λ??
					for (int i = mid + 1; i <= high; ++i) {
						if (Variant.compareArrays(objs[i], keys, keyCount) == 0) {
							mid = i;
						} else {
							break;
						}
					}
					
					if (mid < objs.length - 1) mid++;
				}
				
				return mid; // key found
			}
		}
		
		if (low < objs.length) {
			return low;
		} else {
			return -1;
		}
	}

	//????ֵ???ҿ?ź?λ?ã?????????????????
	//key[] Ҫ???ҵ?ֵ
	//icount ?ֶθ???
	//isStart ?Ƿ????ҿ?ʼ
	//pos[] ????ҵ???λ??
	//index[] ????ҵ??Ŀ??
	private void searchValue(Object[] key, int icount, boolean isStart, long[] pos, int[] index) {
		//int rootBlockCount = rootBlockMaxVals.length;
		int i = 0;
		int j;
		
		index[0] = -1;
		pos[0] = -1;
		index[1] = -1;
		pos[1] = -1;
		
		BlockInfo blockInfo = new BlockInfo();
		while (true) {
			if (icount == 1) {
				i = binarySearch(rootBlockMaxVals, key[0]);
				if (i < 0) {
					break;
				}
				
				if (internalAllBlockPos == null) {
					readInternalBlockInfo(indexFile, rootBlockPos[i], blockInfo);
				} else {
					readInternalBlockInfo(false, i, blockInfo);
				}
				j = binarySearch(blockInfo.internalBlockMaxVals, key[0]);
			} else {
				i = binarySearchArray((Object[][])rootBlockMaxVals, key, isStart);
				if (i < 0) {
					break;
				}
				
				if (internalAllBlockPos == null) {
					readInternalBlockInfo(indexFile, rootBlockPos[i], blockInfo);
				} else {
					readInternalBlockInfo(false, i, blockInfo);
				}
				j = binarySearchArray((Object[][])blockInfo.internalBlockMaxVals, key, isStart);
			}
			if (j < 0) {
				break;
			} 
			index[0] = i * MAX_INTER_BLOCK_COUNT + j;
			pos[0] = blockInfo.internalBlockPos[j];
			break;
		}
	
		if (rootItPos2 == 0) {
			return;
		}
		//rootBlockCount = rootBlockMaxVals2.length;
		i = 0;
		while (true) {
			if (icount == 1) {
				i = binarySearch(rootBlockMaxVals2, key[0]);
				if (i < 0) {
					break;
				}
				
				if (internalAllBlockPos2 == null) {
					readInternalBlockInfo(indexFile, rootBlockPos2[i], blockInfo);
				} else {
					readInternalBlockInfo(true, i, blockInfo);
				}
				j = binarySearch(blockInfo.internalBlockMaxVals, key[0]);
			} else {
				i = binarySearchArray((Object[][])rootBlockMaxVals2, key, isStart);
				if (i < 0) {
					break;
				}

				if (internalAllBlockPos2 == null) {
					readInternalBlockInfo(indexFile, rootBlockPos2[i], blockInfo);
				} else {
					readInternalBlockInfo(true, i, blockInfo);
				}
				j = binarySearchArray((Object[][])blockInfo.internalBlockMaxVals, key, isStart);
			}
			if (j < 0) {
				break;
			} 
			index[1] = i * MAX_INTER_BLOCK_COUNT + j;
			pos[1] = blockInfo.internalBlockPos[j];
			break;
		}
	}

	protected void readBlockInfo(FileObject fo) {
		int rootBlockCount1 = 0;
		int rootBlockCount2 = 0;
		if ((rootBlockMaxVals != null) 
				&& (rootItPos2 == 0 || rootBlockMaxVals2 != null)) {
				return;
		}
		InputStream is = fo.getInputStream();
		ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);

		try {
			readHeader(reader);
			
			int icount = ifields.length;
			if (rootBlockMaxVals == null) {
				reader.seek(rootItPos);
				rootBlockCount1 = reader.readInt(); // ????????
				Object []maxValues;
				long []positions = new long[rootBlockCount1];
				
				if (icount == 1) {
					maxValues = new Object[rootBlockCount1];
					for (int i = 0; i < rootBlockCount1; ++i) {
						maxValues[i] = reader.readObject();
						positions[i] = reader.readLong();
					}
				} else {
					maxValues = new Object[rootBlockCount1][];
					for (int i = 0; i < rootBlockCount1; ++i) {
						Object []vals = new Object[icount];
						for (int f = 0; f < icount; ++f) {
							vals[f] = reader.readObject();
						}
						
						maxValues[i] = vals;
						positions[i] = reader.readLong();
					}
				}
				this.rootBlockMaxVals = maxValues;
				this.rootBlockPos = positions;
				this.internalBlockCount = reader.readLong64();
			}
			
			if (rootItPos2 != 0 && rootBlockMaxVals2 == null) {
				reader.seek(rootItPos2);
				rootBlockCount2 = reader.readInt(); // ????????
				Object []maxValues;
				long []positions = new long[rootBlockCount2];
				
				if (icount == 1) {
					maxValues = new Object[rootBlockCount2];
					for (int i = 0; i < rootBlockCount2; ++i) {
						maxValues[i] = reader.readObject();
						positions[i] = reader.readLong();
					}
				} else {
					maxValues = new Object[rootBlockCount2][];
					for (int i = 0; i < rootBlockCount2; ++i) {
						Object []vals = new Object[icount];
						for (int f = 0; f < icount; ++f) {
							vals[f] = reader.readObject();
						}
						
						maxValues[i] = vals;
						positions[i] = reader.readLong();
					}
				}
				this.rootBlockMaxVals2 = maxValues;
				this.rootBlockPos2 = positions;
				this.internalBlockCount2 = reader.readLong64();
			}

		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		} finally {
			try {
				reader.close();
			} catch (IOException ie){};
		}
	}

	/**
	 * ??ȡһ???м????Ϣ
	 * @param fo
	 * @param pos
	 * @param blockInfo	???
	 */
	private void readInternalBlockInfo(FileObject fo, long pos, BlockInfo blockInfo) {
		int interBlockCount;
//		boolean isSec = false;
//		if (indexPos2 > 0) {
//			if (pos > indexPos2) {
//				isSec = true;
//			}
//		}
		
		InputStream is = fo.getInputStream();
		ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);

		try {
			//readHeader(reader);
			//if (isRowIndexFile()) return;
			
			int icount = ifields.length;
			reader.seek(pos);
			interBlockCount = reader.readInt(); // ????????
			Object []maxValues;
			long []positions = new long[interBlockCount];
			
			if (icount == 1) {
				maxValues = new Object[interBlockCount];
				for (int i = 0; i < interBlockCount; ++i) {
					maxValues[i] = reader.readObject();
					positions[i] = reader.readLong();
				}
			} else {
				maxValues = new Object[interBlockCount][];
				for (int i = 0; i < interBlockCount; ++i) {
					Object []vals = new Object[icount];
					for (int f = 0; f < icount; ++f) {
						vals[f] = reader.readObject();
					}
					
					maxValues[i] = vals;
					positions[i] = reader.readLong();
				}
			}
			
			blockInfo.internalBlockMaxVals = maxValues;
			blockInfo.internalBlockPos = positions;
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		} finally {
			try {
				reader.close();
			} catch (IOException ie){};
		}
	}
	
	// ???ؼ?¼??
	public long count() {
		InputStream is = indexFile.getInputStream();
		ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);

		try {
			readHeader(reader);
			return recordCount;
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		} finally {
			try {
				reader.close();
			} catch (IOException ie){};
		}
	}
	
	// ??1??ʼ????
	public ICursor selectRow(long start, long end, String []fields, String opt, Context ctx) {
		if (opt != null) {
			if (opt.indexOf('l') == -1) start++;
			if (opt.indexOf('r') == -1) end--;
		}

		if (start < 1 || start > end) {
			return null;
		}
		
		InputStream is = indexFile.getInputStream();
		ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);

		try {
			readHeader(reader);
			if (start > recordCount) {
				return null;
			}
			
			if (end > recordCount) {
				end = recordCount;
			}
			
			long lcount = end - start + 1;
			if (lcount > Integer.MAX_VALUE) {
				MessageManager mm = EngineMessage.get();
				throw new RQException("ncursor" + mm.getMessage("engine.indexOutofBound"));
			}
			
			int count = (int)lcount;
			long []srcPos = new long[count];
			reader.skip((start - 1) * 8);
			for (int i = 0; i < count; ++i) {
				srcPos[i] = reader.readLong64();
			}
			return new IndexCursor(srcTable, fields, ifields, srcPos, opt, ctx);
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		} finally {
			try {
				reader.close();
			} catch (IOException ie){};
		}
	}
	
	// ??1??ʼ????
	public ICursor selectRow(long []posArray, String []fields, String opt, Context ctx) {
		InputStream is = indexFile.getInputStream();
		ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);

		try {
			readHeader(reader);
			long recordCount = this.recordCount;
			if (posArray[0] > recordCount) {
				return null;
			}
						
			int count = posArray.length;
			long []srcPos = new long[count];
			long prev = 0;
			
			for (int i = 0; i < count; ++i) {
				long cur = posArray[i];
				if (cur > recordCount) break;
				
				reader.skip((cur - prev - 1) * 8);
				srcPos[i] = reader.readLong64();
				prev = cur;
			}
			
			return new IndexCursor(srcTable, fields, ifields, srcPos, opt, ctx);
			//return new PFileCursor(srcFile, srcPos, BUFFER_SIZE, fields, opt, ctx);
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		} finally {
			try {
				reader.close();
			} catch (IOException ie){};
		}
	}
	
	//Ŀǰû???õ????Ա???
	/**
	 * 
	 * @param exp
	 * @param startVals
	 * @param endVals
	 * @param fields
	 * @param opt
	 * @param ctx
	 * @return	??ַ(α??)????
	 */
 	@SuppressWarnings("unused")
	private LongArray select(Expression exp, Object []startVals, Object []endVals, 
			String []fields, String opt, Context ctx) {
		readBlockInfo(indexFile);
		
		boolean le = opt == null || opt.indexOf('l') == -1;
		boolean re = opt == null || opt.indexOf('r') == -1;
		if (startVals == null) {
			if (endVals == null) {
				return select(exp, opt, ctx);
			}
		} else if (endVals != null) {
			if (startVals.length != endVals.length) {
				MessageManager mm = EngineMessage.get();
				throw new RQException("icursor" + mm.getMessage("function.paramCountNotMatch"));			
			}
			
			int cmp = Variant.compareArrays(startVals, endVals);
			if (cmp > 0) {
				return null;
			} else if (cmp == 0 && (!le || !re)) {
				return null;
			}
		}
		
		if (startVals != null) {
			if (startVals.length > ifields.length) {
				MessageManager mm = EngineMessage.get();
				throw new RQException("icursor" + mm.getMessage("function.invalidParam"));			
			}
		} else {
			if (endVals.length > ifields.length) {
				MessageManager mm = EngineMessage.get();
				throw new RQException("icursor" + mm.getMessage("function.invalidParam"));			
			}
		}
		
		int icount = ifields.length;
		LongArray srcPos = null;
		LongArray srcPos2 = null;
		if (startVals == null) {
			int end[] = new int[2];
			long endPos[] = new long[2];
			
			searchValue(endVals, icount, false, endPos, end);
			if (end[0] < 0 && end[1] < 0 && exp == null) {
				return null;//return srcTable.cursor(fields);
			}
			
			InputStream is = indexFile.getInputStream();
			ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);
			try {
				if (end[0] < 0) {
					srcPos = readPos(reader, exp, ctx, 0, (int)(internalBlockCount - 1), indexPos + 5);
				} else if (icount == 1) {
					srcPos = readPos_s(reader, endVals[0], end[0], re ? LE : LT, exp, ctx, indexPos + 5, endPos[0]);
				} else {
					srcPos = readPos_m(reader, endVals, end[0], re ? LE : LT, exp, ctx, indexPos + 5, endPos[0]);
				}
				
				if (rootItPos2 != 0) {
					if (end[1] < 0) {
						srcPos2 = readPos(reader, exp, ctx, 0, (int)(internalBlockCount2 - 1), indexPos2 + 5);
					} else if (icount == 1) {
						srcPos2 = readPos_s(reader, endVals[0], end[1], re ? LE : LT, exp, ctx, indexPos2 + 5, endPos[1]);
					} else {
						srcPos2 = readPos_m(reader, endVals, end[1], re ? LE : LT, exp, ctx, indexPos2 + 5, endPos[1]);
					}
				}
				if (srcPos == null || srcPos.size() == 0) {
					srcPos = srcPos2;
				} else if (srcPos2 != null) {
					concat(srcPos, srcPos2);
				}
			} catch (IOException e) {
				throw new RQException(e.getMessage(), e);
			} finally {
				try {
					reader.close();
				} catch (IOException ie){};
			}
		} else if (endVals == null) {
			int start[] = new int[2];
			long startPos[] = new long[2];
			
			searchValue(startVals, icount, true, startPos, start);
			if (start[0] < 0 && start[1] < 0) {
				return null;
			}

			InputStream is = indexFile.getInputStream();
			ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);
			try {
				if (start[0] >= 0) {
					if (icount == 1) {
						srcPos = readPos_s(reader, startVals[0], start[0], le ? GE : GT, exp, ctx, 0, startPos[0]);
					} else {
						srcPos = readPos_m(reader, startVals, start[0], le ? GE : GT, exp, ctx, 0, startPos[0]);
					}
				}
				if (rootItPos2 != 0) {
					if (start[1] >= 0) {
						if (icount == 1) {
							srcPos2 = readPos_s(reader, startVals[0], start[1], le ? GE : GT, exp, ctx, 0, startPos[1]);
						} else {
							srcPos2 = readPos_m(reader, startVals, start[1], le ? GE : GT, exp, ctx, 0, startPos[1]);
						}
					}
				}
				if (srcPos == null || srcPos.size() == 0) {
					srcPos = srcPos2;
				} else if (srcPos2 != null) {
					concat(srcPos, srcPos2);
				}
				
			} catch (IOException e) {
				throw new RQException(e.getMessage(), e);
			} finally {
				try {
					reader.close();
				} catch (IOException ie){};
			}
		} else {
			int start[] = new int[2];
			long startPos[] = new long[2];
			int end[] = new int[2];
			long endPos[] = new long[2];

			searchValue(startVals, icount, true, startPos, start);
			if (start[0] < 0 && start[1] < 0) {
				return null;
			}
			searchValue(endVals, icount, false, endPos, end);
			
			InputStream is = indexFile.getInputStream();
			ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);
			try {
				if (start[0] >= 0) {
					if (end[0] < 0) {
						if (icount == 1) {
							srcPos = readPos_s(reader, startVals[0], start[0], le ? GE : GT, exp, ctx, 0, startPos[0]);
						} else {
							srcPos = readPos_m(reader, startVals, start[0], le ? GE : GT, exp, ctx, 0, startPos[0]);
						}
					} else {
						if (icount == 1) {
							srcPos = readPos_s(reader, startVals[0], start[0], le, endVals[0], end[0], re, exp, ctx, startPos[0]);
						} else {
							srcPos = readPos_m(reader, startVals, start[0], le, endVals, end[0], re, exp, ctx, startPos[0]);
						}
					}
				}
				if (rootItPos2 != 0) {
					if (start[1] >= 0) {
						if (end[1] < 0) {
							if (icount == 1) {
								srcPos2 = readPos_s(reader, startVals[0], start[1], le ? GE : GT, exp, ctx, 0, startPos[1]);
							} else {
								srcPos2 = readPos_m(reader, startVals, start[1], le ? GE : GT, exp, ctx, 0, startPos[1]);
							}
						} else {
							if (icount == 1) {
								srcPos2 = readPos_s(reader, startVals[0], start[1], le, endVals[0], end[1], re, exp, ctx, startPos[1]);
							} else {
								srcPos2 = readPos_m(reader, startVals, start[1], le, endVals, end[1], re, exp, ctx, startPos[1]);
							}
						}
					}
				}
				if (srcPos == null || srcPos.size() == 0) {
					srcPos = srcPos2;
				} else if (srcPos2 != null) {
					concat(srcPos, srcPos2);
				}
				
			} catch (IOException e) {
				throw new RQException(e.getMessage(), e);
			} finally {
				try {
					reader.close();
				} catch (IOException ie){};
			}
		}

		return srcPos;
	}
	
 	/**
 	 * ??ֵ?????ѯ?????ֶΣ?
 	 * @param startVals
 	 * @param endVals
 	 * @param opt
 	 * @param ctx
 	 * @return
 	 */
	public LongArray select(Object []startVals, Object []endVals, String opt, Context ctx) {
		readBlockInfo(indexFile);
		
		boolean le = opt == null || opt.indexOf('l') == -1;
		boolean re = opt == null || opt.indexOf('r') == -1;
				
		int icount = ifields.length;
		LongArray srcPos = null;
		LongArray srcPos2 = null;
		if (startVals == null) {
			throw new RQException("icursor: never run to here!");
		} else if (endVals == null) {
			throw new RQException("icursor: never run to here!");
		} else {
			if (startVals.length > ifields.length || endVals.length > ifields.length) {
				MessageManager mm = EngineMessage.get();
				throw new RQException("icursor" + mm.getMessage("function.invalidParam"));			
			}

			if (startVals.length != endVals.length) {
				MessageManager mm = EngineMessage.get();
				throw new RQException("psort" + mm.getMessage("function.paramCountNotMatch"));			
			}
			
			int cmp = Variant.compareArrays(startVals, endVals);
			if (cmp > 0) {
				return new LongArray();
			} else if (cmp == 0 && (!le || !re)) {
				return new LongArray();
			}

			int start[] = new int[2];
			long startPos[] = new long[2];
			int end[] = new int[2];
			long endPos[] = new long[2];
			
			searchValue(startVals, icount, true, startPos, start);
			if (start[0] < 0 && start[1] < 0) return new LongArray();
			searchValue(endVals, icount, false, endPos, end);
			
			InputStream is = indexFile.getInputStream();
			ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);
			try {
				if (start[0] >= 0) {
					if (end[0] < 0) {
						if (icount == 1) {
							srcPos = readPos_s(reader, startVals[0], start[0], le ? GE : GT, 0, startPos[0]);
						} else {
							srcPos = readPos_m(reader, startVals, start[0], le ? GE : GT, 0, startPos[0]);
						}
					} else {
						if (icount == 1) {
							srcPos = readPos_s(reader, startVals[0], start[0], le, endVals[0], end[0], re, startPos[0]);
						} else {
							srcPos = readPos_m(reader, startVals, start[0], le, endVals, end[0], re, startPos[0]);
						}
					}
				}
				if (rootItPos2 != 0) {
					if (start[1] >= 0) {
						if (end[1] < 0) {
							if (icount == 1) {
								srcPos2 = readPos_s(reader, startVals[0], start[1], le ? GE : GT, 0, startPos[1]);
							} else {
								srcPos2 = readPos_m(reader, startVals, start[1], le ? GE : GT, 0, startPos[1]);
							}
						} else {
							if (icount == 1) {
								srcPos2 = readPos_s(reader, startVals[0], start[1], le, endVals[0], end[1], re, startPos[1]);
							} else {
								srcPos2 = readPos_m(reader, startVals, start[1], le, endVals, end[1], re, startPos[1]);
							}
						}
					}
				}
				if (srcPos == null) srcPos = new LongArray();
				concat(srcPos, srcPos2);
			} catch (IOException e) {
				throw new RQException(e.getMessage(), e);
			} finally {
				try {
					reader.close();
				} catch (IOException ie){};
			}
		}

		return srcPos;
	}

	/**
	 * һ?β?ѯ???ֵ
	 * @param vals
	 * @param opt
	 * @param ctx
	 * @return
	 */
	public LongArray select(Object []vals, String opt, Context ctx) {
		readBlockInfo(indexFile);

		int icount = ifields.length;
		int n[] = new int[2];
		long pos[] = new long[2];
		searchValue(vals, icount, true, pos, n);
		if (n[0] < 0 && n[1] < 0) return null;
		
		LongArray srcPos = null;
		LongArray srcPos2 = null;
		InputStream is = indexFile.getInputStream();
		ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);
		try {
			if (n[0] >= 0) {
				if (icount == 1) {
					srcPos = readPos_s(reader, vals[0], n[0], EQ, 0, pos[0]);
				} else {
					srcPos = readPos_m(reader, vals, n[0], EQ, 0, pos[0]);
				}
			}
			if (rootItPos2 != 0) {
				if (n[1] >= 0) {
					if (icount == 1) {
						srcPos2 = readPos_s(reader, vals[0], n[1], EQ, 0, pos[1]);
					} else {
						srcPos2 = readPos_m(reader, vals, n[1], EQ, 0, pos[1]);
					}
				}
			}
			if (srcPos == null) srcPos = new LongArray();
			concat(srcPos, srcPos2);
			
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		} finally {
			try {
				reader.close();
			} catch (IOException ie){};
		}

		return srcPos;
	}

	/**
	 * һ?β?ѯ???ֵ
	 * @param vals
	 * @param opt
	 * @param ctx
	 * @return
	 */
	public LongArray select(Sequence vals, String opt, Context ctx) {
		if (vals == null || vals.length() == 0) return null;

		LongArray srcPos;
		ObjectReader reader = null;
		if (cachedBlockReader == null) {
			InputStream is = indexFile.getInputStream();
			reader = new ObjectReader(is, BUFFER_SIZE);
		}
		
		try {
			if (ifields.length == 1) {
				srcPos = readPos_s(reader, vals);
			} else {
				srcPos = readPos_m(reader, vals);
			}
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		} finally {
			try {
				if (reader != null) {
					reader.close();
				}
			} catch (IOException ie){};
		}

		return srcPos;
	}

	/**
	 * ??????ʽexp??ѯ
	 */
	public ICursor select(Expression exp, String []fields, String opt, Context ctx) {
		if (opt != null && opt.indexOf('s') != -1 && rootItPos2 != 0) {
			int icount = ifields.length;
			int start[] = new int[2];
			long startPos[] = new long[2];
			int end[] = new int[2];
			
			startPos[0] = indexPos + 5;
			startPos[1] = indexPos2 + 5;
			start[0] = start[1] = 0;
			end[0] = (int) (this.internalBlockCount - 1);
			end[1] = (int) (this.internalBlockCount2- 1);
			
			InputStream is = indexFile.getInputStream();
			ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);
			IndexCursor cs1 = null;
			IndexCursor cs2 = null;
			LongArray srcPos = null;
			LongArray srcPos2 = null;
			
			ArrayList mrl = PhyTable.getModifyRecord(srcTable, exp, ctx);
			
			try {
				if (start[0] >= 0) {
					srcPos = readPos(reader, exp, ctx, start[0], end[0], startPos[0]);
					if (srcPos != null && srcPos.size() != 0) {
						cs1 = new IndexCursor(srcTable, fields, ifields, srcPos.toArray(), opt, ctx);
						if (maxRecordLen != 0) {
							cs1.setRowBufferSize(maxRecordLen);
						}
						((IndexCursor) cs1).setModifyRecordList(mrl);
					}
				}
				if (rootItPos2 != 0) {
					if (start[1] >= 0) {
						srcPos2 = readPos(reader, exp, ctx, start[1], end[1], startPos[1]);
						if (srcPos2 != null && srcPos2.size() != 0) {
							cs2 = new IndexCursor(srcTable, fields, ifields, srcPos2.toArray(), opt, ctx);
							if (maxRecordLen != 0) {
								cs2.setRowBufferSize(maxRecordLen);
							}
							((IndexCursor) cs2).setModifyRecordList(mrl);
						}
					}
				}
			} catch (IOException e) {
				throw new RQException(e.getMessage(), e);
			} finally {
				try {
					reader.close();
				} catch (IOException ie){};
			}
			
			if (cs1 == null) {
				return cs2;
			} else if (cs2 == null) {
				return cs1;
			} else {
				ICursor []cursors = new ICursor[]{cs1, cs2};
				Expression []exps = new Expression[icount];
				for (int i = 0; i < fields.length; ++i) {
					exps[i] = new Expression(ctx, "#" + (i + 1));
				}
				return new MergesCursor(cursors, exps, ctx);
			}
		}
		
		LongArray srcPos = select(exp, opt, ctx);
		if (srcPos == null || srcPos.size() == 0) {
			return null;
		}
		if (isPrimaryKey) opt = "s";
		IndexCursor cs = new IndexCursor(srcTable, fields, ifields, srcPos.toArray(), opt, ctx);
		if (maxRecordLen != 0) {
			cs.setRowBufferSize(maxRecordLen);
		}
		return cs;
	}
	
	/**
	 * ??????ʽ??ѯ
	 * @param exp
	 * @param opt
	 * @param ctx
	 * @return	??ַ(α??)????
	 */
	public LongArray select(Expression exp, String opt, Context ctx) {
		readBlockInfo(indexFile);

		int icount = ifields.length;
		if (icount == 0) {
			MessageManager mm = EngineMessage.get();
			throw new RQException(mm.getMessage("Expression.unknownExpression") + exp.toString());
		}
		
		//????contain????ʽ
		Node home = exp.getHome();
		if (home instanceof DotOperator) {
			Node left = home.getLeft();
			Node right = home.getRight();
			if (!(right instanceof Contain)) {
				MessageManager mm = EngineMessage.get();
				throw new RQException("icursor" + mm.getMessage("function.invalidParam"));
			}
			Sequence series;
			Object obj = left.calculate(ctx);
			if (obj == null) {
				return null;
			}
			if (obj instanceof Sequence) {
				series = (Sequence) obj;
			} else {
				MessageManager mm = EngineMessage.get();
				throw new RQException("icursor" + mm.getMessage("function.invalidParam"));
			}
			
			String str = ((Contain)right).getParamString();
			str = str.replaceAll("\\[", "");
			str = str.replaceAll("\\]", "");
			str = str.replaceAll(" ", "");
			String[] split = str.split(",");
			if (icount != split.length) {
				MessageManager mm = EngineMessage.get();
				throw new RQException("icursor" + mm.getMessage("function.paramCountNotMatch"));
			}
			if (0 != Variant.compareArrays(ifields, split)) {
				MessageManager mm = EngineMessage.get();
				throw new RQException("icursor" + mm.getMessage("function.invalidParam"));
			}
			series.sort("o");
			return select(series, opt, ctx);
		}
		
		//????like(F,"xxx*")????ʽ
		if (home instanceof Like) {
			if (((Like) home).getParam().getSubSize() != 2) {
				MessageManager mm = EngineMessage.get();
				throw new RQException("icursor" + mm.getMessage("function.invalidParam"));
			}
			IParam sub1 = ((Like) home).getParam().getSub(0);
			IParam sub2 = ((Like) home).getParam().getSub(1);
			String f = (String) sub1.getLeafExpression().getIdentifierName();
			if (!f.equals(ifields[0])) {
				MessageManager mm = EngineMessage.get();
				throw new RQException("icursor" + mm.getMessage("function.invalidParam"));
			}
			String fmtExp = (String) sub2.getLeafExpression().calculate(ctx);
			int idx = fmtExp.indexOf("*");
			if (idx > 0) {
				fmtExp = fmtExp.substring(0, idx);
				return select(new String[]{fmtExp}, exp, opt, ctx);
			}
		}
				
		FieldFilter []filters = new FieldFilter[icount];
		if (getFieldFilters(exp.getHome(), filters, ctx)) {
			int last = icount - 1;
			for (; last >= 0; --last) {
				if (filters[last] != null) break;
			}
			
			// ???????Ķ?????ȱȽ???????Ż???[a,b...v1]:[a,b...v2]
			boolean canOpt = true;
			for (int i = 0; i < last; ++i) {
				if (filters[i] == null || filters[i].startSign != EQ) {
					canOpt = false;
					break;
				}
			}
			
			if (canOpt) {
				if (filters[last].startSign == EQ) {
					Object []vals = new Object[last + 1];
					for (int i = 0; i <= last; ++i) {
						vals[i] = filters[i].startVal;
					}
					
					if (icount == last + 1) {
						//??????????ֶεĵ???
						Sequence seq = new Sequence();
						seq.addAll(vals);
						if (icount == 1) {
							return select(seq, opt, ctx);
						}
						Sequence series = new Sequence();
						series.add(seq);
						return select(series, opt, ctx);
					}
					return select(vals, opt, ctx);
				} else if (filters[last].startSign != NULL && filters[last].endSign != NULL) {
					Object []startVals = new Object[last + 1];
					Object []endVals = new Object[last + 1];
					for (int i = 0; i <= last; ++i) {
						startVals[i] = filters[i].startVal;
						endVals[i] = filters[i].startVal;
					}
					
					endVals[last] = filters[last].endVal;
					if (opt == null) opt = "";
					if (filters[last].startSign == GT) opt += "l";
					if (filters[last].endSign == LT) opt += "r";
					
					return select(startVals, endVals, opt, ctx);
				}
			}
		}

		Sequence vals = new Sequence(icount); // ǰ????????жϵ??ֶε?ֵ
		FieldFilter ff = null; // ??һ??????????жϵ??ֶε???Ϣ
		
		for (int i = 0; i < icount; ++i) {
			FieldFilter filter = new FieldFilter();
			getFieldFilter(i, exp.getHome(), filter, ctx);
			if (filter.startSign == EQ) {
				vals.add(filter.startVal);
			} else {
				ff = filter;
				break;
			}
		}
		
		int start[] = new int[2];
		long startPos[] = new long[2];
		int end[] = new int[2];
		long endPos[] = new long[2];
		
		startPos[0] = indexPos + 5;
		startPos[1] = indexPos2 + 5;
		start[0] = start[1] = 0;
		end[0] = (int) (this.internalBlockCount - 1);
		end[1] = (int) (this.internalBlockCount2- 1);
		int eqCount = vals.length();
		
		if (eqCount == 0) {
			if (ff != null && ff.startSign != NULL) {
				Object []keys = new Object[]{ff.startVal};
				searchValue(keys, icount, true, startPos, start);
				if (start[0] < 0 && start[1] < 0) return null;
			}
			
			if (ff != null && ff.endSign != NULL) {
				Object []keys = new Object[]{ff.endVal};
				searchValue(keys, icount, false, endPos, end);
				if (end[0] < 0) end[0] = (int) (this.internalBlockCount - 1);
				if (end[1] < 0) end[1] = (int) (this.internalBlockCount2 - 1);
			}
		} else {
			if (ff == null || ff.startSign == NULL) {
				Object []keys = vals.toArray();
				searchValue(keys, icount, true, startPos, start);
			} else {
				Object []keys = new Object[eqCount + 1];
				vals.toArray(keys);
				keys[eqCount] = ff.startVal;
				searchValue(keys, eqCount + 1, true, startPos, start);
			}
			
			if (start[0] < 0 && start[1] < 0) return null;
			
			if (ff == null || ff.endSign == NULL) {
				if (icount == 1) {
					end[0] = start[0];
					end[1] = start[1];
				} else {
					Object []keys = vals.toArray();
					searchValue(keys, icount, false, endPos, end);
				}
			} else {
				Object []keys = new Object[eqCount + 1];
				vals.toArray(keys);
				keys[eqCount] = ff.endVal;
				searchValue(keys, icount, false, endPos, end);
			}

			if (end[0] < 0) end[0] = (int) (this.internalBlockCount - 1);
			if (end[1] < 0) end[1] = (int) (this.internalBlockCount2 - 1);
		}
		
		LongArray srcPos = null;
		LongArray srcPos2 = null;
		InputStream is = indexFile.getInputStream();
		ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);
		try {
			if (start[0] >= 0) {
				srcPos = readPos(reader, exp, ctx, start[0], end[0], startPos[0]);
			}
			if (rootItPos2 != 0) {
				if (start[1] >= 0) {
					srcPos2 = readPos(reader, exp, ctx, start[1], end[1], startPos[1]);
				}
			}
			if (srcPos == null) srcPos = new LongArray();
			concat(srcPos, srcPos2);
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		} finally {
			try {
				reader.close();
			} catch (IOException ie){};
		}

		return srcPos;
	}

	private boolean equalField(int fieldIndex, Node node) {
		if (node instanceof UnknownSymbol) {
			if (ifields[fieldIndex].equals(((UnknownSymbol)node).getName())) {
				return true;
			}
		} else if (node instanceof FieldId) {
			return ((FieldId)node).getFieldIndex() == fieldIndex;
		}
		
		return false;
	}
	
	private boolean getFieldFilters(Node home, FieldFilter []filters, Context ctx) {
		if (!(home instanceof Operator)) return false;
		
		Node left = home.getLeft();
		Node right = home.getRight();
		if (home instanceof And) {
			if (!getFieldFilters(left, filters, ctx)) return false;
			return getFieldFilters(right, filters, ctx);
		} else if (home instanceof Equals) { // ==
			for (int i = 0, icount = ifields.length; i < icount; ++i) {
				if (equalField(i, left)) {
					if (filters[i] == null) {
						filters[i] = new FieldFilter();
					} else {
						return false;
					}
					
					filters[i].startSign = EQ;
					filters[i].startVal = right.calculate(ctx);
					return true;
				} else if (equalField(i, right)) {
					if (filters[i] == null) {
						filters[i] = new FieldFilter();
					} else {
						return false;
					}

					filters[i].startSign = EQ;
					filters[i].startVal = left.calculate(ctx);
					return true;
				}
			}
		} else if (home instanceof NotSmaller) { // >=
			for (int i = 0, icount = ifields.length; i < icount; ++i) {
				if (equalField(i, left)) {
					if (filters[i] == null) {
						filters[i] = new FieldFilter();
					} else if (filters[i].startSign != NULL) {
						return false;
					}
					
					filters[i].startSign = GE;
					filters[i].startVal = right.calculate(ctx);
					return true;
				} else if (equalField(i, right)) {
					if (filters[i] == null) {
						filters[i] = new FieldFilter();
					} else if (filters[i].endSign != NULL) {
						return false;
					}

					filters[i].endSign = LE;
					filters[i].endVal = left.calculate(ctx);
					return true;
				}
			}
		} else if (home instanceof Greater) { // >
			for (int i = 0, icount = ifields.length; i < icount; ++i) {
				if (equalField(i, left)) {
					if (filters[i] == null) {
						filters[i] = new FieldFilter();
					} else if (filters[i].startSign != NULL) {
						return false;
					}
					
					filters[i].startSign = GT;
					filters[i].startVal = right.calculate(ctx);
					return true;
				} else if (equalField(i, right)) {
					if (filters[i] == null) {
						filters[i] = new FieldFilter();
					} else if (filters[i].endSign != NULL) {
						return false;
					}

					filters[i].endSign = LT;
					filters[i].endVal = left.calculate(ctx);
					return true;
				}
			}
		} else if (home instanceof NotGreater) { // <=
			for (int i = 0, icount = ifields.length; i < icount; ++i) {
				if (equalField(i, left)) {
					if (filters[i] == null) {
						filters[i] = new FieldFilter();
					} else if (filters[i].endSign != NULL) {
						return false;
					}
					
					filters[i].endSign = LE;
					filters[i].endVal = right.calculate(ctx);
					return true;
				} else if (equalField(i, right)) {
					if (filters[i] == null) {
						filters[i] = new FieldFilter();
					} else if (filters[i].startSign != NULL) {
						return false;
					}

					filters[i].startSign = GE;
					filters[i].startVal = left.calculate(ctx);
					return true;
				}
			}
		} else if (home instanceof Smaller) { // <
			for (int i = 0, icount = ifields.length; i < icount; ++i) {
				if (equalField(i, left)) {
					if (filters[i] == null) {
						filters[i] = new FieldFilter();
					} else if (filters[i].endSign != NULL) {
						return false;
					}
					
					filters[i].endSign = LT;
					filters[i].endVal = right.calculate(ctx);
					return true;
				} else if (equalField(i, right)) {
					if (filters[i] == null) {
						filters[i] = new FieldFilter();
					} else if (filters[i].startSign != NULL) {
						return false;
					}

					filters[i].startSign = GT;
					filters[i].startVal = left.calculate(ctx);
					return true;
				}
			}
		}

		return false;
	}
	
	/**
	 * ?ҳ??????ֶε?????
	 * @param fieldIndex
	 * @param home
	 * @param filter
	 * @param ctx
	 */
	private void getFieldFilter(int fieldIndex, Node home, FieldFilter filter, Context ctx) {
		if (!(home instanceof Operator)) return;
		
		Node left = home.getLeft();
		Node right = home.getRight();
		if (home instanceof And) {
			getFieldFilter(fieldIndex, left, filter, ctx);
			getFieldFilter(fieldIndex, right, filter, ctx);
		} else if (home instanceof Equals) { // ==
			if (equalField(fieldIndex, left)) {
				filter.startSign = EQ;
				filter.startVal = right.calculate(ctx);
			} else if (equalField(fieldIndex, right)) {
				filter.startSign = EQ;
				filter.startVal = left.calculate(ctx);
			}
		} else if (home instanceof NotSmaller) { // >=
			if (equalField(fieldIndex, left)) {
				filter.startSign = GE;
				filter.startVal = right.calculate(ctx);
			} else if (equalField(fieldIndex, right)) {
				filter.endSign = LE;
				filter.endVal = left.calculate(ctx);
			}
		} else if (home instanceof Greater) { // >
			if (equalField(fieldIndex, left)) {
				filter.startSign = GT;
				filter.startVal = right.calculate(ctx);
			} else if (equalField(fieldIndex, right)) {
				filter.endSign = LT;
				filter.endVal = left.calculate(ctx);
			}
		} else if (home instanceof NotGreater) { // <=
			if (equalField(fieldIndex, left)) {
				filter.endSign = LE;
				filter.endVal = right.calculate(ctx);
			} else if (equalField(fieldIndex, right)) {
				filter.startSign = GE;
				filter.startVal = left.calculate(ctx);
			}
		} else if (home instanceof Smaller) { // <
			if (equalField(fieldIndex, left)) {
				filter.endSign = LT;
				filter.endVal = right.calculate(ctx);
			} else if (equalField(fieldIndex, right)) {
				filter.startSign = GT;
				filter.startVal = left.calculate(ctx);
			}
		} // ????or???????????
	}

	private LongArray readPos(ObjectReader reader, Expression exp, Context ctx, 
			int start, int end, long startPos) throws IOException {
		int icount = ifields.length;
		int posCount = this.positionCount;
		reader.seek(startPos);
		LongArray posArray = new LongArray(1024);
		DataStruct ds = new DataStruct(ifields);
		Record r = new Record(ds);
		
		ComputeStack stack = ctx.getComputeStack();
		stack.push(r);
		try {
			int count;
			for (; start <= end; ++start) {
				while ((count = reader.readInt()) > 0) {
					for (int i = 0; i < icount; ++i) {
						r.setNormalFieldValue(i, reader.readObject());
					}
					
					Object b = exp.calculate(ctx);
					if (Variant.isTrue(b)) {
						for (int i = 0; i < count; ++i) {
							posArray.add(reader.readLong());
							for (int j = 0; j < posCount; ++j) {
								posArray.add(reader.readLong());
							}
						}
					} else {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}
					}
				}
			}
		} finally {
			stack.pop();
		}
		
		return posArray;
	}
	
	private LongArray readPos_s(ObjectReader reader, Object val, int seq, int type, long startPos, long seqPos) throws IOException {
		LongArray posArray = new LongArray(1024);
		int posCount = this.positionCount;
		switch (type) {
		case EQ:
			reader.seek(seqPos);
			while (true) {
				int count = reader.readInt();
				Object cur = reader.readObject();
				int cmp = Variant.compare(cur, val, true);
				if (cmp < 0) {
					for (int i = 0; i < count; ++i) {
						reader.skipObject();
						for (int j = 0; j < posCount; ++j) {
							reader.skipObject();
						}
					}
				} else if (cmp == 0) {
					for (int i = 0; i < count; ++i) {
						posArray.add(reader.readLong());
						for (int j = 0; j < posCount; ++j) {
							posArray.add(reader.readLong());
						}
					}
					
					break;
				} else {
					break;
				}
			}
			
			break;
		case GE:
		case GT:
			reader.seek(seqPos);
			while (true) {
				int count = reader.readInt();
				Object cur = reader.readObject();
				int cmp = Variant.compare(cur, val, true);
				if (cmp < 0) {
					for (int i = 0; i < count; ++i) {
						reader.skipObject();
						for (int j = 0; j < posCount; ++j) {
							reader.skipObject();
						}
					}
				} else if (cmp == 0) {
					if (type == GE) {
						for (int i = 0; i < count; ++i) {
							posArray.add(reader.readLong());
							for (int j = 0; j < posCount; ++j) {
								posArray.add(reader.readLong());
							}
						}
					} else {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}
					}
					
					break;
				} else {
					for (int i = 0; i < count; ++i) {
						posArray.add(reader.readLong());
						for (int j = 0; j < posCount; ++j) {
							posArray.add(reader.readLong());
						}
					}

					break;
				}
			}

			while (true) {
				int count = reader.readInt();
				if (count == BLOCK_START) {
					count = reader.readInt();
				} else if (count == BLOCK_END) {
					break;
				}

				reader.readObject();
				for (int i = 0; i < count; ++i) {
					posArray.add(reader.readLong());
					for (int j = 0; j < posCount; ++j) {
						posArray.add(reader.readLong());
					}
				}
			}
			
			break;
		default: // LE LT
			reader.seek(startPos);
			while (seq > 0) {
				int count = reader.readInt();
				if (count == BLOCK_START) {
					seq--;
				} else {
					reader.readObject();
					for (int i = 0; i < count; ++i) {
						posArray.add(reader.readLong());
						for (int j = 0; j < posCount; ++j) {
							posArray.add(reader.readLong());
						}
					}
				}
			}
			
			while (true) {
				int count = reader.readInt();
				Object cur = reader.readObject();
				int cmp = Variant.compare(cur, val, true);
				if (cmp < 0) {
					for (int i = 0; i < count; ++i) {
						posArray.add(reader.readLong());
						for (int j = 0; j < posCount; ++j) {
							posArray.add(reader.readLong());
						}
					}
				} else if (cmp == 0) {
					if (type == LE) {
						for (int i = 0; i < count; ++i) {
							posArray.add(reader.readLong());
							for (int j = 0; j < posCount; ++j) {
								posArray.add(reader.readLong());
							}
						}
					}
					
					break;
				} else {
					break;
				}
			}
			
			break;
		}
		
		return posArray;
	}
	private LongArray readPos_s(ObjectReader reader, Sequence vals) throws IOException {
		LongArray tempPos = new LongArray(vals.length() * (positionCount + 1));
		int index = 1;
		int rootCount = this.rootBlockMaxVals.length;
		BlockInfo blockInfo = new BlockInfo();
		for (int i = 0; i < rootCount; ++i) {
			if (cachedBlockReader == null) {
				if (internalAllBlockPos == null) {
					readInternalBlockInfo(indexFile, rootBlockPos[i], blockInfo);//ûԤ????
				} else {
					readInternalBlockInfo(false, i, blockInfo);//?ڶ??????
				}
				
				index = readPos_s(reader, vals, index, blockInfo.internalBlockMaxVals, blockInfo.internalBlockPos, tempPos);
			} else {
				index = readPos_s_cache(vals, index, internalAllBlockMaxVals[i], cachedBlockReader[i], tempPos);
			}
			if (index < 0) break;
		}
		index = 1;
		if (rootBlockPos2 == null) {
			return tempPos;
		}
		rootCount = this.rootBlockMaxVals2.length;
		for (int i = 0; i < rootCount; ++i) {
			if (cachedBlockReader2 == null) {
				if (internalAllBlockPos2 == null) {
					readInternalBlockInfo(indexFile, rootBlockPos2[i], blockInfo);
				} else {
					readInternalBlockInfo(true, i, blockInfo);
				}
				
				index = readPos_s(reader, vals, index, blockInfo.internalBlockMaxVals, blockInfo.internalBlockPos, tempPos);
			} else {
				index = readPos_s_cache(vals, index, internalAllBlockMaxVals2[i], cachedBlockReader2[i], tempPos);
			}
			if (index < 0) break;
		}
		return tempPos;
	}
	
	private int readPos_s(ObjectReader reader, Sequence vals, int srcIndex, Object []blockMaxVals, long []blockPos, LongArray outPos) throws IOException {
		IArray mems = vals.getMems();
		Object srcVal = mems.get(srcIndex);
		int block = binarySearch(blockMaxVals, srcVal);
		if (block < 0) return srcIndex;
		
		int posCount = this.positionCount;
		int blockCount = blockPos.length;
		reader.seek(blockPos[block]);
		
		int srcLen = mems.size();
		LongArray posArray = outPos;//new LongArray(srcLen * 2);
		
		Next:
		while (true) {
			int count = reader.readInt();
			if (count == BLOCK_START) {
				// ????ʱ?Ƚ?һ???Ƿ??????鶼?ȵ?ǰҪȡ??ֵС???????????????
				while (true) {
					block++;
					if (block >= blockCount) break Next;
					
					if (Variant.compare(blockMaxVals[block], srcVal, true) >= 0) {
						reader.seek(blockPos[block]);
						break;
					}
				}
				
				count = reader.readInt();
			} else if (count == BLOCK_END) {
				break;
			}
			
			Object cur = reader.readObject();
			int cmp = Variant.compare(cur, srcVal, true);
			if (cmp < 0) {
				for (int i = 0; i < count; ++i) {
					reader.skipObject();
					for (int j = 0; j < posCount; ++j) {
						reader.skipObject();
					}
				}
			} else if (cmp == 0) {
				for (int i = 0; i < count; ++i) {
					posArray.add(reader.readLong());
					for (int j = 0; j < posCount; ++j) {
						posArray.add(reader.readLong());
					}
				}
				
				srcIndex++;
				if (srcIndex > srcLen) break;
				
				srcVal = mems.get(srcIndex);
			} else {
				while (true) {
					srcIndex++;
					if (srcIndex > srcLen) break Next;
					
					srcVal = mems.get(srcIndex);
					cmp = Variant.compare(cur, srcVal, true);
					if (cmp < 0) {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}
						
						continue Next;
					} else if (cmp == 0) {
						for (int i = 0; i < count; ++i) {
							posArray.add(reader.readLong());
							for (int j = 0; j < posCount; ++j) {
								posArray.add(reader.readLong());
							}
						}
						
						srcIndex++;
						if (srcIndex > srcLen) break Next;
						
						srcVal = mems.get(srcIndex);
						continue Next;
					}
				}
			}
		}
		
		if (srcIndex > srcLen) {
			return -1;
		}
		return srcIndex;
	}
	
	private LongArray readPos_m(ObjectReader reader, Sequence vals) throws IOException {
		LongArray srcPos = new LongArray(vals.length() * (positionCount + 1));
		int index = 1;
		int rootCount = this.rootBlockMaxVals.length;
		BlockInfo blockInfo = new BlockInfo();
		
		for (int i = 0; i < rootCount; ++i) {
			if (cachedBlockReader == null) {
				if (internalAllBlockPos == null) {
					readInternalBlockInfo(indexFile, rootBlockPos[i], blockInfo);
				} else {
					readInternalBlockInfo(false, i, blockInfo);
				}
				index = readPos_m(reader, vals, index ,(Object[][])blockInfo.internalBlockMaxVals, blockInfo.internalBlockPos, srcPos);
			} else {
				index = readPos_m_cache(vals, index ,(Object[][])internalAllBlockMaxVals[i], cachedBlockReader[i], srcPos);
			}
			if (index <0) break;
		}
		
		index = 1;
		if (rootBlockPos2 == null) return srcPos;
		rootCount = this.rootBlockMaxVals2.length;
		for (int i = 0; i < rootCount; ++i) {
			if (cachedBlockReader == null) {
				if (internalAllBlockPos2 == null) {
					readInternalBlockInfo(indexFile, rootBlockPos2[i], blockInfo);
				} else {
					readInternalBlockInfo(true, i, blockInfo);
				}
				
				index = readPos_m(reader, vals, index, (Object[][])blockInfo.internalBlockMaxVals, blockInfo.internalBlockPos, srcPos);
			} else {
				index = readPos_m_cache(vals, index ,(Object[][])internalAllBlockMaxVals2[i], cachedBlockReader2[i], srcPos);
			}
			if (index <0) break;
		}
		return srcPos;
	}
	
	private int readPos_m(ObjectReader reader, Sequence vals, int srcIndex, Object [][]blockMaxVals, long []blockPos, LongArray outPos) throws IOException {
		IArray mems = vals.getMems();
		Object srcVal = mems.get(srcIndex);
		boolean isSequence = false;
		int srcKeyCount = 1;
		Object []srcKeys;
		if (srcVal instanceof Sequence) {
			isSequence = true;
			srcKeys = ((Sequence)srcVal).toArray();
			srcKeyCount = srcKeys.length;
		} else {
			srcKeys = new Object[]{srcVal};
		}
		
		int block = binarySearchArray(blockMaxVals, srcKeys, true);
		if (block < 0) return srcIndex;
		
		int posCount = this.positionCount;
		int blockCount = blockPos.length;
		reader.seek(blockPos[block]);
		
		int icount = ifields.length;
		Object []keys = new Object[icount];
		int srcLen = mems.size();
		LongArray posArray = new LongArray(srcLen);
		
		Next:
		while (true) {
			int count = reader.readInt();
			if (count == BLOCK_START) {
				// ????ʱ?Ƚ?һ???Ƿ??????鶼?ȵ?ǰҪȡ??ֵС???????????????
				while (true) {
					block++;
					if (block >= blockCount) break Next;
					
					if (Variant.compareArrays(blockMaxVals[block], srcKeys, srcKeyCount) >= 0) {
						reader.seek(blockPos[block]);
						break;
					}
				}
				
				count = reader.readInt();
			} else if (count == BLOCK_END) {
				break;
			}
			
			for (int i = 0; i < icount; ++i) {
				keys[i] = reader.readObject();
			}
			
			int cmp = Variant.compareArrays(keys, srcKeys, srcKeyCount);
			if (cmp < 0) {
				for (int i = 0; i < count; ++i) {
					reader.skipObject();
					for (int j = 0; j < posCount; ++j) {
						reader.skipObject();
					}
				}
			} else if (cmp == 0) {
				for (int i = 0; i < count; ++i) {
					posArray.add(reader.readLong());
					for (int j = 0; j < posCount; ++j) {
						posArray.add(reader.readLong());
					}
				}
				
			} else {
				while (true) {
					srcIndex++;
					if (srcIndex > srcLen) break Next;
					
					srcVal = mems.get(srcIndex);
					if (isSequence) {
						((Sequence)srcVal).toArray(srcKeys);
					} else {
						srcKeys[0] = srcVal;
					}
					
					cmp = Variant.compareArrays(keys, srcKeys, srcKeyCount);
					if (cmp < 0) {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}
						
						continue Next;
					} else if (cmp == 0) {
						for (int i = 0; i < count; ++i) {
							posArray.add(reader.readLong());
							for (int j = 0; j < posCount; ++j) {
								posArray.add(reader.readLong());
							}
						}

						continue Next;
					}
				}
			}
		}
		
		for (int i = 0; i < posArray.size(); i++) {
			outPos.add(posArray.get(i));
		}

		if (srcIndex > srcLen) {
			return -1;
		}
		return srcIndex;
	}
	
	private LongArray readPos_s(ObjectReader reader, Object val, int seq, int type, 
			Expression exp, Context ctx, long startPos, long seqPos) throws IOException {
		if (exp == null) {
			return readPos_s(reader, val, seq, type, startPos, seqPos);
		}
		
		LongArray posArray = new LongArray(1024);
		DataStruct ds = new DataStruct(ifields);
		Record r = new Record(ds);
		int posCount = this.positionCount;
		
		ComputeStack stack = ctx.getComputeStack();
		stack.push(r);
		try {
			switch (type) {
			case EQ:
				reader.seek(seqPos);
				while (true) {
					int count = reader.readInt();
					Object cur = reader.readObject();
					int cmp = Variant.compare(cur, val, true);
					if (cmp < 0) {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}
					} else if (cmp == 0) {
						r.setNormalFieldValue(0, cur);
						Object b = exp.calculate(ctx);
						if (Variant.isTrue(b)) {
							for (int i = 0; i < count; ++i) {
								posArray.add(reader.readLong());
								for (int j = 0; j < posCount; ++j) {
									posArray.add(reader.readLong());
								}
							}
						}
						
						break;
					} else {
						break;
					}
				}
				
				break;
			case LIKE:
				reader.seek(startPos);
				boolean findFirst = false;
				while (true) {
					int count = reader.readInt();
					if (count == BLOCK_START) {
						count = reader.readInt();
					} else if (count == BLOCK_END) {
						break;
					}
					Object cur = reader.readObject();
					r.setNormalFieldValue(0, cur);
					Object b = exp.calculate(ctx);
					if (Variant.isTrue(b)) {
						findFirst = true;//?ҵ???
						for (int i = 0; i < count; ++i) {
							posArray.add(reader.readLong());
							for (int j = 0; j < posCount; ++j) {
								posArray.add(reader.readLong());
							}
						}
					} else {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}
						if (findFirst) {
							//??????һ????
							findFirst = false;
							break;
						}
					}
				}
				if (!findFirst) {
					//û?ҵ??????߶??ڵ?һ????????Һ?????
					break;
				}
				
				while (true) {
					int count = reader.readInt();
					if (count == BLOCK_START) {
						count = reader.readInt();
					} else if (count == BLOCK_END) {
						break;
					}

					Object cur = reader.readObject();
					r.setNormalFieldValue(0, cur);
					Object b = exp.calculate(ctx);
					if (Variant.isTrue(b)) {
						for (int i = 0; i < count; ++i) {
							posArray.add(reader.readLong());
							for (int j = 0; j < posCount; ++j) {
								posArray.add(reader.readLong());
							}
						}
					} else {
						break;
					}
				}
				
				break;
			case GE:
			case GT:
				reader.seek(seqPos);
				while (true) {
					int count = reader.readInt();
					Object cur = reader.readObject();
					int cmp = Variant.compare(cur, val, true);
					if (cmp < 0) {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}
					} else if (cmp == 0) {
						if (type == GE) {
							r.setNormalFieldValue(0, cur);
							Object b = exp.calculate(ctx);
							if (Variant.isTrue(b)) {
								for (int i = 0; i < count; ++i) {
									posArray.add(reader.readLong());
									for (int j = 0; j < posCount; ++j) {
										posArray.add(reader.readLong());
									}
								}
							} else {
								for (int i = 0; i < count; ++i) {
									reader.skipObject();
									for (int j = 0; j < posCount; ++j) {
										reader.skipObject();
									}
								}
							}
						} else {
							for (int i = 0; i < count; ++i) {
								reader.skipObject();
								for (int j = 0; j < posCount; ++j) {
									reader.skipObject();
								}
							}
						}
						
						break;
					} else {
						r.setNormalFieldValue(0, cur);
						Object b = exp.calculate(ctx);
						if (Variant.isTrue(b)) {
							for (int i = 0; i < count; ++i) {
								posArray.add(reader.readLong());
								for (int j = 0; j < posCount; ++j) {
									posArray.add(reader.readLong());
								}
							}
						} else {
							for (int i = 0; i < count; ++i) {
								reader.skipObject();
								for (int j = 0; j < posCount; ++j) {
									reader.skipObject();
								}
							}
						}

						break;
					}
				}

				while (true) {
					int count = reader.readInt();
					if (count == BLOCK_START) {
						count = reader.readInt();
					} else if (count == BLOCK_END) {
						break;
					}

					Object cur = reader.readObject();
					r.setNormalFieldValue(0, cur);
					Object b = exp.calculate(ctx);
					if (Variant.isTrue(b)) {
						for (int i = 0; i < count; ++i) {
							posArray.add(reader.readLong());
							for (int j = 0; j < posCount; ++j) {
								posArray.add(reader.readLong());
							}
						}
					} else {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}
					}
				}
				
				break;
			default: // LE LT
				reader.seek(startPos);
				while (seq > 0) {
					int count = reader.readInt();
					if (count == BLOCK_START) {
						seq--;
					} else {
						Object cur = reader.readObject();
						r.setNormalFieldValue(0, cur);
						Object b = exp.calculate(ctx);
						if (Variant.isTrue(b)) {
							for (int i = 0; i < count; ++i) {
								posArray.add(reader.readLong());
								for (int j = 0; j < posCount; ++j) {
									posArray.add(reader.readLong());
								}
							}
						} else {
							for (int i = 0; i < count; ++i) {
								reader.skipObject();
								for (int j = 0; j < posCount; ++j) {
									reader.skipObject();
								}
							}
						}
					}
				}
				
				while (true) {
					int count = reader.readInt();
					Object cur = reader.readObject();
					int cmp = Variant.compare(cur, val, true);
					if (cmp < 0) {
						r.setNormalFieldValue(0, cur);
						Object b = exp.calculate(ctx);
						if (Variant.isTrue(b)) {
							for (int i = 0; i < count; ++i) {
								posArray.add(reader.readLong());
								for (int j = 0; j < posCount; ++j) {
									posArray.add(reader.readLong());
								}
							}
						} else {
							for (int i = 0; i < count; ++i) {
								reader.skipObject();
								for (int j = 0; j < posCount; ++j) {
									reader.skipObject();
								}
							}
						}
					} else if (cmp == 0) {
						if (type == LE) {
							r.setNormalFieldValue(0, cur);
							Object b = exp.calculate(ctx);
							if (Variant.isTrue(b)) {
								for (int i = 0; i < count; ++i) {
									posArray.add(reader.readLong());
									for (int j = 0; j < posCount; ++j) {
										posArray.add(reader.readLong());
									}
								}
							}
						}
						
						break;
					} else {
						break;
					}
				}
				
				break;
			}
		} finally {
			stack.pop();
		}
		
		return posArray;
	}
	
	private LongArray readPos_m(ObjectReader reader, Object []vals, int seq, int type, long startPos, long seqPos) throws IOException {
		LongArray posArray = new LongArray(1024);
		int sc = vals.length;
		int icount = ifields.length;
		int posCount = this.positionCount;
		Object []keys = new Object[icount];
		
		Next:
		switch (type) {
		case EQ:
			reader.seek(seqPos);
			while (true) {
				// ???ֶ?????ʱ??ֻѡ?????ֶο??????ظ???
				int count = reader.readInt();
				if (count == BLOCK_START) {
					count = reader.readInt();
				} else if (count == BLOCK_END) {
					break;
				}
				
				for (int i = 0; i < icount; ++i) {
					keys[i] = reader.readObject();
				}
				
				int cmp = Variant.compareArrays(keys, vals, sc);
				if (cmp < 0) {
					for (int i = 0; i < count; ++i) {
						reader.skipObject();
						for (int j = 0; j < posCount; ++j) {
							reader.skipObject();
						}
					}
				} else if (cmp == 0) {
					for (int i = 0; i < count; ++i) {
						posArray.add(reader.readLong());
						for (int j = 0; j < posCount; ++j) {
							posArray.add(reader.readLong());
						}
					}
				} else {
					break;
				}
			}
			
			break;
		case GE:
		case GT:
			reader.seek(seqPos);
			while (true) {
				int count = reader.readInt();
				if (count == BLOCK_START) {
					count = reader.readInt();
				} else if (count == BLOCK_END) {
					break Next;
				}
				
				for (int i = 0; i < icount; ++i) {
					keys[i] = reader.readObject();
				}
				
				int cmp = Variant.compareArrays(keys, vals, sc);
				if (cmp > 0 || (cmp == 0 && type ==GE)) {
					for (int i = 0; i < count; ++i) {
						posArray.add(reader.readLong());
						for (int j = 0; j < posCount; ++j) {
							posArray.add(reader.readLong());
						}
					}

					break;
				} else {
					for (int i = 0; i < count; ++i) {
						reader.skipObject();
						for (int j = 0; j < posCount; ++j) {
							reader.skipObject();
						}
					}
				}
			}
			
			while (true) {
				int count = reader.readInt();
				if (count == BLOCK_START) {
					count = reader.readInt();
				} else if (count == BLOCK_END) {
					break;
				}

				for (int i = 0; i < icount; ++i) {
					reader.readObject();
				}

				for (int i = 0; i < count; ++i) {
					posArray.add(reader.readLong());
					for (int j = 0; j < posCount; ++j) {
						posArray.add(reader.readLong());
					}
				}
			}
			
			break;
		default: // LE LT
			reader.seek(startPos);
			int count;
			while (seq > 0) {
				count = reader.readInt();
				if (count == BLOCK_START) {
					seq--;
					continue;
				} else if (count == BLOCK_END) {
					break;
				}
				
				for (int i = 0; i < icount; ++i) {
					keys[i] = reader.readObject();
				}

				int cmp = Variant.compareArrays(keys, vals, sc);
				if (cmp < 0) {
					for (int i = 0; i < count; ++i) {
						posArray.add(reader.readLong());
						for (int j = 0; j < posCount; ++j) {
							posArray.add(reader.readLong());
						}
					}
				} else {
					if (cmp == 0 && type == LE) {
						for (int i = 0; i < count; ++i) {
							posArray.add(reader.readLong());
							for (int j = 0; j < posCount; ++j) {
								posArray.add(reader.readLong());
							}
						}
					} else {
						for (int i = 0; i < count; ++i) {
							reader.readLong();
							for (int j = 0; j < posCount; ++j) {
								reader.readLong();
							}
						}
					}
					break;
				}
			}
			while (true) {
				count = reader.readInt();
				if (count == BLOCK_START) {
					count = reader.readInt();
				} else if (count == BLOCK_END) {
					break;
				}
				
				for (int i = 0; i < icount; ++i) {
					keys[i] = reader.readObject();
				}

				int cmp = Variant.compareArrays(keys, vals, sc);
				if (cmp < 0) {
					for (int i = 0; i < count; ++i) {
						posArray.add(reader.readLong());
						for (int j = 0; j < posCount; ++j) {
							posArray.add(reader.readLong());
						}
					}
				} else if (cmp == 0 && type == LE) {
					for (int i = 0; i < count; ++i) {
						posArray.add(reader.readLong());
						for (int j = 0; j < posCount; ++j) {
							posArray.add(reader.readLong());
						}
					}
				} else {
					break;
				}
			}
			
			break;
		}
		
		return posArray;
	}
	
	private LongArray readPos_m(ObjectReader reader, Object []vals, int seq, int type, 
			Expression exp, Context ctx, long startPos, long seqPos) throws IOException {
		if (exp == null) {
			return readPos_m(reader, vals, seq, type, startPos, seqPos);
		}
		
		LongArray posArray = new LongArray(1024);
		int sc = vals.length;
		int icount = ifields.length;
		int posCount = this.positionCount;
		Object []keys = new Object[icount];
		
		DataStruct ds = new DataStruct(ifields);
		Record r = new Record(ds);
		
		ComputeStack stack = ctx.getComputeStack();
		stack.push(r);
		try {
			Next:
			switch (type) {
			case EQ:
				reader.seek(seqPos);
				while (true) {
					// ???ֶ?????ʱ??ֻѡ?????ֶο??????ظ???
					int count = reader.readInt();
					if (count == BLOCK_START) {
						count = reader.readInt();
					} else if (count == BLOCK_END) {
						break;
					}
					
					for (int i = 0; i < icount; ++i) {
						keys[i] = reader.readObject();
					}
					
					int cmp = Variant.compareArrays(keys, vals, sc);
					if (cmp < 0) {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}
					} else if (cmp == 0) {
						r.setStart(0, keys);
						Object b = exp.calculate(ctx);
						if (Variant.isTrue(b)) {
							for (int i = 0; i < count; ++i) {
								posArray.add(reader.readLong());
								for (int j = 0; j < posCount; ++j) {
									posArray.add(reader.readLong());
								}
							}
						} else {
							for (int i = 0; i < count; ++i) {
								reader.skipObject();
								for (int j = 0; j < posCount; ++j) {
									reader.skipObject();
								}
							}
						}
					} else {
						break;
					}
				}
				
				break;
			case GE:
			case GT:
				reader.seek(seqPos);
				while (true) {
					int count = reader.readInt();
					if (count == BLOCK_START) {
						count = reader.readInt();
					} else if (count == BLOCK_END) {
						break Next;
					}
					
					for (int i = 0; i < icount; ++i) {
						keys[i] = reader.readObject();
					}
					
					int cmp = Variant.compareArrays(keys, vals, sc);
					if (cmp > 0 || (cmp == 0 && type ==GE)) {
						r.setStart(0, keys);
						Object b = exp.calculate(ctx);
						if (Variant.isTrue(b)) {
							for (int i = 0; i < count; ++i) {
								posArray.add(reader.readLong());
								for (int j = 0; j < posCount; ++j) {
									posArray.add(reader.readLong());
								}
							}
						} else {
							for (int i = 0; i < count; ++i) {
								reader.skipObject();
								for (int j = 0; j < posCount; ++j) {
									reader.skipObject();
								}
							}
						}

						break;
					} else {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}
					}
				}
				
				while (true) {
					int count = reader.readInt();
					if (count == BLOCK_START) {
						count = reader.readInt();
					} else if (count == BLOCK_END) {
						break;
					}

					for (int i = 0; i < icount; ++i) {
						keys[i] = reader.readObject();
					}

					r.setStart(0, keys);
					Object b = exp.calculate(ctx);
					if (Variant.isTrue(b)) {
						for (int i = 0; i < count; ++i) {
							posArray.add(reader.readLong());
							for (int j = 0; j < posCount; ++j) {
								posArray.add(reader.readLong());
							}
						}
					} else {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}
					}
				}
				
				break;
			default: // LE LT
				reader.seek(startPos);
				int count;
				while (seq > 0) {
					count = reader.readInt();
					if (count == BLOCK_START) {
						//count = reader.readInt();
						seq--;
						continue;
					} 
					
					for (int i = 0; i < icount; ++i) {
						keys[i] = reader.readObject();
					}

					int cmp = Variant.compareArrays(keys, vals, sc);
					if (cmp < 0) {
						r.setStart(0, keys);
						Object b = exp.calculate(ctx);
						if (Variant.isTrue(b)) {
							for (int i = 0; i < count; ++i) {
								posArray.add(reader.readLong());
								for (int j = 0; j < posCount; ++j) {
									posArray.add(reader.readLong());
								}
							}
						} else {
							for (int i = 0; i < count; ++i) {
								reader.skipObject();
								for (int j = 0; j < posCount; ++j) {
									reader.skipObject();
								}
							}
						}
					} else {
						if (cmp == 0 && type == LE) {
							
							r.setStart(0, keys);
							Object b = exp.calculate(ctx);
							if (Variant.isTrue(b)) {
								for (int i = 0; i < count; ++i) {
									posArray.add(reader.readLong());
									for (int j = 0; j < posCount; ++j) {
										posArray.add(reader.readLong());
									}
								}
							} else {
								for (int i = 0; i < count; ++i) {
									reader.skipObject();
									for (int j = 0; j < posCount; ++j) {
										reader.skipObject();
									}
								}
							}
						} else {
							for (int i = 0; i < count; ++i) {
								reader.skipObject();
								for (int j = 0; j < posCount; ++j) {
									reader.skipObject();
								}
							}
						}
						break;
					}
					

				}
				while (true) {
					count = reader.readInt();
					if (count == BLOCK_START) {
						count = reader.readInt();
					} else if (count == BLOCK_END) {
						break;
					}
					
					for (int i = 0; i < icount; ++i) {
						keys[i] = reader.readObject();
					}

					int cmp = Variant.compareArrays(keys, vals, sc);
					if (cmp < 0) {
						r.setStart(0, keys);
						Object b = exp.calculate(ctx);
						if (Variant.isTrue(b)) {
							for (int i = 0; i < count; ++i) {
								posArray.add(reader.readLong());
								for (int j = 0; j < posCount; ++j) {
									posArray.add(reader.readLong());
								}
							}
						} else {
							for (int i = 0; i < count; ++i) {
								reader.skipObject();
								for (int j = 0; j < posCount; ++j) {
									reader.skipObject();
								}
							}
						}
					} else if (cmp == 0 && type == LE) {
						r.setStart(0, keys);
						Object b = exp.calculate(ctx);
						if (Variant.isTrue(b)) {
							for (int i = 0; i < count; ++i) {
								posArray.add(reader.readLong());
								for (int j = 0; j < posCount; ++j) {
									posArray.add(reader.readLong());
								}
							}
						} else {
							for (int i = 0; i < count; ++i) {
								reader.skipObject();
								for (int j = 0; j < posCount; ++j) {
									reader.skipObject();
								}
							}
						}
					} else {
						break;
					}
				}
				
				break;
			}
		} finally {
			stack.pop();
		}
		
		return posArray;
	}
	
	private LongArray readPos_s(ObjectReader reader, Object startVal, int start, boolean le, 
			Object endVal, int end, boolean re, long startPos) throws IOException {
		LongArray posArray = new LongArray(1024);
		int posCount = this.positionCount;
		reader.seek(startPos);
		
		while (true) {
			int count = reader.readInt();
			Object cur = reader.readObject();
			int cmp = Variant.compare(cur, startVal, true);
			if (cmp < 0) {
				for (int i = 0; i < count; ++i) {
					reader.skipObject();
					for (int j = 0; j < posCount; ++j) {
						reader.skipObject();
					}
				}
			} else if (cmp == 0) {
				if (le) {
					for (int i = 0; i < count; ++i) {
						posArray.add(reader.readLong());
						for (int j = 0; j < posCount; ++j) {
							posArray.add(reader.readLong());
						}
					}
				} else {
					for (int i = 0; i < count; ++i) {
						reader.skipObject();
						for (int j = 0; j < posCount; ++j) {
							reader.skipObject();
						}
					}
				}
				
				break;
			} else {
				cmp = Variant.compare(cur, endVal, true);
				if (cmp < 0) {
					for (int i = 0; i < count; ++i) {
						posArray.add(reader.readLong());
						for (int j = 0; j < posCount; ++j) {
							posArray.add(reader.readLong());
						}
					}
	
					break;
				} else if (cmp == 0 && re) {
					for (int i = 0; i < count; ++i) {
						posArray.add(reader.readLong());
						for (int j = 0; j < posCount; ++j) {
							posArray.add(reader.readLong());
						}
					}
					
					return posArray;
				} else {
					return null;
				}
			}
		}

		while (start < end) {
			int count = reader.readInt();
			if (count == BLOCK_START) {
				start++;
			} else {
				reader.readObject();
				for (int i = 0; i < count; ++i) {
					posArray.add(reader.readLong());
					for (int j = 0; j < posCount; ++j) {
						posArray.add(reader.readLong());
					}
				}
			}
		}

		while (true) {
			int count = reader.readInt();
			if (count < 1) break;
			
			Object cur = reader.readObject();
			int cmp = Variant.compare(cur, endVal, true);
			if (cmp < 0) {
				for (int i = 0; i < count; ++i) {
					posArray.add(reader.readLong());
					for (int j = 0; j < posCount; ++j) {
						posArray.add(reader.readLong());
					}
				}
			} else {
				if (cmp == 0 && re) {
					for (int i = 0; i < count; ++i) {
						posArray.add(reader.readLong());
						for (int j = 0; j < posCount; ++j) {
							posArray.add(reader.readLong());
						}
					}
				}
				
				break;
			}
		}
		
		return posArray;
	}

	private LongArray readPos_s(ObjectReader reader, Object startVal, int start, boolean le, 
			Object endVal, int end, boolean re, Expression exp, Context ctx, long startPos) throws IOException {
		if (exp == null) {
			return readPos_s(reader, startVal, start, le, endVal, end, re, startPos);
		}
		
		LongArray posArray = new LongArray(1024);
		int posCount = this.positionCount;
		reader.seek(startPos);
		
		DataStruct ds = new DataStruct(ifields);
		Record r = new Record(ds);
		ComputeStack stack = ctx.getComputeStack();
		stack.push(r);
		
		try {
			while (true) {
				int count = reader.readInt();
				Object cur = reader.readObject();
				int cmp = Variant.compare(cur, startVal, true);
				if (cmp < 0) {
					for (int i = 0; i < count; ++i) {
						reader.skipObject();
						for (int j = 0; j < posCount; ++j) {
							reader.skipObject();
						}
					}
				} else if (cmp == 0) {
					if (le) {
						r.setNormalFieldValue(0, cur);
						Object b = exp.calculate(ctx);
						if (Variant.isTrue(b)) {
							for (int i = 0; i < count; ++i) {
								posArray.add(reader.readLong());
								for (int j = 0; j < posCount; ++j) {
									posArray.add(reader.readLong());
								}
							}
						} else {
							for (int i = 0; i < count; ++i) {
								reader.skipObject();
								for (int j = 0; j < posCount; ++j) {
									reader.skipObject();
								}
							}
						}
					} else {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}
					}
					
					break;
				} else {
					cmp = Variant.compare(cur, endVal, true);
					if (cmp < 0) {
						r.setNormalFieldValue(0, cur);
						Object b = exp.calculate(ctx);
						if (Variant.isTrue(b)) {
							for (int i = 0; i < count; ++i) {
								posArray.add(reader.readLong());
								for (int j = 0; j < posCount; ++j) {
									posArray.add(reader.readLong());
								}
							}
						} else {
							for (int i = 0; i < count; ++i) {
								reader.skipObject();
								for (int j = 0; j < posCount; ++j) {
									reader.skipObject();
								}
							}
						}

						break;
					} else if (cmp == 0 && re) {
						r.setNormalFieldValue(0, cur);
						Object b = exp.calculate(ctx);
						if (Variant.isTrue(b)) {
							for (int i = 0; i < count; ++i) {
								posArray.add(reader.readLong());
								for (int j = 0; j < posCount; ++j) {
									posArray.add(reader.readLong());
								}
							}
							
							return posArray;
						} else {
							return null;
						}
					} else {
						return null;
					}
				}
			}
	
			while (start < end) {
				int count = reader.readInt();
				if (count == BLOCK_START) {
					start++;
				} else {
					Object cur = reader.readObject();
					r.setNormalFieldValue(0, cur);
					Object b = exp.calculate(ctx);
					if (Variant.isTrue(b)) {
						for (int i = 0; i < count; ++i) {
							posArray.add(reader.readLong());
							for (int j = 0; j < posCount; ++j) {
								posArray.add(reader.readLong());
							}
						}
					} else {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}
					}
				}
			}
	
			while (true) {
				int count = reader.readInt();
				if (count < 1) break;
				
				Object cur = reader.readObject();
				int cmp = Variant.compare(cur, endVal, true);
				if (cmp < 0) {
					r.setNormalFieldValue(0, cur);
					Object b = exp.calculate(ctx);
					if (Variant.isTrue(b)) {
						for (int i = 0; i < count; ++i) {
							posArray.add(reader.readLong());
							for (int j = 0; j < posCount; ++j) {
								posArray.add(reader.readLong());
							}
						}
					} else {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}
					}
				} else {
					if (cmp == 0 && re) {
						r.setNormalFieldValue(0, cur);
						Object b = exp.calculate(ctx);
						if (Variant.isTrue(b)) {
							for (int i = 0; i < count; ++i) {
								posArray.add(reader.readLong());
								for (int j = 0; j < posCount; ++j) {
									posArray.add(reader.readLong());
								}
							}
						} else {
							for (int i = 0; i < count; ++i) {
								reader.skipObject();
								for (int j = 0; j < posCount; ++j) {
									reader.skipObject();
								}
							}
						}
					}
					
					break;
				}
			}
		} finally {
			stack.pop();
		}
		
		return posArray;
	}

	private LongArray readPos_m(ObjectReader reader, Object []startVals, int start, boolean le, 
			Object []endVals, int end, boolean re, long startPos) throws IOException {
		LongArray posArray = new LongArray(1024);
		int icount = ifields.length;
		int posCount = this.positionCount;
		int sc = startVals.length;
		Object []keys = new Object[icount];
		reader.seek(startPos);
		
		while (true) {
			int count = reader.readInt();
			if (count == BLOCK_START) {
				count = reader.readInt();
				start++;
			} else if (count == BLOCK_END) {
				return posArray;
			}
			
			for (int i = 0; i < icount; ++i) {
				keys[i] = reader.readObject();
			}

			int cmp = Variant.compareArrays(keys, startVals, sc);
			if (cmp < 0) {
				for (int i = 0; i < count; ++i) {
					reader.skipObject();
					for (int j = 0; j < posCount; ++j) {
						reader.skipObject();
					}
				}
			} else if (cmp == 0) {
				if (le) {
					for (int i = 0; i < count; ++i) {
						posArray.add(reader.readLong());
						for (int j = 0; j < posCount; ++j) {
							posArray.add(reader.readLong());
						}
					}
					
					break;
				} else {
					for (int i = 0; i < count; ++i) {
						reader.skipObject();
						for (int j = 0; j < posCount; ++j) {
							reader.skipObject();
						}
					}
				}
			} else {
				cmp = Variant.compareArrays(keys, endVals, sc);
				if (cmp < 0 || (cmp == 0 && re)) {
					for (int i = 0; i < count; ++i) {
						posArray.add(reader.readLong());
						for (int j = 0; j < posCount; ++j) {
							posArray.add(reader.readLong());
						}
					}
	
					break;
				} else {
					return null;
				}
			}
		}

		int count;
		while (start < end) {
			count = reader.readInt();
			if (count == BLOCK_START) {
				start++;
				continue;
			} else if (count == BLOCK_END) {
				break;
			}
			
			for (int i = 0; i < icount; ++i) {
				keys[i] = reader.readObject();
			}

			int cmp = Variant.compareArrays(keys, endVals, sc);
			if (cmp < 0) {
				for (int i = 0; i < count; ++i) {
					posArray.add(reader.readLong());
					for (int j = 0; j < posCount; ++j) {
						posArray.add(reader.readLong());
					}
				}
			} else {
				if (cmp == 0 && re) {
					for (int i = 0; i < count; ++i) {
						posArray.add(reader.readLong());
						for (int j = 0; j < posCount; ++j) {
							posArray.add(reader.readLong());
						}
					}
				} else {
					for (int i = 0; i < count; ++i) {
						reader.readLong();
						for (int j = 0; j < posCount; ++j) {
							reader.readLong();
						}
					}
				}
				break;

			}
			
		}
		while (true) {
			count = reader.readInt();
			if (count == BLOCK_START) {
				count = reader.readInt();
			} else if (count == BLOCK_END) {
				break;
			}
			
			for (int i = 0; i < icount; ++i) {
				keys[i] = reader.readObject();
			}

			int cmp = Variant.compareArrays(keys, endVals, sc);
			if (cmp < 0 || (cmp == 0 && re)) {
				for (int i = 0; i < count; ++i) {
					posArray.add(reader.readLong());
					for (int j = 0; j < posCount; ++j) {
						posArray.add(reader.readLong());
					}
				}
			} else {
				break;
			}
		}
		
		return posArray;
	}

	private LongArray readPos_m(ObjectReader reader, Object []startVals, int start, boolean le, 
			Object []endVals, int end, boolean re, Expression exp, Context ctx, long startPos) throws IOException {
		if (exp == null) {
			return readPos_m(reader, startVals, start, le, endVals, end, re, startPos);
		}
		
		LongArray posArray = new LongArray(1024);
		int icount = ifields.length;
		int posCount = this.positionCount;
		int sc = startVals.length;
		Object []keys = new Object[icount];
		reader.seek(startPos);
		
		DataStruct ds = new DataStruct(ifields);
		Record r = new Record(ds);
		ComputeStack stack = ctx.getComputeStack();
		stack.push(r);
		
		try {
			while (true) {
				int count = reader.readInt();
				if (count == BLOCK_START) {
					count = reader.readInt();
					start++;
				} else if (count == BLOCK_END) {
					if (posArray.size() > 0) {
						return posArray;
					} else {
						return null;
					}
				}
				
				for (int i = 0; i < icount; ++i) {
					keys[i] = reader.readObject();
				}
	
				int cmp = Variant.compareArrays(keys, startVals, sc);
				if (cmp < 0) {
					for (int i = 0; i < count; ++i) {
						reader.skipObject();
						for (int j = 0; j < posCount; ++j) {
							reader.skipObject();
						}
					}
				} else if (cmp == 0) {
					if (le) {
						r.setStart(0, keys);
						Object b = exp.calculate(ctx);
						if (Variant.isTrue(b)) {
							for (int i = 0; i < count; ++i) {
								posArray.add(reader.readLong());
								for (int j = 0; j < posCount; ++j) {
									posArray.add(reader.readLong());
								}
							}
						} else {
							for (int i = 0; i < count; ++i) {
								reader.skipObject();
								for (int j = 0; j < posCount; ++j) {
									reader.skipObject();
								}
							}
						}
						
						break;
					} else {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}
					}
				} else {
					cmp = Variant.compareArrays(keys, endVals, sc);
					if (cmp < 0 || (cmp == 0 && re)) {
						r.setStart(0, keys);
						Object b = exp.calculate(ctx);
						if (Variant.isTrue(b)) {
							for (int i = 0; i < count; ++i) {
								posArray.add(reader.readLong());
								for (int j = 0; j < posCount; ++j) {
									posArray.add(reader.readLong());
								}
							}
						} else {
							for (int i = 0; i < count; ++i) {
								reader.skipObject();
								for (int j = 0; j < posCount; ++j) {
									reader.skipObject();
								}
							}
						}
		
						break;
					} else {
						return null;
					}
				}
			}
	
			int count;
			while (start < end) {
				count = reader.readInt();
				if (count == BLOCK_START) {
					start++;
					continue;
				}
				
				for (int i = 0; i < icount; ++i) {
					keys[i] = reader.readObject();
				}
	
				int cmp = Variant.compareArrays(keys, endVals, sc);
				if (cmp < 0) {
					r.setStart(0, keys);
					Object b = exp.calculate(ctx);
					if (Variant.isTrue(b)) {
						for (int i = 0; i < count; ++i) {
							posArray.add(reader.readLong());
							for (int j = 0; j < posCount; ++j) {
								posArray.add(reader.readLong());
							}
						}
					} else {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}
					}
				} else {
					if  (cmp == 0 && re) {
						r.setStart(0, keys);
							Object b = exp.calculate(ctx);
							if (Variant.isTrue(b)) {
								for (int i = 0; i < count; ++i) {
									posArray.add(reader.readLong());
									for (int j = 0; j < posCount; ++j) {
										posArray.add(reader.readLong());
									}
								}
							} else {
								for (int i = 0; i < count; ++i) {
									reader.skipObject();
									for (int j = 0; j < posCount; ++j) {
										reader.skipObject();
									}
								}
							}
					} else {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}	
					}					
					break;
				}
			}
			while (true) {
				count = reader.readInt();
				if (count == BLOCK_START) {
					count = reader.readInt();
				} else if (count == BLOCK_END) {
					break;
				}
				
				for (int i = 0; i < icount; ++i) {
					keys[i] = reader.readObject();
				}
	
				int cmp = Variant.compareArrays(keys, endVals, sc);
				if (cmp < 0 || (cmp == 0 && re)) {
					r.setStart(0, keys);
					Object b = exp.calculate(ctx);
					if (Variant.isTrue(b)) {
						for (int i = 0; i < count; ++i) {
							posArray.add(reader.readLong());
							for (int j = 0; j < posCount; ++j) {
								posArray.add(reader.readLong());
							}
						}
					} else {
						for (int i = 0; i < count; ++i) {
							reader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								reader.skipObject();
							}
						}
					}
				} else {
					break;
				}
			}
		} finally {
			stack.pop();
		}
		
		return posArray;
	}
	
	private static void concat(LongArray a, LongArray b) {
		if (b == null) return;
		int size = b.size();
		if (size == 0) return;
		for (int i = 0; i < size; i++) {
			a.add(b.get(i));
		}
	}
	
//	private LongArray concatAndSort(LongArray a, LongArray b) {
//		if (b == null) return a;
//		int sizeB = b.size();
//		if (sizeB == 0) return a;
//		
//		int sizeA = a.size();
//		int i = 0, j = 0;
//		LongArray c = new LongArray(sizeA + sizeB);
//		if (srcTable instanceof RowTableMetaData) {
//			int count = positionCount + 1;
//			while (i < sizeA && j < sizeB) {
//				long valueA = a.get(i + 1);
//				long valueB = b.get(j + 1);
//				if (valueA < valueB) {
//					for (int k = 0; k < count; k++) {
//						c.add(a.get(i));
//						i++;
//					}
//				} else {
//					for (int k = 0; k < count; k++) {
//						c.add(b.get(j));
//						j++;
//					}
//				}
//			}
//		} else {
//			while (i < sizeA && j < sizeB) {
//				if (a.get(i) < b.get(j)) {
//					c.add(a.get(i));
//					i++;
//				} else {
//					c.add(b.get(j));
//					j++;
//				}
//			}
//		}
//		
//		while (i < sizeA) {
//			c.add(a.get(i));
//			i++;
//		}
//		while (j < sizeB) {
//			c.add(b.get(j));
//			j++;
//		}
//		return c;
//	}
	
	//index@2
	public synchronized void loadAllBlockInfo() {
		if (internalAllBlockPos!= null) return;
		readBlockInfo(indexFile);//load root info
		
		int rootCount = this.rootBlockMaxVals.length;
		internalAllBlockMaxVals = new Object[rootCount][];
		internalAllBlockPos = new long[rootCount][];
		
		BlockInfo blockInfo = new BlockInfo();
		for (int i = 0; i < rootCount; ++i) {
			readInternalBlockInfo(indexFile, rootBlockPos[i], blockInfo);
			internalAllBlockMaxVals[i] = blockInfo.internalBlockMaxVals;
			internalAllBlockPos[i] = blockInfo.internalBlockPos;
		}
		
		if (rootBlockPos2 != null) {
			rootCount = this.rootBlockMaxVals2.length;
			internalAllBlockMaxVals2 = new Object[rootCount][];
			internalAllBlockPos2 = new long[rootCount][];
			for (int i = 0; i < rootCount; ++i) {
				readInternalBlockInfo(indexFile, rootBlockPos2[i], blockInfo);
				internalAllBlockMaxVals2[i] = blockInfo.internalBlockMaxVals;
				internalAllBlockPos2[i] = blockInfo.internalBlockPos;
			}
		}
	}
	
	//index@3
	public synchronized void loadAllKeys() {
		if (internalAllBlockPos!= null) return;
		
		//????Ƿ??Ƕ?????????????
		boolean isPrimaryKey = false;
		String[] keyNames = srcTable.getAllSortedColNames();
		if (srcTable.hasPrimaryKey && keyNames != null && ifields.length == keyNames.length) {
			isPrimaryKey = true;
			for (int i = 0, len = ifields.length; i < len; ++i) {
				if (!ifields[i].equals(keyNames[i])) {
					isPrimaryKey = false;
					break;
				}
			}
		}
		this.isPrimaryKey = isPrimaryKey;
		
		readBlockInfo(indexFile);//load root info
		
		int rootCount = this.rootBlockMaxVals.length;
		internalAllBlockMaxVals = new Object[rootCount][];
		internalAllBlockPos = new long[rootCount][];
		
		BlockInfo blockInfo = new BlockInfo();
		for (int i = 0; i < rootCount; ++i) {
			readInternalBlockInfo(indexFile, rootBlockPos[i], blockInfo);
			internalAllBlockMaxVals[i] = blockInfo.internalBlockMaxVals;
			internalAllBlockPos[i] = blockInfo.internalBlockPos;
		}
		
		if (rootBlockPos2 != null) {
			rootCount = this.rootBlockMaxVals2.length;
			internalAllBlockMaxVals2 = new Object[rootCount][];
			internalAllBlockPos2 = new long[rootCount][];
			for (int i = 0; i < rootCount; ++i) {
				readInternalBlockInfo(indexFile, rootBlockPos2[i], blockInfo);
				internalAllBlockMaxVals2[i] = blockInfo.internalBlockMaxVals;
				internalAllBlockPos2[i] = blockInfo.internalBlockPos;
			}
		}
		
		int icount = ifields.length;
		int posCount = this.positionCount;
		boolean needRecNum = true;
		if (srcTable instanceof RowPhyTable) {
			needRecNum = srcTable.getModifyRecords() != null;
		}
		
		cachedBlockReader = new byte[rootCount][][];
		int parallelNum = Env.getParallelNum();
		if (parallelNum > 8) parallelNum = 8;
		if (parallelNum > rootCount) parallelNum = rootCount;
		int avg = rootCount / parallelNum;
		Thread []threads = new Thread[parallelNum];
		for (int i = 0; i < parallelNum; ++i) {
			InputStream is = indexFile.getInputStream();
			ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);
			if (i + 1 == parallelNum) {
				threads[i] = newLoadDataThread(needRecNum, cachedBlockReader, internalAllBlockPos, reader, icount,
						i * avg, rootCount, posCount);
			} else {
				threads[i] = newLoadDataThread(needRecNum, cachedBlockReader, internalAllBlockPos, reader, icount,
						i * avg, (i + 1) * avg, posCount);
			}
			threads[i].start(); // ?????߳?
		}
		// ?ȴ????????߳̽???
		for (int i = 0; i < parallelNum; ++i) {
			try {
				threads[i].join();
			} catch (InterruptedException e) {
				throw new RQException(e);
			}
		}
		
		if (rootBlockPos2 != null) {
			cachedBlockReader2 = new byte[rootCount][][];
			parallelNum = Env.getParallelNum();
			if (parallelNum > 8) parallelNum = 8;
			rootCount = this.rootBlockMaxVals2.length;
			cachedBlockReader2 = new byte[rootCount][][];
			if (parallelNum > rootCount) parallelNum = rootCount;
			avg = rootCount / parallelNum;
			threads = new Thread[parallelNum];
			for (int i = 0; i < parallelNum; ++i) {
				InputStream is = indexFile.getInputStream();
				ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);
				if (i + 1 == parallelNum) {
					threads[i] = newLoadDataThread(needRecNum, cachedBlockReader2, internalAllBlockPos2, reader, icount,
							i * avg, rootCount, posCount);
				} else {
					threads[i] = newLoadDataThread(needRecNum, cachedBlockReader2, internalAllBlockPos2, reader, icount,
							i * avg, (i + 1) * avg, posCount);
				}
				threads[i].start(); // ?????߳?
			}
			// ?ȴ????????߳̽???
			for (int i = 0; i < parallelNum; ++i) {
				try {
					threads[i].join();
				} catch (InterruptedException e) {
					throw new RQException(e);
				}
			}
		}
		
		try {
//			rootCount = this.rootBlockMaxVals.length;
//			cachedBlockReader = new byte[rootCount][][];
//			for (int c = 0; c < rootCount; ++c) {
//				int len = internalAllBlockPos[c].length;
//				cachedBlockReader[c] = new byte[len][];
//				for (int i = 0; i < len; ++i) {
//					reader.seek(internalAllBlockPos[c][i]);
//					BufferWriter writer = new BufferWriter(null);
//					long lastPos = -1;
//					while (true) {
//						int count = reader.readInt();
//						writer.writeInt(count);
//
//						if (count == BLOCK_START) {
//							break;
//						} else if (count == BLOCK_END) {
//							break;
//						}
//						
//						for (int j = 0; j < icount; ++j) {
//							writer.writeObject(reader.readObject());
//						}
//						writer.flush();
//						
//						for (int j = 0; j < count; ++j) {
//							if (needRecNum) {
//								writer.writeLong(reader.readLong());
//							} else {
//								//û?в???ʱ????Ҫα??
//								reader.readLong();
//								writer.writeLong(0);
//							}
//							
//							for (int k = 0; k < posCount; ++k) {
//								long pos = reader.readLong();
//								if (lastPos == -1) {
//									writer.writeLong(pos);
//									lastPos = pos;
//								} else {
//									writer.writeLong(pos - lastPos);
//								}
//								
//							}
//						}
//					}
//					writer.flush();
//					cachedBlockReader[c][i] = writer.finish();
//				}
//			}
			
//			if (rootBlockPos2 != null) {
//				rootCount = this.rootBlockMaxVals2.length;
//				cachedBlockReader2 = new byte[rootCount][][];
//				for (int c = 0; c < rootCount; ++c) {
//					int len = internalAllBlockPos2[c].length;
//					cachedBlockReader2[c] = new byte[len][];
//					for (int i = 0; i < len; ++i) {
//						reader.seek(internalAllBlockPos2[c][i]);
//						BufferWriter writer = new BufferWriter(null);
//						
//						while (true) {
//							int count = reader.readInt();
//							writer.writeInt(count);
//	
//							if (count == BLOCK_START) {
//								break;
//							} else if (count == BLOCK_END) {
//								break;
//							}
//							
//							for (int j = 0; j < icount; ++j) {
//								writer.writeObject(reader.readObject());
//							}
//							writer.flush();
//							
//							for (int j = 0; j < count; ++j) {
//								if (needRecNum) {
//									writer.writeLong(reader.readLong());
//								} else {
//									//û?в???ʱ????Ҫα??
//									reader.readLong();
//									writer.writeLong(0);
//								}
//								
//								for (int k = 0; k < posCount; ++k) {
//									writer.writeLong(reader.readLong());
//								}
//							}
//						}
//						writer.flush();
//						cachedBlockReader2[c][i] = writer.finish();
//					}
//				}
//			}
			
			boolean isRow = srcTable.parent == null && srcTable instanceof RowPhyTable;
			RowBufferWriter writer = new RowBufferWriter(null);
			int maxLen = 0;
			ICursor cs = srcTable.cursor();
			Sequence table = cs.fetch(ICursor.FETCHCOUNT);
			while (table != null && table.length() != 0) {
				if (isRow) {
					IArray mems = table.getMems();
					int size = mems.size();
					for (int j = 1; j <= size; j++) {
						Record r = (Record)mems.get(j);
						Object []vals = r.getFieldValues();
						int len = 9;
						writer.reset();
						for (Object obj : vals) {
							writer.writeObject(obj);
						}
						len += writer.getCount();
						if (len > maxLen) {
							maxLen = len;
						}
					}
				}
				//ȫ????̫??ʱ??????ֻȡ??ͷ??һ??????Ԥ??
				//table = cs.fetch(ICursor.FETCHCOUNT);
				table = null;
			}
			cs.close();
			maxRecordLen = maxLen + maxLen;
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		}
		
		Runtime rt = Runtime.getRuntime();
		EnvUtil.runGC(rt);
	}
	
	private static Thread newLoadDataThread(final boolean needRecNum, final byte [][][]cachedBlockReader, 
			final long [][]internalAllBlockPos, final ObjectReader reader, final int icount, 
			final int start, final int end, final int posCount) {
		return new Thread() {
			public void run() {
				try {
					//?ѵ??????key???浽buffer??ͬʱ??ַҲ??ָ???ڴ?
					for (int c = start; c < end; ++c) {

						int len = internalAllBlockPos[c].length;
						cachedBlockReader[c] = new byte[len][];
						for (int i = 0; i < len; ++i) {
							reader.seek(internalAllBlockPos[c][i]);
							BufferWriter writer = new BufferWriter(null);
							long lastPos = -1;
							while (true) {
								int count = reader.readInt();
								writer.writeInt(count);

								if (count == BLOCK_START) {
									break;
								} else if (count == BLOCK_END) {
									break;
								}
								
								for (int j = 0; j < icount; ++j) {
									writer.writeObject(reader.readObject());
								}
								writer.flush();
								
								for (int j = 0; j < count; ++j) {
									if (needRecNum) {
										writer.writeLong(reader.readLong());
									} else {
										//û?в???ʱ????Ҫα??
										reader.readLong();
										writer.writeLong(0);
									}
									
									for (int k = 0; k < posCount; ++k) {
										long pos = reader.readLong();
										if (lastPos == -1) {
											writer.writeLong(pos);
											lastPos = pos;
										} else {
											writer.writeLong(pos - lastPos);
										}
										
									}
								}
							}
							writer.flush();
							cachedBlockReader[c][i] = writer.finish();
						}
					
					}
				} catch (IOException e) {
					throw new RQException(e.getMessage(), e);
				} finally {
					try {
						reader.close();
					} catch (IOException ie){};
				}
			}
		};
	}
	
	public void unloadAllBlockInfo() {
		internalAllBlockMaxVals = null;
		internalAllBlockPos = null;
		internalAllBlockMaxVals2 = null;
		internalAllBlockPos2 = null;
		Runtime rt = Runtime.getRuntime();
		EnvUtil.runGC(rt);
	}

	//???????Ļ????????
	private int readPos_p_cache(Sequence vals, int srcIndex, 
			Object []blockMaxVals, byte [][]blockBuffers, LongArray outPos) throws IOException {
		IArray mems = vals.getMems();
		Object srcVal = mems.get(srcIndex);
		int block = binarySearch(blockMaxVals, srcVal);
		if (block < 0) return srcIndex;
		
		int blockCount = blockBuffers.length;
		BufferReader bufferReader = new BufferReader(null, blockBuffers[block]);
		int srcLen = mems.size();
		LongArray posArray = outPos;//new LongArray(srcLen * (posCount + 1));
		long firstPos = -1;
		Next:
		while (true) {
			int count = bufferReader.readInt();
			if (count == BLOCK_START) {
				// ????ʱ?Ƚ?һ???Ƿ??????鶼?ȵ?ǰҪȡ??ֵС???????????????
				while (true) {
					block++;
					if (block >= blockCount) break Next;
					
					if (Variant.compare(blockMaxVals[block], srcVal, true) >= 0) {
						bufferReader = new BufferReader(null, blockBuffers[block]);
						firstPos = -1;
						break;
					}
				}

				count = bufferReader.readInt();
			} else if (count == BLOCK_END) {
				break;
			}
			
			Object cur = bufferReader.readObject();
			int cmp = Variant.compare(cur, srcVal, true);
			if (cmp < 0) {
				bufferReader.skipObject();
				if (firstPos == -1) {
					firstPos = bufferReader.readLong();
				} else {
					bufferReader.skipObject();
				}
			} else if (cmp == 0) {
				posArray.add(bufferReader.readLong());
				if (firstPos == -1) {
					firstPos = bufferReader.readLong();
					posArray.add(firstPos);
				} else {
					posArray.add(bufferReader.readLong() + firstPos);
				}
				
				srcIndex++;
				if (srcIndex > srcLen) break;
				
				srcVal = mems.get(srcIndex);
				
				//????µ?Ҫ???ҵ?ֵ???ڱ??????ֵ????????
				if (Variant.compare(blockMaxVals[block], srcVal, true) < 0) {
					while (true) {
						block++;
						if (block >= blockCount) break Next;
						
						if (Variant.compare(blockMaxVals[block], srcVal, true) >= 0) {
							bufferReader = new BufferReader(null, blockBuffers[block]);
							firstPos = -1;
							break;
						}
					}
				}
			} else {
				while (true) {
					srcIndex++;
					if (srcIndex > srcLen) break Next;
					
					srcVal = mems.get(srcIndex);
					cmp = Variant.compare(cur, srcVal, true);
					if (cmp < 0) {
						bufferReader.skipObject();
						if (firstPos == -1) {
							firstPos = bufferReader.readLong();
						} else {
							bufferReader.skipObject();
						}
						
						continue Next;
					} else if (cmp == 0) {
						posArray.add(bufferReader.readLong());
						if (firstPos == -1) {
							firstPos = bufferReader.readLong();
							posArray.add(firstPos);
						} else {
							posArray.add(bufferReader.readLong() + firstPos);
						}
						
						srcIndex++;
						if (srcIndex > srcLen) break Next;
						
						srcVal = mems.get(srcIndex);
						continue Next;
					}
				}
			}
		}
		if (srcIndex > srcLen) {
			return -1;
		}
		return srcIndex;
	}
	
	private int readPos_s_cache(Sequence vals, int srcIndex, 
			Object []blockMaxVals, byte [][]blockBuffers, LongArray outPos) throws IOException {
		if (positionCount == 1 && isPrimaryKey) {
			return readPos_p_cache(vals, srcIndex, blockMaxVals, blockBuffers, outPos);
		}
		IArray mems = vals.getMems();
		Object srcVal = mems.get(srcIndex);
		int block = binarySearch(blockMaxVals, srcVal);
		if (block < 0) return srcIndex;
		
		int posCount = this.positionCount;
		int blockCount = blockBuffers.length;
		BufferReader bufferReader = new BufferReader(null, blockBuffers[block]);
		int srcLen = mems.size();
		LongArray posArray = outPos;//new LongArray(srcLen * (posCount + 1));
		long firstPos = -1;
		Next:
		while (true) {
			int count = bufferReader.readInt();
			if (count == BLOCK_START) {
				// ????ʱ?Ƚ?һ???Ƿ??????鶼?ȵ?ǰҪȡ??ֵС???????????????
				while (true) {
					block++;
					if (block >= blockCount) break Next;
					
					if (Variant.compare(blockMaxVals[block], srcVal, true) >= 0) {
						bufferReader = new BufferReader(null, blockBuffers[block]);
						firstPos = -1;
						break;
					}
				}

				count = bufferReader.readInt();
			} else if (count == BLOCK_END) {
				break;
			}
			
			Object cur = bufferReader.readObject();
			int cmp = Variant.compare(cur, srcVal, true);
			if (cmp < 0) {
				for (int i = 0; i < count; ++i) {
					bufferReader.skipObject();
					for (int j = 0; j < posCount; ++j) {
						if (firstPos == -1) {
							firstPos = bufferReader.readLong();
						} else {
							bufferReader.skipObject();
						}
					}
				}
			} else if (cmp == 0) {
				for (int i = 0; i < count; ++i) {
					posArray.add(bufferReader.readLong());
					for (int j = 0; j < posCount; ++j) {
						long pos = bufferReader.readLong();
						if (firstPos == -1) {
							firstPos = pos;
						} else {
							pos = pos + firstPos;
						}
						posArray.add(pos);
					}
				}
				
				srcIndex++;
				if (srcIndex > srcLen) break;
				
				srcVal = mems.get(srcIndex);
				
				//????µ?Ҫ???ҵ?ֵ???ڱ??????ֵ????????
				if (Variant.compare(blockMaxVals[block], srcVal, true) < 0) {
					while (true) {
						block++;
						if (block >= blockCount) break Next;
						
						if (Variant.compare(blockMaxVals[block], srcVal, true) >= 0) {
							bufferReader = new BufferReader(null, blockBuffers[block]);
							firstPos = -1;
							break;
						}
					}
				}
			} else {
				while (true) {
					srcIndex++;
					if (srcIndex > srcLen) break Next;
					
					srcVal = mems.get(srcIndex);
					cmp = Variant.compare(cur, srcVal, true);
					if (cmp < 0) {
						for (int i = 0; i < count; ++i) {
							bufferReader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								if (firstPos == -1) {
									firstPos = bufferReader.readLong();
								} else {
									bufferReader.skipObject();
								}
							}
						}
						
						continue Next;
					} else if (cmp == 0) {
						for (int i = 0; i < count; ++i) {
							posArray.add(bufferReader.readLong());
							for (int j = 0; j < posCount; ++j) {
								//posArray.add(bufferReader.readLong());
								long pos = bufferReader.readLong();
								if (firstPos == -1) {
									firstPos = pos;
								} else {
									pos = pos + firstPos;
								}
								posArray.add(pos);
							}
						}
						
						srcIndex++;
						if (srcIndex > srcLen) break Next;
						
						srcVal = mems.get(srcIndex);
						continue Next;
					}
				}
			}
		}

		if (srcIndex > srcLen) {
			return -1;
		}
		return srcIndex;
	}

	private int readPos_m_cache(Sequence vals, int srcIndex, 
			Object [][]blockMaxVals, byte [][]blockBuffers, LongArray outPos) throws IOException {
		IArray mems = vals.getMems();
		Object srcVal = mems.get(srcIndex);
		boolean isSequence = false;
		int srcKeyCount = 1;
		Object []srcKeys;
		if (srcVal instanceof Sequence) {
			isSequence = true;
			srcKeys = ((Sequence)srcVal).toArray();
			srcKeyCount = srcKeys.length;
		} else {
			srcKeys = new Object[]{srcVal};
		}
		
		int block = binarySearchArray(blockMaxVals, srcKeys, true);
		if (block < 0) return srcIndex;
		
		int posCount = this.positionCount;
		int blockCount = blockBuffers.length;
		BufferReader bufferReader = new BufferReader(null, blockBuffers[block]);
		
		int icount = ifields.length;
		Object []keys = new Object[icount];
		int srcLen = mems.size();
		LongArray posArray = new LongArray(srcLen);
		long firstPos = -1;
		Next:
		while (true) {
			int count = bufferReader.readInt();
			if (count == BLOCK_START) {
				// ????ʱ?Ƚ?һ???Ƿ??????鶼?ȵ?ǰҪȡ??ֵС???????????????
				while (true) {
					block++;
					if (block >= blockCount) break Next;
					
					if (Variant.compareArrays(blockMaxVals[block], srcKeys, srcKeyCount) >= 0) {
						bufferReader = new BufferReader(null, blockBuffers[block]);
						firstPos = -1;
						break;
					}
				}
				
				count = bufferReader.readInt();
			} else if (count == BLOCK_END) {
				break;
			}
			
			for (int i = 0; i < icount; ++i) {
			keys[i] = bufferReader.readObject();
			}
			int cmp = Variant.compareArrays(keys, srcKeys, srcKeyCount);
			if (cmp < 0) {
				for (int i = 0; i < count; ++i) {
					bufferReader.skipObject();
					for (int j = 0; j < posCount; ++j) {
						if (firstPos == -1) {
							firstPos = bufferReader.readLong();
						} else {
							bufferReader.skipObject();
						}
					}
				}
			} else if (cmp == 0) {
				for (int i = 0; i < count; ++i) {
					posArray.add(bufferReader.readLong());
					for (int j = 0; j < posCount; ++j) {
						long pos = bufferReader.readLong();
						if (firstPos == -1) {
							firstPos = pos;
						} else {
							pos = pos + firstPos;
						}
						posArray.add(pos);
					}
				}
				
			} else {
				while (true) {
					srcIndex++;
					if (srcIndex > srcLen) break Next;
					
					srcVal = mems.get(srcIndex);
					if (isSequence) {
						((Sequence)srcVal).toArray(srcKeys);
					} else {
						srcKeys[0] = srcVal;
					}
					
					cmp = Variant.compareArrays(keys, srcKeys, srcKeyCount);
					if (cmp < 0) {
						for (int i = 0; i < count; ++i) {
							bufferReader.skipObject();
							for (int j = 0; j < posCount; ++j) {
								if (firstPos == -1) {
									firstPos = bufferReader.readLong();
								} else {
									bufferReader.skipObject();
								}
							}
						}
						
						continue Next;
					} else if (cmp == 0) {
						for (int i = 0; i < count; ++i) {
							posArray.add(bufferReader.readLong());
							for (int j = 0; j < posCount; ++j) {
								long pos = bufferReader.readLong();
								if (firstPos == -1) {
									firstPos = pos;
								} else {
									pos = pos + firstPos;
								}
								posArray.add(pos);
							}
						}

						continue Next;
					}
				}
			}
		}
		
		outPos = posArray;
		if (srcIndex > srcLen) {
			return -1;
		}
		return srcIndex;
	}
	
	/**
	 * װ???м??
	 * @param isSec ?Ƿ??ǵڶ?????
	 * @param i		װ?صڼ???
	 */
	private void readInternalBlockInfo(boolean isSec, int i, BlockInfo blockInfo) {
		if (!isSec) {
			blockInfo.internalBlockMaxVals = internalAllBlockMaxVals[i];
			blockInfo.internalBlockPos = internalAllBlockPos[i];
		} else {
			blockInfo.internalBlockMaxVals = internalAllBlockMaxVals2[i];
			blockInfo.internalBlockPos = internalAllBlockPos2[i];
		}
	}
	
	/**
	 * ??????key[0]??ͷ??
	 * @param key	key[0]??String
	 * @param exp	like????ʽ
	 * @param ctx
	 * @return	??ַ(α??)????
	 */
	public LongArray select(String []key, Expression exp, String opt, Context ctx) {
		int start[] = new int[2];
		long startPos[] = new long[2];
		LongArray srcPos = null;
		LongArray srcPos2 = null;
		
		startPos[0] = indexPos + 5;
		startPos[1] = indexPos2 + 5;
		start[0] = start[1] = 0;
		
		searchValue(key, 1, true, startPos, start);
		if (start[0] < 0 && start[1] < 0) return new LongArray();
		InputStream is = indexFile.getInputStream();
		ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);
		try {
			if (start[0] >= 0) {
				srcPos = readPos_s(reader, key[0], -1, LIKE, exp, ctx, startPos[0], -1);

			}
			if (rootItPos2 != 0) {
				if (start[1] >= 0) {
					srcPos2 = readPos_s(reader, key[0], -1, LIKE, exp, ctx, startPos[1], -1);

				}
			}
			if (srcPos == null) srcPos = new LongArray();
			concat(srcPos, srcPos2);
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		} finally {
			try {
				reader.close();
			} catch (IOException ie){};
		}
		return srcPos;
	}

	public int getMaxRecordLen() {
		return maxRecordLen;
	}
	
	public boolean hasSecIndex() {
		return (rootBlockPos2 != null);
	}
	
	public int getPositionCount() {
		return positionCount;
	}

	public void dup(PhyTable table) {
		String dir = table.getGroupTable().getFile().getAbsolutePath() + "_";
		FileObject indexFile = new FileObject(dir + table.getTableName() + "_" + name);
		RandomOutputStream os = indexFile.getRandomOutputStream(true);
		RandomObjectWriter writer = new RandomObjectWriter(os);
		try {
			writeHeader(writer);
			writer.close();
		} catch (IOException e) {
			throw new RQException(e);
		}
	}
	
	public void setName(String name) {
		this.name = name;
	}

	public Object getIndexStruct() {
		InputStream is = indexFile.getInputStream();
		ObjectReader reader = new ObjectReader(is, BUFFER_SIZE);
		try {
			readHeader(reader);
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		} finally {
			try {
				reader.close();
			} catch (IOException ie){};
		}
		
		Record rec = new Record(new DataStruct(INDEX_FIELD_NAMES));
		rec.setNormalFieldValue(0, name);
		rec.setNormalFieldValue(1, 0);
		rec.setNormalFieldValue(2, new Sequence(ifields));
		rec.setNormalFieldValue(3, null);
		rec.setNormalFieldValue(4, filter == null ? null : filter.toString());
		return rec;
	}
	
	/**
	 * ?ж??ֶ??Ƿ???????????
	 * @param fieldNames ?ֶ???????
	 * @param ifields ?????ֶ?
	 * @return
	 */
	public static boolean isCompatible(String []fieldNames, String[] ifields) {
		if (fieldNames == null || ifields == null)
			return false;
		ArrayList list = new ArrayList();
		for (String str : ifields) {
			list.add(str);
		}
		for (String str : fieldNames) {
			if (!list.contains(str)) {
				return false;
			}
		}
		return true;
	}
	
	public static String[][] readIndexFields(FileObject indexFile) {
		String[][] names = new String[2][];
		ObjectReader reader = null;
		try {
			InputStream is = indexFile.getInputStream();
			reader = new ObjectReader(is, BUFFER_SIZE);
			if (reader.read() != 'r' || reader.read() != 'q' || 
					reader.read() != 'd' || reader.read() != 'w' ||
					reader.read() != 'i' || reader.read() != 'd' ) {
				MessageManager mm = EngineMessage.get();
				throw new RQException(mm.getMessage("license.fileFormatError"));
			}
			
			int flag = reader.read();
			reader.readFully(new byte[32]);
			reader.readLong64();
			reader.readLong64();
			reader.readLong64();
			if (flag != 'h') {
				reader.readLong64();
				reader.readLong64();
				reader.readLong64();
				reader.readLong64();
			}
			names[0] = reader.readStrings();//ifields
			if (flag == 'v') 
				names[1] = reader.readStrings();//
		} catch (IOException e) {
			throw new RQException(e);
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
				}
			}
		}
		return names;
	}
	
	public static Object getIndexStruct(FileObject indexFile) {
		String[] ifields = null;
		String[] vfields = null;
		String filter = null;
		int flag;
		
		Record rec = new Record(new DataStruct(INDEX_FIELD_NAMES2));
		ObjectReader reader = null;
		try {
			InputStream is = indexFile.getInputStream();
			reader = new ObjectReader(is, BUFFER_SIZE);
			if (reader.read() != 'r' || reader.read() != 'q' || 
					reader.read() != 'd' || reader.read() != 'w' ||
					reader.read() != 'i' || reader.read() != 'd' ) {
				MessageManager mm = EngineMessage.get();
				throw new RQException(mm.getMessage("license.fileFormatError"));
			}
			
			flag = reader.read();
			reader.readFully(new byte[32]);
			reader.readLong64();
			reader.readLong64();
			reader.readLong64();
			if (flag != 'h') {
				reader.readLong64();
				reader.readLong64();
				reader.readLong64();
				reader.readLong64();
			}

			ifields = reader.readStrings();
			
			if (flag == 'x')
				rec.setNormalFieldValue(0, 0);//????
			else if (flag == 'v') {
				rec.setNormalFieldValue(0, 0);
				vfields = reader.readStrings();//key-v
			} else if (flag == 'w')
				rec.setNormalFieldValue(0, null);//ȫ??
			else if (flag == 'h') {
				int h  = reader.readInt32();
				reader.readInt32();
				reader.readInt32();
				rec.setNormalFieldValue(0, h);//hash
			} else {
				MessageManager mm = EngineMessage.get();
				throw new RQException(mm.getMessage("license.fileFormatError"));
			}
				
			if (reader.read() != 0) {
				filter = reader.readUTF();
			}
			
		} catch (IOException e) {
			throw new RQException(e);
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
				}
			}
		}

		rec.setNormalFieldValue(1, new Sequence(ifields));
		rec.setNormalFieldValue(2, new Sequence(vfields));
		rec.setNormalFieldValue(3, filter);
		return rec;
	}
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy