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

com.scudata.dm.query.SimpleUnion 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.dm.query;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.scudata.cellset.ICellSet;
import com.scudata.common.MessageManager;
import com.scudata.common.RQException;
import com.scudata.dm.Context;
import com.scudata.dm.DataStruct;
import com.scudata.dm.Sequence;
import com.scudata.dm.cursor.ICursor;
import com.scudata.dm.cursor.MemoryCursor;
import com.scudata.dm.cursor.MergesCursor;
import com.scudata.dm.op.New;
import com.scudata.expression.Expression;
import com.scudata.resources.ParseMessage;

public class SimpleUnion 
{
	final public static int unionType = 0x01;
	final public static int exceptType = 0x02;
	final public static int intersectType = 0x04;
	final public static int allType = 0x08;
	
	private List parameterList;
	private Context ctx;
	private DataStruct ds;
	private ICursor icur;
	private Map withTableMap;
	private ICellSet ics;
	private boolean isMemory;
	
	public SimpleUnion(ICellSet ics, Context ctx)
	{
		this.icur = null;
		this.ds = null;
		this.ctx = ctx;
		this.ics = ics;
		init();
	}
	
	private void init()
	{
		this.parameterList = null;
		if(this.ctx == null)
		{
			this.ctx = new Context();
		}
		this.withTableMap = null;
	}
	
	public void setSQLParameters(List paramList)
	{
		this.parameterList = paramList;
	}
	
	public ICursor query(Token[] tokens, int start, int next)
	{
		start = scanWith(tokens, start, next);
		if(start < 0)
		{
			MessageManager mm = ParseMessage.get();
			throw new RQException(mm.getMessage("syntax.error") + ":query, ?Ƿ??IJ?ѯ???");
		}
		
		tokens = Arrays.copyOfRange(tokens, start, next);
		start = 0;
		next = tokens.length;
		
		List mergeList = new ArrayList();
		List orderList = new ArrayList();
		
		List subTokenList = scanUnion(tokens, start, next, mergeList, orderList);
		if(subTokenList.size() == 1)
		{
			SimpleJoin join = new SimpleJoin(this.ics, this.ctx);
			join.setMemory(this.isMemory);
			join.setSQLParameters(this.parameterList);
			join.setWithTableMap(this.withTableMap);
			this.icur = join.query(tokens, start, next);
			this.ds = join.getDataStruct();
		}
		else
		{
			this.isMemory = true;
			
			DataStruct ds = null;
			Expression[] colExps = null;
			List subCurList = new ArrayList(subTokenList.size());
			
			for(int i=0, sz=subTokenList.size(); i orderStrList = new ArrayList();
					List descList = new ArrayList();
					int commaPos = -1;
					do
					{
						commaPos = Tokenizer.scanComma(orderTokens, begin, end);
						if(commaPos < 0)
						{
							StringBuffer sb = new StringBuffer();
							int desc = 0;
							for(int i=begin; i= 0);
					exps = new Expression[orderStrList.size()];
					for(int i=0, sz=orderStrList.size(); i ds.getFieldCount())
							{
								MessageManager mm = ParseMessage.get();
								throw new RQException(mm.getMessage("syntax.error") + ":scanUnion, ?????ֶ???ų?????Χ");
							}
							exps[i] = new Expression(String.format("%s#%d%s", ifDesc?"-(":"", k, ifDesc?")":""));
						}
						catch(NumberFormatException nfe)
						{
							for(int j=0, len=ds.getFieldCount(); j scanUnion(Token []tokens, int start, int next, List mergeList, List orderList) 
	{
		if(mergeList == null)
		{
			MessageManager mm = ParseMessage.get();
			throw new RQException(mm.getMessage("syntax.error") + ":scanUnion, ????????:?????????б?????Ϊ??");
		}
		mergeList.clear();
		if(orderList == null)
		{
			MessageManager mm = ParseMessage.get();
			throw new RQException(mm.getMessage("syntax.error") + ":scanUnion, ????????:?????ֶ??б?????Ϊ??");
		}
		orderList.clear();
		String[] keyWords = new String[]{"UNION", "INTERSECT", "EXCEPT", "MINUS"};
		List tokenList = new ArrayList();
		List resultList = new ArrayList();
		int keyPos = -1;
		int begin = start;
		do
		{
			keyPos = Tokenizer.scanKeyWords(keyWords, tokens, begin, next);
			if(keyPos < 0)
			{
				Token[] subTokens = Arrays.copyOfRange(tokens, begin, next);
				tokenList.add(subTokens);
			}
			else
			{
				Token[] subTokens = Arrays.copyOfRange(tokens, begin, keyPos);
				tokenList.add(subTokens);
				int mergeType = 0;
				if(tokens[keyPos].isKeyWord("UNION"))
				{
					mergeType = unionType;
				}
				else if(tokens[keyPos].isKeyWord("INTERSECT"))
				{
					mergeType = intersectType;
				}
				else if(tokens[keyPos].isKeyWord("EXCEPT"))
				{
					mergeType = exceptType;
				}
				else if(tokens[keyPos].isKeyWord("MINUS"))
				{
					mergeType = exceptType;
				}
				if(keyPos+1 == next)
				{
					MessageManager mm = ParseMessage.get();
					throw new RQException(mm.getMessage("syntax.error") + ":scanUnion, SQL??䳤?ȴ???");
				}
				if(tokens[keyPos+1].getType() == Tokenizer.KEYWORD && tokens[keyPos+1].isKeyWord("ALL"))
				{
					if(mergeType != unionType)
					{
						MessageManager mm = ParseMessage.get();
						throw new RQException(mm.getMessage("syntax.error") + ":scanUnion, ??֧??EXCEPT(MINUS)??INTERSECT??ALL?ؼ???????");
					}
					mergeType |= allType;
					begin = keyPos + 2;
				}
				else
				{
					begin = keyPos + 1;
				}
				if(begin == next)
				{
					MessageManager mm = ParseMessage.get();
					throw new RQException(mm.getMessage("syntax.error") + ":scanUnion, SQL??䳤?ȴ???");
				}
				mergeList.add(mergeType);
			}
		}
		while(keyPos >= 0);
		
		if(tokenList.size() > 0)
		{
			for(int i=0, sz=tokenList.size(); i= 0)
				{
					if(i != sz-1)
					{
						MessageManager mm = ParseMessage.get();
						throw new RQException(mm.getMessage("syntax.error") + ":scanUnion, ?м??Ϲ?ϵ?????ORDER?Ӿ???????????Ψһ");
					}
					else  // ??????Ϊȫ?ֵ?order??¼
					{
						Token[] orderTokens = Arrays.copyOfRange(subTokens, orderPos, len);
						orderList.addAll(Arrays.asList(orderTokens));
						subTokens = Arrays.copyOfRange(subTokens, 0, orderPos);
						len = subTokens.length;
					}
				}
				while(subTokens[0].getType() == Tokenizer.LPAREN) //??ȥ???????????
				{
					int end = Tokenizer.scanParen(subTokens, 0, len);
					if(end == len - 1)
					{
						subTokens = Arrays.copyOfRange(subTokens, 1, len-1);
						len = subTokens.length;
					}
					else
					{
						break;
					}
				}
				orderPos = Tokenizer.scanKeyWord("ORDER", subTokens, 0, len);
				if(orderPos >= 0)
				{
					int topPos = Tokenizer.scanKeyWord("TOP", subTokens, 0, len);
					int limitPos = Tokenizer.scanKeyWord("LIMIT", subTokens, 0, len);
					int offsetPos = Tokenizer.scanKeyWord("OFFSET", subTokens, 0, len);
					if(topPos < 0 && limitPos < 0 && offsetPos < 0) // ?????????????û??top/limit/offset????????order?????Ż???
					{
						subTokens = Arrays.copyOfRange(subTokens, 0, orderPos);
						len = subTokens.length;
					}
				}
				while(subTokens[0].getType() == Tokenizer.LPAREN)//?ü?order???ٴ???ȥ???????????
				{
					int end = Tokenizer.scanParen(subTokens, 0, len);
					if(end == len - 1)
					{
						subTokens = Arrays.copyOfRange(subTokens, 1, len-1);
						len = subTokens.length;
					}
					else
					{
						break;
					}
				}
				resultList.add(subTokens);
			}
		}
		
		return resultList;
	}
	
	private void addTable(Token[] tokens, int start, int next)
	{
		if (start+4 >= next)
		{
			MessageManager mm = ParseMessage.get();
			throw new RQException(mm.getMessage("syntax.error") + ":addTable, WITH?Ӿ䳤?ȴ???");
		}
		else if (tokens[start].getType() != Tokenizer.IDENT )
		{
			MessageManager mm = ParseMessage.get();
			throw new RQException(mm.getMessage("syntax.error") + ":addTable, WITH?Ӿ??????????");
		}
		else if (!tokens[start+1].isKeyWord("AS"))
		{
			MessageManager mm = ParseMessage.get();
			throw new RQException(mm.getMessage("syntax.error") + ":addTable, WITH?Ӿ?AS?ؼ??ִ???");
		}
		else if (tokens[start+2].getType() != Tokenizer.LPAREN || tokens[next-1].getType() != Tokenizer.RPAREN)
		{
			MessageManager mm = ParseMessage.get();
			throw new RQException(mm.getMessage("syntax.error") + ":addTable, WITH?Ӿ????????Ŵ???");
		}
		
		String tableName = tokens[start].getString();
		String tableExpress = "";
		Token[] newTokens = new Token[next-start-4];
		for(int i=start+3, j=0; i<=next-2; i++, j++)
		{
			tableExpress += tokens[i].getOriginString();
			tableExpress += tokens[i].getSpaces();
			newTokens[j] = tokens[i];
		}
		
		tableExpress = tableExpress.trim();
		
		Object tableNode = null;	
		if(tableExpress.startsWith("\"") && tableExpress.endsWith("\"") //??""??Ĭ???DZ??ļ?????????֧??
			&& tableExpress.substring(1, tableExpress.length()-1).indexOf("\"") == -1)
		{
			MessageManager mm = ParseMessage.get();
			throw new RQException(mm.getMessage("syntax.error") + ":addTable, WITH?Ӿ???ֻ??ʹ?ü??????ű????Ӳ?ѯ???");
		}
		else //????????Ǽ?????????ʽ???Ӳ?ѯ???????
		{
			try
			{
				Expression exp = new Expression(this.ics, this.ctx, tableExpress);
				exp.calculate(this.ctx);
				tableNode = exp;
			}
			catch(RQException rq)
			{
				String[] keywords = new String[]{"SELECT", "WITH", "UNION", "INTERSECT", "EXCEPT", "MINUS"};
				int keyPos = Tokenizer.scanKeyWords(keywords, newTokens, 0, newTokens.length);
				boolean isSubQuery = ((keyPos < 0) ? false : true);
				if(isSubQuery)
				{
					try
					{
						int intoPos = -1;
						int withPos = -1;
						int orderPos =  -1;
						int topPos = -1;
						int limitPos = -1;
						int offsetPos = -1;
						for(int i=0; i= 0)
						{
							throw new RQException("INTO");
						}
						else if(withPos >= 0)
						{
							throw new RQException("WITH");
						}
						else if(orderPos >= 0)
						{
							if(topPos < 0 && limitPos < 0 && offsetPos < 0)
							{
								throw new RQException("ORDER");
							}
						}
						Map subWithTableMap = new HashMap();
						subWithTableMap.putAll(this.withTableMap);//?????µ?Map?Է?ֹSimpleSQL?ص??????????ѭ??
						SimpleSQL lq = new SimpleSQL(this.ics, newTokens, 0, newTokens.length, this.parameterList, this.ctx, false);
						lq.setMemory(this.isMemory);
						lq.setWithTableMap(subWithTableMap);
						lq.query();
						tableNode = lq;
					}
					catch(RQException ex)
					{
						String msg = ex.getMessage();
						if(msg != null && msg.equalsIgnoreCase("INTO"))
						{
							MessageManager mm = ParseMessage.get();
							throw new RQException(mm.getMessage("syntax.error") + ":addTable, WITH?Ӿ??в???ʹ??INTO?ؼ???");
						}
						else if(msg != null && msg.equalsIgnoreCase("WITH"))
						{
							MessageManager mm = ParseMessage.get();
							throw new RQException(mm.getMessage("syntax.error") + ":addTable, WITH?Ӿ??в???Ƕ??WITH?ؼ???");
						}
						else if(msg != null && msg.equalsIgnoreCase("ORDER"))
						{
							MessageManager mm = ParseMessage.get();
							throw new RQException(mm.getMessage("syntax.error") + ":addTable, WITH?Ӿ??в???ʹ??ORDER?ؼ??ֳ?????TOP/LIMIT/OFFSET?ؼ???");
						}

						isSubQuery = false;
					}
				}
				if(!isSubQuery) //????֧?ֱ??ļ?·??
				{
					MessageManager mm = ParseMessage.get();
					throw new RQException(mm.getMessage("syntax.error") + ":addTable, WITH?Ӿ???ֻ??ʹ?ü??????ű????Ӳ?ѯ???");
				}
			}
		}
		this.withTableMap.put(tableName, tableNode);
	}
	
	private int scanWith(Token[] tokens, int start, int next)
	{
		int beginPos = start;
		int endPos = beginPos;
		int withPos = Tokenizer.scanKeyWord("WITH", tokens, start, next);
		if(withPos >= 0)
		{
			if(withPos != start)
			{
				MessageManager mm = ParseMessage.get();
				throw new RQException(mm.getMessage("syntax.error") + ":scanWith, WITH?ؼ???λ?ô???");
			}
			beginPos = withPos+1;
			while(beginPos + 5 < next && tokens[beginPos].getType() == Tokenizer.IDENT 
					&& tokens[beginPos + 1].isKeyWord("AS") 
					&& tokens[beginPos + 2].getType() == Tokenizer.LPAREN)
			{
				int end = Tokenizer.scanParen(tokens, beginPos + 2, next);
				endPos = end + 1;
				if(endPos == next)
				{
					MessageManager mm = ParseMessage.get();
					throw new RQException(mm.getMessage("syntax.error") + ":scanWith, WITH?Ӿ?ȱ???????");
				}
				else if(tokens[endPos].getType() != Tokenizer.COMMA)
				{
					break;
				}
				beginPos = endPos + 1;
			}
			beginPos = withPos+1;
			while(withPos >= 0)
			{
				if(this.withTableMap == null)
				{
					this.withTableMap = new HashMap();
				}
				int commaPos = Tokenizer.scanComma(tokens, beginPos, endPos);
				if(commaPos < 0)
				{
					addTable(tokens, beginPos, endPos);
					break;
				}
				else
				{
					addTable(tokens, beginPos, commaPos);
					beginPos = commaPos+1;
				}
			}
		}
		return endPos;
	}
	
	public void setWithTableMap(Map tableMap)
	{
		this.withTableMap = tableMap;
	}
	
	void setMemory(boolean isMemory)
	{
		this.isMemory = isMemory;
	}
}