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

com.scudata.dw.pseudo.PseudoTable Maven / Gradle / Ivy

Go to download

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

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

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

import com.scudata.common.RQException;
import com.scudata.common.Types;
import com.scudata.dm.BaseRecord;
import com.scudata.dm.Context;
import com.scudata.dm.DataStruct;
import com.scudata.dm.Sequence;
import com.scudata.dm.cursor.ConjxCursor;
import com.scudata.dm.cursor.ICursor;
import com.scudata.dm.cursor.MemoryCursor;
import com.scudata.dm.cursor.MergeCursor;
import com.scudata.dm.cursor.MultipathCursors;
import com.scudata.dm.op.Conj;
import com.scudata.dm.op.Group;
import com.scudata.dm.op.Join;
import com.scudata.dm.op.New;
import com.scudata.dm.op.Operable;
import com.scudata.dm.op.Operation;
import com.scudata.dm.op.Select;
import com.scudata.dm.op.Switch;
import com.scudata.dw.ColPhyTable;
import com.scudata.dw.Cursor;
import com.scudata.dw.IFilter;
import com.scudata.dw.IPhyTable;
import com.scudata.dw.RowCursor;
import com.scudata.dw.RowPhyTable;
import com.scudata.dw.PhyTable;
import com.scudata.expression.Constant;
import com.scudata.expression.Expression;
import com.scudata.expression.IParam;
import com.scudata.expression.Node;
import com.scudata.expression.ParamParser;
import com.scudata.expression.UnknownSymbol;
import com.scudata.expression.VarParam;
import com.scudata.expression.mfn.sequence.Contain;
import com.scudata.expression.operator.And;
import com.scudata.expression.operator.DotOperator;
import com.scudata.expression.operator.Equals;
import com.scudata.expression.operator.NotEquals;
import com.scudata.expression.operator.Or;

public class PseudoTable extends Pseudo {
	//?????α???Ҫ?IJ???
	protected String []fkNames;
	protected Sequence []codes;
	protected int pathCount;
	
	protected ArrayList extraOpList = new ArrayList();//??????????????ӳټ??㣨????????????select???ӣ?
	protected ArrayList joinColumnList = new ArrayList();//?????????
	protected PseudoTable mcsTable;
	
	protected boolean hasPseudoColumns = false;//?Ƿ???Ҫ????α?ֶ?ת????ö?١???ֵ??????ʽ
	
	public PseudoTable() {
	}
	
	/**
	 * ???????????
	 * @param rec ?????¼
	 * @param hs ?ֻ?????
	 * @param n ??????
	 * @param ctx
	 */
	public PseudoTable(BaseRecord rec, int n, Context ctx) {
		pd = new PseudoDefination(rec, ctx);
		pathCount = n;
		this.ctx = ctx;
		extraNameList = new ArrayList();
		init();
	}

	public PseudoTable(PseudoDefination pd, int n, Context ctx) {
		this.pd = pd;
		pathCount = n;
		this.ctx = ctx;
		extraNameList = new ArrayList();
		init();
	}
	
	public PseudoTable(BaseRecord rec, PseudoTable mcs, Context ctx) {
		this(rec, 0, ctx);
		mcsTable = mcs;
	}
	
	public static PseudoTable create(BaseRecord rec, int n, Context ctx) {
		PseudoDefination pd = new PseudoDefination(rec, ctx);
		if (pd.isBFile()) {
			return new PseudoBFile(pd, n, ctx);
		} else {
			return new PseudoTable(pd, n, ctx);
		}
	}
	
	protected void init() {
		if (getPd() != null) {
			allNameList = new ArrayList();
			String []names = getPd().getAllColNames();
			for (String name : names) {
				allNameList.add(name);
			}
			
			if (getPd().getColumns() != null) {
				List columns = getPd().getColumns();
				for (PseudoColumn column : columns) {
					//???????ö??α?ֶκͶ?ֵα?ֶΣ?Ҫ??¼???????ڽ??????Ĵ????л??õ?
					if (column.getPseudo() != null) {
						hasPseudoColumns = true;
					}
					if (column.getBits() != null) {
						hasPseudoColumns = true;
					}
					
					if (column.getDim() != null) {
						if (column.getFkey() == null) {
							addColName(column.getName());
						} else {
							for (String key : column.getFkey()) {
								addColName(key);
							}
						}
						
						Sequence dim = (Sequence) column.getDim();
						if (column.getTkey() != null && dim.dataStruct().getTimeKeyCount() > 0) {
							addColName(column.getTkey());
						}
					}
				}
			}
		}
	}

	public void addPKeyNames() {
		addColNames(getPd().getAllSortedColNames());
	}
	
	public void addColNames(String []nameArray) {
		for (String name : nameArray) {
			addColName(name);
		}
	}
	
	public void addColName(String name) {
		if (name == null) return; 
		if (allNameList.contains(name) && !extraNameList.contains(name)) {
			extraNameList.add(name);
		}
	}
	
	/**
	 * ????ȡ???ֶ?
	 * @param exps ȡ??????ʽ
	 * @param fields ȡ??????
	 */
	protected void setFetchInfo(Expression []exps, String []fields) {
		this.exps = null;
		this.names = null;
		boolean needNew = extraNameList.size() > 0;
		Expression newExps[] = null;
		
		extraOpList.clear();
		joinColumnList.clear();
		
		//set FK codes info
		if (fkNameList != null) {
			int size = fkNameList.size();
			fkNames = new String[size];
			fkNameList.toArray(fkNames);
			
			codes = new Sequence[size];
			codeList.toArray(codes);
		}
		
		if (exps == null) {
			if (fields == null) {
				return;
			} else {
				int len = fields.length;
				exps = new Expression[len];
				for (int i = 0; i < len; i++) {
					exps[i] = new Expression(fields[i]);
				}
			}
		}
		
		newExps = exps.clone();//????һ??
		
		/**
		 * ??ȡ??????ʽҲ??ȡ???ֶ?,????extraNameList???Ƿ????exps????ֶ?
		 * ?????????ȥ??
		 */
		ArrayList tempList = new ArrayList();
		for (String name : extraNameList) {
			if (!tempList.contains(name)) {
				tempList.add(name);
			}
		}
		for (Expression exp : exps) {
			String expName = exp.getIdentifierName();
			if (tempList.contains(expName)) {
				tempList.remove(expName);
			}
		}
		
		ArrayList tempNameList = new ArrayList();
		ArrayList tempExpList = new ArrayList();
		int size = exps.length;
		for (int i = 0; i < size; i++) {
			Expression exp = exps[i];
			String name = fields[i];
			Node node = exp.getHome();
			
			if (node instanceof UnknownSymbol || node instanceof VarParam) {
				String expName = exp.getIdentifierName();
				if (!allNameList.contains(expName)) {
					/**
					 * ?????α?ֶ?????ת??
					 */
					PseudoColumn col = pd.findColumnByPseudoName(expName);
					if (col != null) {
						if (col.getDim() != null) {
							if (col.getFkey() == null) {
								String colName = col.getName();
								if (!tempNameList.contains(colName)) {
									tempExpList.add(new Expression(colName));
									tempNameList.add(colName);
								}
							} else {
								for (String colName : col.getFkey()) {
									if (!tempNameList.contains(colName)) {
										tempExpList.add(new Expression(colName));
										tempNameList.add(colName);
									}
								}
							}
							joinColumnList.add(col);
						} else if (col.getExp() != null) {
							//?б???ʽ??α??
							newExps[i] = new Expression(col.getExp());
							needNew = true;
							
							ArrayList list = new ArrayList();
							newExps[i].getUsedFields(ctx, list);
							for(String field : list) {
								if (!tempNameList.contains(field)) {
									tempExpList.add(new Expression(field));
									tempNameList.add(field);
								}
							}
							
						} else if (col.get_enum() != null) {
							/**
							 * ö???ֶ???ת??
							 */
							String var = "pseudo_enum_value_" + i;
							ctx.setParamValue(var, col.get_enum());
							name = col.getName();
							newExps[i] = new Expression(var + "(" + name + ")");
							exp = new Expression(name);
							needNew = true;
							if (!tempNameList.contains(name)) {
								tempExpList.add(exp);
								tempNameList.add(name);
							}
						} else if (col.getBits() != null) {
							/**
							 * ??ֵ?ֶ???ת??
							 */
							name = col.getName();
							String pname = ((UnknownSymbol) node).getName();
							Sequence seq;
							seq = col.getBits();
							int idx = seq.firstIndexOf(pname) - 1;
							int bit = 1 << idx;
							String str = "and(" + col.getName() + "," + bit + ")!=0";//??Ϊ???ֶε?λ????
							newExps[i] = new Expression(str);
							exp = new Expression(name);
							needNew = true;
							tempExpList.add(exp);
							tempNameList.add(name);
						}
					}
				} else {
					if (!tempNameList.contains(name)) {
						tempExpList.add(exp);
						tempNameList.add(name);
					}
				}
				
//			} else if (node instanceof DotOperator) {
//				Node left = node.getLeft();
//				if (left != null && left instanceof UnknownSymbol) {
//					PseudoColumn col = getPd().findColumnByName( ((UnknownSymbol)left).getName());
//					if (col != null) {
//						Derive derive = new Derive(new Expression[] {exp}, new String[] {name}, null);
//						extraOpList.add(derive);
//					}
//				}
			}
		}

		//???????date?????ȡ?????ֶ?ugrp
		String date = pd.getDate();
		String ugrp = pd.getUgrp();
		if (date != null && !tempNameList.contains(ugrp)) {
			needNew = true;
			tempList.add(ugrp);
		}
		
		for (String name : tempList) {
			tempExpList.add(new Expression(name));
			tempNameList.add(name);
		}
		
		size = tempExpList.size();
		this.exps = new Expression[size];
		tempExpList.toArray(this.exps);
		
		this.names = new String[size];
		tempNameList.toArray(this.names);
	
		if (needNew) {
			New _new = new New(newExps, fields, null);
			extraOpList.add(_new);
		}
		return;
	}
	
	public String[] getFetchColNames(String []fields) {
		ArrayList tempList = new ArrayList();
		if (fields != null) {
			for (String name : fields) {
				tempList.add(name);
			}
		}
		for (String name : extraNameList) {
			if (!tempList.contains(name)) {
				tempList.add(name);
			}
		}
		
		int size = tempList.size();
		if (size == 0) {
			return null;
		}
		String []newFields = new String[size];
		tempList.toArray(newFields);
		return newFields;
	}
	
	/**
	 * ?õ??????ÿ??ʵ??????α깹?ɵ?????
	 * @return
	 */
	public ICursor[] getCursors(boolean isColumn) {
		List tables = getPd().getTables();
		int size = tables.size();
		ICursor cursors[] = new ICursor[size];
		
		for (int i = 0; i < size; i++) {
			cursors[i] = getCursor(tables.get(i), null, true, isColumn);
		}
		return cursors;
	}
	
	/**
	 * ???ӿ????õ??????????
	 */
	protected void addJoin(ICursor cursor) {
		List list = getFieldSwitchColumns(this.names);
		if (list != null) {
			for (PseudoColumn col : joinColumnList) {
				list.add(col);
			}
		} else {
			list = joinColumnList;
		}
		if (getPd() != null && list != null) {
			for (PseudoColumn column : list) {
				if (column.getDim() != null) {//??????????????????һ??switch???ӳټ???
					Sequence dim;
					if (column.getDim() instanceof Sequence) {
						dim = (Sequence) column.getDim();
					} else {
						dim = ((IPseudo) column.getDim()).cursor(null, null, false).fetch();
					}
					boolean hasTimeKey = column.getTkey() != null && dim.dataStruct().getTimeKeyCount() == 1;
					
					String fkey[] = column.getFkey();
					if (fkey == null) {
						/**
						 * ??ʱname????????ֶ?
						 */
						String[] fkNames = new String[] {column.getName()};
						String[] timeFkNames =hasTimeKey ? new String[] {column.getTkey()} : null;
						Sequence[] codes = new Sequence[] {dim};
						Switch s = new Switch(
								null,
								fkNames, 
								timeFkNames,
								codes,
								null,
								null,
								null);
						cursor.addOperation(s, ctx);
					} else {
						int size = fkey.length;
						
						/**
						 * ?????????ʱ???ֶ?,?Ͱ?ʱ???ֶ?ƴ?ӵ?fkeyĩβ
						 */
						if (hasTimeKey) {
							size++;
							fkey = new String[size];
							System.arraycopy(column.getFkey(), 0, fkey, 0, size - 1);
							fkey[size - 1] = column.getTkey();
						}
						
						Expression[][] exps = new Expression[1][];
						exps[0] = new Expression[size];
						for (int i = 0; i < size; i++) {
							exps[0][i] = new Expression(fkey[i]);
						}
						Expression[][] newExps = new Expression[1][];
						newExps[0] = new Expression[] {new Expression("~")};
						
						String newName = column.getName();
						if (newName == null && column.getFkey() != null) {
							newName = column.getFkey()[0];
						}
						String[][] newNames = new String[1][];
						newNames[0] = new String[] {newName};
						
						Expression[][] dimKeyExps = new Expression[1][];
						String[] dimKey = column.getDimKey();
						if (dimKey == null) {
							dimKeyExps[0] = null;
						} else {
							Expression[] dimKeyExp = new Expression[size];
							for (int i = 0; i < size; i++) {
								dimKeyExp[i] = new Expression(dimKey[i]);
							}
							dimKeyExps[0] = dimKeyExp;
						}
						
						Join join = new Join(null, null, exps, new Sequence[] {dim}, dimKeyExps, newExps, newNames, null);
						cursor.addOperation(join, ctx);
					}
				}
			}
		}
	}
	
	/**
	 * ?õ?table???α?
	 * @param table
	 * @param mcs
	 * @param addOpt ?Ƿ?Ѹ??Ӽ???????
	 * @param isColumn ?Ƿ񷵻???ʽ?α?
	 * @return
	 */
	private ICursor getCursor(IPhyTable table, ICursor mcs, boolean addOpt, boolean isColumn) {
		ICursor cursor = null;

		if (fkNames != null) {
			if (mcs != null ) {
				if (mcs instanceof MultipathCursors) {
					cursor = table.cursor(null, this.names, filter, fkNames, codes, null, (MultipathCursors)mcs, null, ctx);
				} else {
					if (exps == null) {
						cursor = table.cursor(null, this.names, filter, fkNames, codes, null, null, ctx);
					} else {
						cursor = table.cursor(this.exps, this.names, filter, fkNames, codes, null, null, ctx);
					}
				}
			} else if (pathCount > 1) {
				if (exps == null) {
					cursor = table.cursor(null, this.names, filter, fkNames, codes, null, pathCount, null, ctx);
				} else {
					cursor = table.cursor(this.exps, this.names, filter, fkNames, codes, null, pathCount, null, ctx);
				}
			} else {
				if (exps == null) {
					cursor = table.cursor(null, this.names, filter, fkNames, codes, null, null, ctx);
				} else {
					cursor = table.cursor(this.exps, this.names, filter, fkNames, codes, null, null, ctx);
				}
			}
		} else {
			if (mcs != null ) {
				if (mcs instanceof MultipathCursors) {
					cursor = table.cursor(null, this.names, filter, null, null, null, (MultipathCursors)mcs, null, ctx);
				} else {
					if (exps == null) {
						cursor = table.cursor(this.names, filter, ctx);
					} else {
						cursor = table.cursor(this.exps, this.names, filter, null, null, null, null, ctx);
					}
				}
			} else if (pathCount > 1) {
				if (exps == null) {
					cursor = table.cursor(null, this.names, filter, null, null, null, pathCount, null, ctx);
				} else {
					cursor = table.cursor(this.exps, this.names, filter, null, null, null, pathCount, null, ctx);
				}
			} else {
				if (exps == null) {
					cursor = table.cursor(this.names, filter, ctx);
				} else {
					cursor = table.cursor(this.exps, this.names, filter, null, null, null, null, ctx);
				}
			}
		}
	
		
		addJoin(cursor);
	
		if (addOpt) {
			if (opList != null) {
				for (Operation op : opList) {
					cursor.addOperation(op, ctx);
				}
			}
			if (extraOpList != null) {
				for (Operation op : extraOpList) {
					cursor.addOperation(op, ctx);
				}
			}
		}

		return cursor;
	
	}
	
	/**
	 * ??user???? ?????ص????α?ʱʹ?ã?
	 * @param cursors
	 * @param pd
	 * @param ctx
	 * @return
	 */
	static ICursor sortCursor(ICursor cursor, PseudoDefination pd, Context ctx) {
//		if (pd.getDate() == null) {
//			return cursor;
//		}
		
		String ugrp = pd.getUgrp();
		String user = pd.getUser();
		DataStruct ds = cursor.getDataStruct();
		if (user == null || user.equals(ugrp) || ds.getFieldIndex(user) == -1) {
			return cursor;
		}
		
		return new GroupSortCursor(cursor, ugrp, user, ctx);
	}
	
	/**
	 * ?鲢?????????α?
	 * @param cursors
	 * @return
	 */
	static ICursor mergeCursor(ICursor cursors[], PseudoDefination pd, Context ctx) {
		if (pd.getDate() == null) {
			return new ConjxCursor(cursors);
		}
		
		String ugrp = pd.getUgrp();
		DataStruct ds = cursors[0].getDataStruct();
		int index = ds.getFieldIndex(ugrp); 
		if (index == -1) {
			return new ConjxCursor(cursors);
		}
		
		ICursor cs = new MergeCursor(cursors, new int[] {index}, null, ctx);
		
		//???user?????ڻ????ugrp
		String user = pd.getUser();
		if (user == null || user.equals(ugrp) || ds.getFieldIndex(user) == -1) {
			return cs;
		}
		
		//user???????ֶΣ??ڹ鲢??ֵͬ???ֶ??ڵ????ݰ?user????
		return new GroupSortCursor(cs, ugrp, user, ctx);
	}
	
	static ICursor mergeCursor(ICursor cursors[], Context ctx) {
		return new ConjxCursor(cursors);
	}
	
	/**
	 * ???????user???˻????ԣ???group(???ֶ?).conj(~.group(user)),
	 * ?????????user????ʹ?????ֶι鲢??
	 */
	static void groupByUser(ICursor cursor, String user, String ugrp, Context ctx) {
		if (user != null && ugrp != null && user.equals(ugrp)) {
			Expression[] exps = new Expression[1];
			exps[0] = new Expression(ugrp);
			cursor.addOperation(new Group(exps, null), ctx);
			cursor.addOperation(new Conj(new Expression("~.group("+user+")")), ctx);
		}
	}
	
	private ICursor addOptionToCursor(ICursor cursor) {
		if (opList != null) {
			for (Operation op : opList) {
				cursor.addOperation(op, ctx);
			}
		}
		if (extraOpList != null) {
			for (Operation op : extraOpList) {
				cursor.addOperation(op, ctx);
			}
		}
		return cursor;
	}
	
	private List filterTables(List tables) {
		if (filter != null && pd.getDate() != null) {
			String dateName = pd.getDate();
			PseudoColumn dateCol = pd.findColumnByPseudoName(dateName);
			if (dateCol != null && dateCol.getExp() != null) {
				dateName = dateCol.getName();
			}
			IPhyTable table = tables.get(0);
			
			//?ж??Ƿ??й???date?Ĺ???
			Object obj;
			if (table instanceof ColPhyTable)
				obj = Cursor.parseFilter((ColPhyTable) table, filter, ctx);
			else 
				obj = RowCursor.parseFilter((RowPhyTable) table, filter.getHome(), ctx);
			
			IFilter dateFilter = null;
			if (obj instanceof IFilter) {
				if (((IFilter)obj).getColumnName().equals(dateName)) {
					dateFilter = (IFilter)obj;
				}
			} else if (obj instanceof ArrayList) {
				@SuppressWarnings("unchecked")
				ArrayList list = (ArrayList)obj;
				for (Object f : list) {
					if (f instanceof IFilter) {
						if (((IFilter)f).getColumnName().equals(dateName)) {
							dateFilter = (IFilter)f;
							break;
						}
					}
				}
			}
			
			if (dateFilter != null) {
				int count = tables.size();
				List list = new ArrayList(count);
				List max = pd.getMaxValues();
				List min = pd.getMinValues();			
				for (int i = 0; i < count; i++) {
					PhyTable t = (PhyTable) tables.get(i);
					if (t.getTotalRecordCount() == 0) {
						continue;
					}
					if (dateFilter.match(min.get(i), max.get(i))) {
						list.add(t);
					}
				}
				return list;
			}
		}

		int count = tables.size();
		List list = new ArrayList(count);
		for (int i = 0; i < count; i++) {
			PhyTable t = (PhyTable) tables.get(i);
			if (t.getTotalRecordCount() == 0) {
				continue;
			}
			list.add(t);
		}
		return list;
	}
	
	public ICursor cursor(Expression []exps, String []names) {
		return cursor(exps, names, false);
	}
	
	//??????????α?
	public ICursor cursor(Expression []exps, String []names, boolean isColumn) {
		setFetchInfo(exps, names);//??ȡ???ֶ????ӽ?ȥ????????ܻ??extraOpList??ֵ
		
		//ÿ??ʵ???ļ?????һ???α?
		List tables = getPd().getTables();
		int size = tables.size();
		ICursor cursors[] = new ICursor[size];
		
		/**
		 * ?Եõ??α???й鲢????Ϊ???
		 * 1 ֻ??һ???α??򷵻أ?
		 * 2 ?ж???α??Ҳ?????ʱ?????й鲢
		 * 3 ?ж???α??Ҳ???ʱ???ȶԵ?һ???α?ֶΣ?Ȼ???????α갴??һ??ͬ???ֶΣ?????ÿ???α??ÿ???ν??й鲢
		 */
		if (pathCount == 1 && size == 1) {//ֻ??һ???α?ֱ?ӷ???
			ICursor cs = getCursor(tables.get(0), null, false, isColumn);
			cs = sortCursor(cs, pd, ctx);
			return addOptionToCursor(cs);
		} else {
			tables = filterTables(tables);
			size = tables.size();
			if (size == 0) {
				return new MemoryCursor(null);
			}
			
			if (pathCount > 1) {//ָ???˲?????????ʱ????mcsTable
				cursors[0] = getCursor(tables.get(0), null, false, isColumn);
				for (int i = 1; i < size; i++) {
					cursors[i] = getCursor(tables.get(i), cursors[0], false, isColumn);
				}
			} else {//û??ָ????????
				if (mcsTable == null) {//û??ָ???ֶβο????mcsTable
					for (int i = 0; i < size; i++) {
						cursors[i] = getCursor(tables.get(i), null, false, isColumn);
					}
					return addOptionToCursor(mergeCursor(cursors, pd, ctx));
				} else {//ָ???˷ֶβο????mcsTable
					ICursor mcs = mcsTable.cursor();
					for (int i = 0; i < size; i++) {
						cursors[i] = getCursor(tables.get(i), mcs, false, isColumn);
					}
					mcs.close();
				}
			}
			
			//??cursors???ι鲢??????:???????α?ĵ?N·?鲢,?õ?N???α?,?ٰ???N???α????ɶ?·?α귵??
			int mcount = ((MultipathCursors)cursors[0]).getPathCount();//?ֶ???
			ICursor mcursors[] = new ICursor[mcount];//????α?
			for (int m = 0; m < mcount; m++) {
				if (size == 1) {
					mcursors[m] = sortCursor(((MultipathCursors)cursors[0]).getCursors()[m], pd, ctx);
				} else {
					ICursor cursorArray[] = new ICursor[size];
					for (int i = 0; i < size; i++) {
						cursorArray[i] = ((MultipathCursors)cursors[i]).getCursors()[m];
					}
					mcursors[m] = mergeCursor(cursorArray, pd, ctx);
				}
			}
			return addOptionToCursor(new MultipathCursors(mcursors, ctx));
		}
	}
	
	//???ڻ?ȡ??·?α?
	private ICursor cursor() {
		List tables = getPd().getTables();
		return tables.get(0).cursor(null, null, null, null, null, null, pathCount, null, ctx);
	}

	public Object clone(Context ctx) throws CloneNotSupportedException {
		PseudoTable obj = new PseudoTable();
		obj.hasPseudoColumns = hasPseudoColumns;
		obj.pathCount = pathCount;
		obj.mcsTable = mcsTable;
		obj.fkNames = fkNames == null ? null : fkNames.clone();
		obj.codes = codes == null ? null : codes.clone();
		cloneField(obj);
		obj.ctx = ctx;
		return obj;
	}

	public Pseudo setPathCount(int pathCount) {
		PseudoTable table = null;
		try {
			table = (PseudoTable) clone(ctx);
			table.pathCount = pathCount;
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return table;
	}

	public Pseudo setMcsTable(Pseudo mcsTable) {
		PseudoTable table = null;
		try {
			table = (PseudoTable) clone(ctx);
			table.mcsTable = (PseudoTable) mcsTable;
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return table;
	}
	
	/**
	 * ת????ֵα?ֶνڵ?Ϊ???ֶ?
	 * ת????ͨα?ֶνڵ?Ϊ???ֶ?
	 * @param node
	 * @return
	 */
	private Node bitsToBoolean(Node node) {
		String pname = ((UnknownSymbol) node).getName();
		PseudoColumn col = getPd().findColumnByPseudoName(pname);
		
		if (col == null) {
			return null;
		}
		
		if (col.getBits() != null) {
			/**
			 * ??һ??UnknownSymbol?Ķ?ֵ?ڵ?ת??Ϊһ??Boolean?ڵ?
			 */
			Sequence seq;
			seq = col.getBits();
			int idx = seq.firstIndexOf(pname) - 1;
			int bit = 1 << idx;
			String str = "and(" + col.getName() + "," + bit + ")!=0";//??Ϊ???ֶε?λ????
			return new Expression(str).getHome();
		} else if (col.get_enum() != null) {
			return null;//ö?ٵIJ??????ﴦ??
		} else if (col.getExp() != null) {
			return new Expression(col.getExp()).getHome();
		} else if (col.getFkey() != null) {
			return null;//new UnknownSymbol(col.getFkey()[0]);//??Fkeyʱ Fkey[0]?????ֶ?
		} else {
			return new UnknownSymbol(col.getName());//??????ͨα?ֶ?
		}
	}
	
	/**
	 * ??????ֵα?ֶ?
	 */
	private void replaceFilter(Node node) {
		if (node == null) {
			return;
		}
		
		if (node.getLeft() instanceof UnknownSymbol) {
			Node left = bitsToBoolean(node.getLeft());
			if (left != null) {
				node.setLeft(left);
			}
		} else {
			replaceFilter(node.getLeft());
		}
		
		if (node.getRight() instanceof UnknownSymbol) {
			Node right = bitsToBoolean(node.getRight());
			if (right != null) {
				node.setRight(right);
			}
		} else {
			replaceFilter(node.getRight());
		}
	}
	
	/**
	 * ?ѱ???ʽ???漰α?ֶε?ö?????????ת??
	 * @param node
	 */
	private void parseFilter(Node node) {
		if (node instanceof And || node instanceof Or) {
			/**
			 * ?߼??롢??ʱ???ݹ鴦??
			 */
			parseFilter(node.getLeft());
			parseFilter(node.getRight());
		} else if (node instanceof Equals || node instanceof NotEquals) {
			/**
			 * ??α?ֶε?==??!=???д???
			 */
			if (node.getLeft() instanceof UnknownSymbol) {
				//?ж??Ƿ???α?ֶ?
				String pname = ((UnknownSymbol) node.getLeft()).getName();
				PseudoColumn col = getPd().findColumnByPseudoName(pname);
				if (col != null) {
					Sequence seq;
					//?ж??Ƿ??Ƕ?ö??α?ֶν???????
					if (col.get_enum() != null) {
						seq = col.get_enum();
						node.setLeft(new UnknownSymbol(col.getName()));//??Ϊ???ֶ?
						Integer obj = seq.firstIndexOf(node.getRight().calculate(ctx));
						node.setRight(new Constant(obj));//??ö??ֵ??Ϊ??Ӧ?????ֵ
					}
				}
			} else if (node.getRight() instanceof UnknownSymbol) {
				//?????ֶ??????ұߵ?????????ҽ???һ???ٴ??????߼???????һ??
				Node right = node.getRight();
				node.setRight(node.getLeft());
				node.setLeft(right);
				parseFilter(node);
			}
		} else if (node instanceof DotOperator) {
			//????ö???б???α?ֶε?contain???д???
			if (node.getRight() instanceof Contain) {
				Contain contain = (Contain)node.getRight();
				IParam param = contain.getParam();
				if (param == null || !param.isLeaf()) {
					return;
				}
				
				//?ж??Ƿ??Ƕ?α?ֶν???contain????
				PseudoColumn col = null;
				Node containNode = param.getLeafExpression().getHome();
				if (containNode instanceof UnknownSymbol) {
					UnknownSymbol un = (UnknownSymbol) param.getLeafExpression().getHome();
					col = getPd().findColumnByPseudoName(un.getName());
				}
				if (col != null && col.get_enum() != null) {
					Object val = node.getLeft().calculate(ctx);
					if (val instanceof Sequence) {
						//??contain?ұߵ??ֶ?????Ϊ???ֶ?
						IParam newParam = ParamParser.parse(col.getName(), null, ctx);
						contain.setParam(newParam);
						
						//??contain??ߵ?ö??ֵ???и?Ϊ??Ӧ?????ֵ??????
						Sequence value = (Sequence) val;
						Sequence newValue = new Sequence();
						int size = value.length();
						for (int i = 1; i <= size; i++) {
							Integer obj = col.get_enum().firstIndexOf(value.get(i));
							newValue.add(obj);
						}
						node.setLeft(new Constant(newValue));
					}
				}
			}
		}
	}
	
	public Operable addOperation(Operation op, Context ctx) {
		if (op == null) {
			return this;
		}
		
		if (hasPseudoColumns) {
			/**
			 * ????α?ֶΣ???ֵ?ֶΣ?ö???ֶ?
			 */
			Expression exp;
			if (op instanceof Select) {
				exp = ((Select) op).getFilterExpression();
			} else if (op instanceof New) {
				return super.addOperation(op, ctx);
			} else {
				exp = op.getFunction().getParam().getLeafExpression();
			}
			Node node = exp.getHome();
			if (node instanceof UnknownSymbol) {
				/**
				 * node??α?ֶ?
				 */
				Node n = bitsToBoolean(node);
				if (n != null) {
					op = new Select(new Expression(n), null);
					
					ArrayList tempList = new ArrayList();
					n.getUsedFields(ctx, tempList);
					for (String name : tempList) {
						addColName(name);
					}
				}
			} else {
				/**
				 * node????ͨ?ֶ?
				 */
				replaceFilter(node);
				parseFilter(node);
			}
		}
		
		return super.addOperation(op, ctx);
	}
	
	/**
	 * ???α??α??ת??Ϊ???ֶΣ?????update??append
	 * @param cursor
	 * @param columns
	 * @param fields
	 */
	private void convertPseudoColumn(ICursor cursor, List columns, String fields[]) {
		//?ȰѲ???α?ֶεĸ?ֵ????
		DataStruct ds = new DataStruct(fields);
		int size = ds.getFieldCount();
		Expression []exps = new Expression[size];
		String []names = new String[size];
		for (int c = 0; c < size; c++) {
			exps[c] = new Expression(fields[c]);
			names[c] = fields[c];
		}
		
		//ת???α????α?ֶ?
		size = columns.size();
		for (int c = 0; c < size; c++) {
			PseudoColumn column = columns.get(c);
			String pseudoName = column.getPseudo();
			Sequence bitNames = column.getBits();
			int idx = ds.getFieldIndex(column.getName());
			
			if (column.getExp() != null) {
				//?б???ʽ??α??
				exps[idx] = new Expression(column.getExp());
				names[idx] = column.getName();
			} else if (pseudoName != null && column.get_enum() != null) {
				//ö??α??
				String var = "pseudo_enum_value_" + c;
				Context context = cursor.getContext();
				if (context == null) {
					context = new Context();
					cursor.setContext(context);
					context.setParamValue(var, column.get_enum());
				} else {
					context.setParamValue(var, column.get_enum());
				}
				exps[idx] = new Expression(var + ".pos(" + pseudoName + ")");
				names[idx] = column.getName();
			} else if (bitNames != null) {
				//??????ֵα?ֶ?(???α?ֶΰ?λת??Ϊһ?????ֶ?)
				String exp = "0";
				int len = bitNames.length();
				for (int i = 1; i <= len; i++) {
					String field = (String) bitNames.get(i);
					//ת??Ϊbitֵ,???ۼ?
					int bit = 1 << (i - 1);
					exp += "+ if(" + field + "," + bit + ",0)";
				}
				exps[idx] = new Expression(exp);
				names[idx] = column.getName();
			}
		}
		
		New _new = new New(exps, names, null);
		cursor.addOperation(_new, null);
	}
	
	public void append(ICursor cursor, String option) {
		//??????׷?ӵ?file
		List tables = getPd().getTables();
		IPhyTable table = null;
		boolean flag = true;//????д???־
		int size = tables.size();
		if (size == 0) {
			return;
		} else if (option != null && option.indexOf("y") != -1) {
			table = tables.get(0);//??@yʱ???µ???һ????
			flag = false;
		} else if (size == 1) {
			table = tables.get(0);
		} else {
			/**
			 * ?ļ???׷??ʱҪ?????ֲ?????·?α??Զ???@x????·???ô???
			 */
			if (!(cursor instanceof MultipathCursors)) {
				option = (option == null) ? "x" : option + "x";
			}
			table = getPd().getTableMetaDataGroup();
		}
		
		List columns = pd.getColumns();
		if (columns != null) {
			String fields[] = table.getAllColNames();
			convertPseudoColumn(cursor, columns, fields);
		}
		
		try {
			if (flag) {
				option = (option == null) ? "i" : option + "i";
			}
			table.append(cursor, option);
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		}
	}
	
	public Sequence update(Sequence data, String opt) {
		//???µ????һ??file
		List tables = getPd().getTables();
		int size = tables.size();
		if (size == 0) {
			return null;
		}
		IPhyTable table = tables.get(size - 1);

		List columns = pd.getColumns();
		if (columns != null) {
			String fields[] = table.getAllColNames();
			ICursor cursor = new MemoryCursor(data);
			convertPseudoColumn(cursor, columns, fields);
			data = cursor.fetch();
		}
		
		try {
			return table.update(data, opt);
		} catch (IOException e) {
			throw new RQException(e.getMessage(), e);
		}
	}
	
	public Sequence delete(Sequence data, String opt) {
		List tables = getPd().getTables();
		int size = tables.size();
		if (size == 0) {
			return null;
		}
		
		Sequence result = null;
		for (IPhyTable table : tables) {
			List columns = pd.getColumns();
			if (columns != null) {
				String fields[] = table.getAllColNames();
				ICursor cursor = new MemoryCursor(data);
				convertPseudoColumn(cursor, columns, fields);
				data = cursor.fetch();
			}
			
			try {
				result = table.delete(data, opt);
			} catch (IOException e) {
				throw new RQException(e.getMessage(), e);
			}
		}
		return result;
	}
	
	/**
	 * ???????
	 * @param fkName	?????
	 * @param fieldNames ????ֶ?
	 * @param code	???
	 * @return
	 */
	public Pseudo addForeignKeys(String fkName, String []fieldNames, Object code, String[] codeKeys, boolean clone) {
		PseudoTable table = null;
		try {
			table = clone ? (PseudoTable) clone(ctx) : this;
			table.getPd().addPseudoColumn(new PseudoColumn(fkName, fieldNames, code, codeKeys));
//			if (fieldNames == null) {
//				table.addColName(fkName);
//			} else {
//				for (String key : fieldNames) {
//					table.addColName(key);
//				}
//			}
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return table;
	}
	
	// ???ӱ?????????????????????
//	public static ICursor join(PseudoTable masterTable, PseudoTable subTable) {
//		String[] keys = masterTable.getPrimaryKey();
//		if (keys != null) {
//			int size = keys.length;
//			Expression[] exps = new Expression[size];
//			for (int i = 0; i < size; i++) {
//				exps[i] = new Expression(keys[i]);
//			}
//			Expression [][]joinExps = new Expression [][] {exps, exps};//ʹ??????????????join
//			
//			ICursor cursors[] = new ICursor[]{masterTable.cursor(null, null), subTable.cursor(null, null)};
//			ICursor cursor = CursorUtil.joinx(cursors, null, joinExps, null, masterTable.getContext());
//			return cursor;
//		}
//		return null;
//	}
	
	/**
	 * ????????Ӧ????????ֶ?
	 * @return
	 */
	public String[] getFieldNames() {
		return getPd().getAllColNames();
	}
	
	protected static byte getProperDataType(Object value) {
		if (value instanceof String) {
			return Types.DT_STRING;
		}
		if (value instanceof java.lang.Double || value instanceof java.lang.Float) {
			return Types.DT_DOUBLE;
		}
		if (value instanceof java.lang.Integer) {
				return Types.DT_INT;
			}
		
		if (value instanceof java.lang.Integer || value instanceof java.lang.Long ||
			value instanceof java.math.BigInteger) {
			return Types.DT_LONG;
		}

		if (value instanceof java.sql.Time) {
			return Types.DT_TIME;
		}

		if (value instanceof java.sql.Timestamp) {
			return Types.DT_DATETIME;
		}

		if (value instanceof java.sql.Date) {
			return Types.DT_DATE;
		}

		if (value instanceof java.math.BigDecimal) {
			return Types.DT_DECIMAL;
		}
		if (value instanceof java.lang.Boolean) {
			return Types.DT_BOOLEAN;
		}
		return Types.DT_STRING;
	}
	
	/**
	 * ????????Ӧ???????ÿ?е?????????
	 * ע?⣺???ص????????Ե?һ????¼Ϊ׼
	 * @return
	 */
	public byte[] getFieldTypes() {
		List tables = getPd().getTables();
		ICursor cursor = tables.get(0).cursor(null, null, null, null, null, null, 1, null, ctx);
		Sequence data = cursor.fetch(1);
		cursor.close();
		
		if (data == null || data.length() == 0) {
			return null;
		}
		
		BaseRecord record = (BaseRecord) data.getMem(1);
		Object[] objs = record.getFieldValues();
		int len = objs.length;
		byte[] types = new byte[len];
		
		for (int i = 0; i < len; i++) {
			types[i] = getProperDataType(objs[i]);
		}
		return types;
	}
	
	/**
	 * ?????????????????еĶ???
	 * û?????ʱ????NULL
	 * @return
	 */
	public List getDimColumns() {
		List dims = new ArrayList();
		List columns = getPd().getColumns();
		for (PseudoColumn col : columns) {
			if (col.getDim() != null) {
				dims.add(col);
			}
		}
		if (dims.size() == 0) {
			return null;
		}
		return dims;
	}
}