[teiid-commits] teiid SVN: r2689 - in trunk: connectors/translator-file/src/main/java/org/teiid/translator/file and 12 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Fri Oct 29 13:21:22 EDT 2010


Author: shawkins
Date: 2010-10-29 13:21:21 -0400 (Fri, 29 Oct 2010)
New Revision: 2689

Modified:
   trunk/api/src/main/java/org/teiid/language/SQLConstants.java
   trunk/connectors/translator-file/src/main/java/org/teiid/translator/file/FileExecutionFactory.java
   trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java
   trunk/engine/src/main/java/org/teiid/query/function/aggregate/TextAgg.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java
   trunk/engine/src/main/java/org/teiid/query/sql/symbol/DerivedColumn.java
   trunk/engine/src/main/java/org/teiid/query/sql/symbol/TextLine.java
   trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
   trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
   trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
   trunk/engine/src/main/resources/org/teiid/query/i18n.properties
   trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
   trunk/engine/src/test/java/org/teiid/query/processor/TestTextTable.java
   trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
   trunk/metadata/src/test/java/org/teiid/metadata/index/TestMultipleModelIndexes.java
Log:
TEIID-962 refinements to textagg.  added the for keyword so that textagg can be non-reserved.  also changed to directly output a blob value and expanded the validation.

Modified: trunk/api/src/main/java/org/teiid/language/SQLConstants.java
===================================================================
--- trunk/api/src/main/java/org/teiid/language/SQLConstants.java	2010-10-28 21:21:51 UTC (rev 2688)
+++ trunk/api/src/main/java/org/teiid/language/SQLConstants.java	2010-10-29 17:21:21 UTC (rev 2689)
@@ -98,6 +98,9 @@
 		public static final String LAST = "LAST"; //$NON-NLS-1$
 		
 		public static final String KEY = "KEY"; //$NON-NLS-1$
+		
+		public static final String ENCODING = "ENCODING"; //$NON-NLS-1$
+		public static final String TEXTAGG = "TEXTAGG"; //$NON-NLS-1$
 	}
 	
 	public interface Reserved {
@@ -319,7 +322,6 @@
 	    public static final String SYSTEM_USER = "SYSTEM_USER"; //$NON-NLS-1$
 		public static final String TABLE = "TABLE"; //$NON-NLS-1$
 	    public static final String TEMPORARY = "TEMPORARY"; //$NON-NLS-1$
-	    public static final String TEXTAGG = "TEXTAGG"; //$NON-NLS-1$
 	    public static final String THEN = "THEN"; //$NON-NLS-1$
 	    public static final String TIME = "TIME"; //$NON-NLS-1$
 		public static final String TIMESTAMP = "TIMESTAMP"; //$NON-NLS-1$

Modified: trunk/connectors/translator-file/src/main/java/org/teiid/translator/file/FileExecutionFactory.java
===================================================================
--- trunk/connectors/translator-file/src/main/java/org/teiid/translator/file/FileExecutionFactory.java	2010-10-28 21:21:51 UTC (rev 2688)
+++ trunk/connectors/translator-file/src/main/java/org/teiid/translator/file/FileExecutionFactory.java	2010-10-29 17:21:21 UTC (rev 2689)
@@ -109,7 +109,7 @@
 			Object value = null;
 			if (isText) {
 				ClobImpl clob = new ClobImpl(isf, -1);
-				clob.setEncoding(encoding);
+				clob.setEncoding(encoding.name());
 				value = new ClobType(clob);
 			} else {
 				value = new BlobType(new BlobImpl(isf));
@@ -131,15 +131,15 @@
 	public static final String GETFILES = "getFiles"; //$NON-NLS-1$
 	public static final String SAVEFILE = "saveFile"; //$NON-NLS-1$
 	
-	private String encoding = Charset.defaultCharset().name();
+	private Charset encoding = Charset.defaultCharset();
 	
 	@TranslatorProperty(display="File Encoding",advanced=true)
 	public String getEncoding() {
-		return encoding;
+		return encoding.name();
 	}
 	
 	public void setEncoding(String encoding) {
-		this.encoding = encoding;
+		this.encoding = Charset.forName(encoding);
 	}
 	
 	//@Override
@@ -161,7 +161,7 @@
 						if (file instanceof SQLXML) {
 							is = ((SQLXML)file).getBinaryStream();
 						} else if (file instanceof Clob) {
-							is = new ReaderInputStream(((Clob)file).getCharacterStream(), Charset.forName(encoding));
+							is = new ReaderInputStream(((Clob)file).getCharacterStream(), encoding);
 						} else if (file instanceof Blob) {
 							is = ((Blob)file).getBinaryStream();
 						} else {

Modified: trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java	2010-10-28 21:21:51 UTC (rev 2688)
+++ trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java	2010-10-29 17:21:21 UTC (rev 2689)
@@ -30,6 +30,7 @@
 import java.sql.SQLException;
 import java.sql.SQLXML;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -649,7 +650,7 @@
 	   } else if (expression instanceof Criteria) {
 		   return evaluate((Criteria)expression, tuple);
 	   } else if (expression instanceof TextLine){
-		   return evaluateTextForest(tuple, (TextLine)expression);
+		   return evaluateTextLine(tuple, (TextLine)expression);
 	   } else if (expression instanceof XMLElement){
 		   return evaluateXMLElement(tuple, (XMLElement)expression);
 	   } else if (expression instanceof XMLForest){
@@ -813,11 +814,19 @@
 		return new ClobType(new ClobImpl(isf, -1));
 	}
 	
-	private Object evaluateTextForest(List<?> tuple, TextLine function) 	throws ExpressionEvaluationException, BlockedException, TeiidComponentException, FunctionExecutionException {
+	private Object evaluateTextLine(List<?> tuple, TextLine function) throws ExpressionEvaluationException, BlockedException, TeiidComponentException, FunctionExecutionException {
 		List<DerivedColumn> args = function.getExpressions();
 		Evaluator.NameValuePair<Object>[] nameValuePairs = getNameValuePairs(tuple, args, true);
-
-		return TextLine.evaluate(nameValuePairs, function.getDelimiter(), function.getQuote());
+		
+		try {
+			return TextLine.evaluate(Arrays.asList(nameValuePairs), new TextLine.ValueExtractor<NameValuePair<Object>>() {
+				public Object getValue(NameValuePair<Object> t) {
+					return t.value;
+				}
+			}, function.getDelimiter(), function.getQuote());
+		} catch (TransformationException e) {
+			throw new ExpressionEvaluationException(e, e.getMessage());
+		}
 	}
 
 	private Object evaluateXMLForest(List<?> tuple, XMLForest function)

Modified: trunk/engine/src/main/java/org/teiid/query/function/aggregate/TextAgg.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/TextAgg.java	2010-10-28 21:21:51 UTC (rev 2688)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/TextAgg.java	2010-10-29 17:21:21 UTC (rev 2689)
@@ -25,18 +25,21 @@
 import java.io.IOException;
 import java.io.Writer;
 import java.sql.SQLException;
+import java.util.Arrays;
 import java.util.List;
 
-import javax.sql.rowset.serial.SerialClob;
+import javax.sql.rowset.serial.SerialBlob;
 
 import org.teiid.common.buffer.FileStore;
 import org.teiid.common.buffer.FileStore.FileStoreOutputStream;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
-import org.teiid.core.types.ClobImpl;
-import org.teiid.core.types.ClobType;
+import org.teiid.core.types.BlobImpl;
+import org.teiid.core.types.BlobType;
 import org.teiid.core.types.Streamable;
 import org.teiid.query.processor.xml.XMLUtil.FileStoreInputStreamFactory;
+import org.teiid.query.sql.symbol.DerivedColumn;
+import org.teiid.query.sql.symbol.ElementSymbol;
 import org.teiid.query.sql.symbol.TextLine;
 import org.teiid.query.util.CommandContext;
 
@@ -54,13 +57,20 @@
     	this.textLine = textLine;    	    	
 	}
 
-	private FileStoreInputStreamFactory buildResult(CommandContext context, TextLine textLine) throws TeiidProcessingException {
+	private FileStoreInputStreamFactory buildResult() throws TeiidProcessingException {
 		try {
 			FileStore fs = context.getBufferManager().createFileStore("textagg"); //$NON-NLS-1$
-			FileStoreInputStreamFactory fisf = new FileStoreInputStreamFactory(fs, Streamable.ENCODING);
+			FileStoreInputStreamFactory fisf = new FileStoreInputStreamFactory(fs, textLine.getEncoding()==null?Streamable.ENCODING:textLine.getEncoding());
 			Writer w = fisf.getWriter();
 			if (textLine.isIncludeHeader()) {
-				w.write(TextLine.getHeader(textLine.getExpressions(), textLine.getDelimiter(), textLine.getQuote()));
+				w.write(TextLine.evaluate(textLine.getExpressions(), new TextLine.ValueExtractor<DerivedColumn>() {
+					public Object getValue(DerivedColumn t) {
+						if (t.getAlias() == null && t.getExpression() instanceof ElementSymbol) {
+							return ((ElementSymbol)t.getExpression()).getShortName();
+						}
+						return t.getAlias();
+					}
+				}, textLine.getDelimiter(), textLine.getQuote()));
 			}
 			w.close();
 			return fisf;
@@ -81,7 +91,7 @@
     public void addInputDirect(Object input, List<?> tuple) throws TeiidComponentException, TeiidProcessingException {
     	try {
     		if (this.result == null) {
-    			this.result = buildResult(this.context, this.textLine);
+    			this.result = buildResult();
     		}
     		String in = (String)input;
     		Writer w = result.getWriter();
@@ -97,7 +107,7 @@
      */
     public Object getResult() throws TeiidProcessingException{
     	if (this.result == null) {
-    		this.result = buildResult(this.context, this.textLine);
+    		this.result = buildResult();
     	}
     	
     	try {
@@ -105,11 +115,9 @@
 			fs.close();
 		
 			if (fs.bytesWritten()) {
-				return new ClobType(new ClobImpl(result, -1));
+				return new BlobType(new BlobImpl(result));
 			}
-			// fun convert bytes to string to char array!!
-			String msg = new String(fs.getBuffer(),0, fs.getCount(), Streamable.ENCODING);
-			return new ClobType(new SerialClob(msg.toCharArray()));
+			return new BlobType(new SerialBlob(Arrays.copyOf(fs.getBuffer(), fs.getCount())));
 		} catch (IOException e) {
 			throw new TeiidProcessingException(e);
 		}  catch (SQLException e) {

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java	2010-10-28 21:21:51 UTC (rev 2688)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java	2010-10-29 17:21:21 UTC (rev 2689)
@@ -119,7 +119,7 @@
     
     @Override
     public void visit(TextLine obj) {
-    	markInvalid(obj, "Pushdown of TextForest not allowed"); //$NON-NLS-1$
+    	markInvalid(obj, "Pushdown of TextLine not allowed"); //$NON-NLS-1$
     }
     
     @Override

Modified: trunk/engine/src/main/java/org/teiid/query/sql/symbol/DerivedColumn.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/symbol/DerivedColumn.java	2010-10-28 21:21:51 UTC (rev 2688)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/DerivedColumn.java	2010-10-29 17:21:21 UTC (rev 2689)
@@ -24,6 +24,7 @@
 
 import org.teiid.core.util.EquivalenceUtil;
 import org.teiid.core.util.HashCodeUtil;
+import org.teiid.query.function.source.XMLSystemFunctions;
 import org.teiid.query.sql.LanguageObject;
 import org.teiid.query.sql.LanguageVisitor;
 import org.teiid.query.sql.visitor.SQLStringVisitor;

Modified: trunk/engine/src/main/java/org/teiid/query/sql/symbol/TextLine.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/symbol/TextLine.java	2010-10-28 21:21:51 UTC (rev 2688)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/TextLine.java	2010-10-29 17:21:21 UTC (rev 2689)
@@ -21,23 +21,30 @@
  */
 package org.teiid.query.sql.symbol;
 
-import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 
 import org.teiid.core.types.DataTypeManager;
+import org.teiid.core.types.TransformationException;
 import org.teiid.core.util.EquivalenceUtil;
 import org.teiid.core.util.HashCodeUtil;
-import org.teiid.query.eval.Evaluator;
+import org.teiid.core.util.StringUtil;
+import org.teiid.query.sql.LanguageObject;
 import org.teiid.query.sql.LanguageVisitor;
 import org.teiid.query.sql.visitor.SQLStringVisitor;
 
+/**
+ * Represents the only allowable expression for the textagg aggregate.
+ * This is a Teiid specific construct.
+ */
 public class TextLine implements Expression {
-	public static String nl = System.getProperty("line.separator"); //$NON-NLS-1$
+	public static final String nl = System.getProperty("line.separator"); //$NON-NLS-1$
 
-	private Character delimiter = null;
-	private Character quote = null;
+	private Character delimiter;
+	private Character quote;
 	private boolean includeHeader;
 	private List<DerivedColumn> expressions;
+	private String encoding;
 	
 	public Character getDelimiter() {
 		return delimiter;
@@ -46,6 +53,14 @@
 	public void setDelimiter(Character delimiter) {
 		this.delimiter = delimiter;
 	}
+	
+	public String getEncoding() {
+		return encoding;
+	}
+	
+	public void setEncoding(String encoding) {
+		this.encoding = encoding;
+	}
 
 	public Character getQuote() {
 		return quote;
@@ -73,7 +88,7 @@
 	
 	@Override
 	public Class<?> getType() {
-		return DataTypeManager.DefaultDataClasses.CLOB;
+		return DataTypeManager.DefaultDataClasses.BLOB;
 	}
 
 	@Override
@@ -94,24 +109,11 @@
 	@Override
 	public TextLine clone() {
 		TextLine clone = new TextLine();
-
-		if (this.expressions != null && !this.expressions.isEmpty()) {
-			List<DerivedColumn> list = new ArrayList<DerivedColumn>();
-			for (DerivedColumn expr:this.expressions) {
-				list.add(expr.clone());
-			}
-			clone.expressions = list;
-		}
-		
-		if (this.delimiter != null) {
-			clone.delimiter = new Character(this.delimiter);
-		}
-		
-		if (this.quote != null) {
-			clone.quote = new Character(this.quote);
-		}
-		
+		clone.expressions = LanguageObject.Util.deepClone(this.expressions, DerivedColumn.class);
+		clone.delimiter = this.delimiter;
+		clone.quote = this.quote;
 		clone.includeHeader = this.includeHeader;
+		clone.encoding = this.encoding;
 		return clone;
 	}
 
@@ -127,7 +129,8 @@
 		return EquivalenceUtil.areEqual(this.expressions, other.expressions)
 			  && EquivalenceUtil.areEqual(this.delimiter, other.delimiter)
 			  && EquivalenceUtil.areEqual(this.quote, other.quote)
-			  && this.includeHeader == other.includeHeader;
+			  && this.includeHeader == other.includeHeader
+			  && EquivalenceUtil.areEqual(this.encoding, other.encoding);
 	}
 
 	@Override
@@ -140,57 +143,37 @@
 		return SQLStringVisitor.getSQLString(this);
 	}	
 	
-	public static String evaluate(final Evaluator.NameValuePair[] values, Character delimeter, Character quote) {
-				
+	public static interface ValueExtractor<T> {
+		Object getValue(T t);
+	}
+	
+	public static <T> String evaluate(final List<T> values, ValueExtractor<T> valueExtractor, Character delimeter, Character quote) throws TransformationException {
 		if (delimeter == null) {
 			delimeter = new Character(',');
 		}
-				
+		String quoteStr = null;		
+		if (quote == null) {
+			quoteStr = "\""; //$NON-NLS-1$
+		} else {
+			quoteStr = String.valueOf(quote);
+		}
+		String doubleQuote = quoteStr + quoteStr;
 		StringBuilder sb = new StringBuilder();
-		for (int i = 0; i < values.length; i++) {
-			if (values[i].value != null) {
-				addQuote(quote, sb);
-				sb.append(values[i].value);
-				addQuote(quote, sb);
+		for (Iterator<T> iterator = values.iterator(); iterator.hasNext();) {
+			T t = iterator.next();
+			String text = DataTypeManager.transformValue(valueExtractor.getValue(t), DataTypeManager.DefaultDataClasses.STRING);
+			if (text == null) {
+				continue;
 			}
-			if (i < values.length-1) {
+			sb.append(quoteStr);
+			sb.append(StringUtil.replaceAll(text, quoteStr, doubleQuote));
+			sb.append(quoteStr);
+			if (iterator.hasNext()) {
 				sb.append(delimeter);
 			}			
 		}
 		sb.append(nl);
-		
 		return sb.toString();
 	}
-
-	public static String getHeader(List<DerivedColumn> args, Character delimeter, Character quote) {
-		
-		if (delimeter == null) {
-			delimeter = new Character(',');
-		}		
-		
-		StringBuilder sb = new StringBuilder();
-		for (int i = 0; i < args.size(); i++) {
-			DerivedColumn symbol = args.get(i);
-			String name = symbol.getAlias();
-			Expression ex = symbol.getExpression();
-			if (name == null && ex instanceof ElementSymbol) {
-				name = ((ElementSymbol)ex).getShortName();
-			}
-			addQuote(quote, sb);
-			sb.append(name);
-			addQuote(quote, sb);
-			
-			if (i < args.size()-1) {
-				sb.append(delimeter);
-			}
-		}
-		sb.append(nl);
-		return sb.toString();
-	}
 	
-	private static void addQuote(Character quote, StringBuilder sb) {
-		if (quote != null) {
-			sb.append(quote);
-		}
-	}
 }

Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java	2010-10-28 21:21:51 UTC (rev 2688)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java	2010-10-29 17:21:21 UTC (rev 2689)
@@ -1595,8 +1595,8 @@
     
     @Override
     public void visit( TextLine obj ) {
-        append("TEXTLINE"); //$NON-NLS-1$
-        append("("); //$NON-NLS-1$
+        append(FOR); 
+        append(SPACE);
         registerNodes(obj.getExpressions(), 0);
         
         if (obj.getDelimiter() != null) {
@@ -1615,8 +1615,12 @@
             append(SPACE);
             append(NonReserved.HEADER);
         }
-        
-        append(")"); //$NON-NLS-1$
+        if (obj.getEncoding() != null) {
+        	append(SPACE);
+            append(NonReserved.ENCODING);
+        	append(SPACE);
+        	outputDisplayName(obj.getEncoding());
+        }
     }    
 
     @Override

Modified: trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java	2010-10-28 21:21:51 UTC (rev 2688)
+++ trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java	2010-10-29 17:21:21 UTC (rev 2689)
@@ -22,6 +22,7 @@
 
 package org.teiid.query.validator;
 
+import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
@@ -124,6 +125,7 @@
 import org.teiid.query.sql.symbol.XMLNamespaces;
 import org.teiid.query.sql.symbol.XMLParse;
 import org.teiid.query.sql.symbol.XMLQuery;
+import org.teiid.query.sql.symbol.AggregateSymbol.Type;
 import org.teiid.query.sql.util.SymbolMap;
 import org.teiid.query.sql.visitor.AggregateSymbolCollectorVisitor;
 import org.teiid.query.sql.visitor.CommandCollectorVisitor;
@@ -1241,17 +1243,27 @@
     }
     
     @Override
-    public void visit(TextLine obj) {
-    	validateDerivedColumnNames(obj, obj.getExpressions());
-    	for (DerivedColumn dc : obj.getExpressions()) {
-			if (dc.getAlias() == null) {
-				continue;
-			}
-			validateQName(obj, dc.getAlias());
+    public void visit(AggregateSymbol obj) {
+    	if (obj.getAggregateFunction() != Type.TEXTAGG) {
+    		return;
+    	}
+    	TextLine tl = (TextLine)obj.getExpression();
+    	if (tl.isIncludeHeader()) {
+    		validateDerivedColumnNames(obj, tl.getExpressions());
+    	}
+    	for (DerivedColumn dc : tl.getExpressions()) {
 			validateXMLContentTypes(dc.getExpression(), obj);
 		}
+    	validateTextOptions(obj, tl.getDelimiter(), tl.getQuote());
+    	if (tl.getEncoding() != null) {
+    		try {
+    			Charset.forName(tl.getEncoding());
+    		} catch (IllegalArgumentException e) {
+    			handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.invalid_encoding", tl.getEncoding()), obj); //$NON-NLS-1$
+    		}
+    	}
     }
-
+    
 	private String[] validateQName(LanguageObject obj, String name) {
 		try {
 			return Name11Checker.getInstance().getQNameParts(name);
@@ -1401,31 +1413,34 @@
         		handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.text_table_width"), obj); //$NON-NLS-1$
     		}
     	} else {
-        	delimiter = obj.getDelimiter();
-    		if (delimiter == null) {
-    			delimiter = ',';
-    		}
+        	if (obj.getHeader() != null && obj.getHeader() < 0) {
+	    		handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.text_table_negative"), obj); //$NON-NLS-1$
+	    	}
+    		delimiter = obj.getDelimiter();
+    		quote = obj.getQuote();
+			validateTextOptions(obj, delimiter, quote);
     	}
     	if (obj.getSkip() != null && obj.getSkip() < 0) {
     		handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.text_table_negative"), obj); //$NON-NLS-1$
     	}
-		if (!widthSet) {
-	    	if (obj.getHeader() != null && obj.getHeader() < 0) {
-	    		handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.text_table_negative"), obj); //$NON-NLS-1$
-	    	}
-	    	quote = obj.getQuote();
-			if (quote == null) {
-				quote = '"';
-			} 
-			if (EquivalenceUtil.areEqual(quote, delimiter)) {
-				handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.text_table_delimiter"), obj); //$NON-NLS-1$
-			}
-			if (EquivalenceUtil.areEqual(quote, '\n') 
-					|| EquivalenceUtil.areEqual(delimiter, '\n')) {
-				handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.text_table_newline"), obj); //$NON-NLS-1$
-			}
+    }
+
+	private void validateTextOptions(LanguageObject obj, Character delimiter,
+			Character quote) {
+		if (quote == null) {
+			quote = '"';
+		} 
+		if (delimiter == null) {
+			delimiter = ',';
 		}
-    }
+		if (EquivalenceUtil.areEqual(quote, delimiter)) {
+			handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.text_table_delimiter"), obj); //$NON-NLS-1$
+		}
+		if (EquivalenceUtil.areEqual(quote, '\n') 
+				|| EquivalenceUtil.areEqual(delimiter, '\n')) {
+			handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.text_table_newline"), obj); //$NON-NLS-1$
+		}
+	}
     
     @Override
     public void visit(XMLParse obj) {

Modified: trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
===================================================================
--- trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2010-10-28 21:21:51 UTC (rev 2688)
+++ trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2010-10-29 17:21:21 UTC (rev 2689)
@@ -260,7 +260,6 @@
 |   <SYSTEM_USER: "system_user">
 |   <TABLE: "table">
 |   <TEMPORARY: "temporary">
-|   <TEXTAGG: "textagg">
 |   <THEN: "then">
 |   <TIMEZONE_HOUR: "timezone_hour">
 |   <TIMEZONE_MINUTE: "timezone_minute">
@@ -1795,13 +1794,14 @@
 	DerivedColumn expression = null;
 	Character delimiter = null;
 	Character quote = null;
-	Integer header = null;	
+	boolean header = false;	
 	List<DerivedColumn> expressions = new ArrayList<DerivedColumn>();
 	OrderBy orderBy = null;
+	String encoding = null;
 }
 {
-	<TEXTAGG> <LPAREN>
-	expression = derivedColumn(info)
+	nonReserved("TEXTAGG") <LPAREN>
+	<FOR> expression = derivedColumn(info)
 	{
 		expressions.add(expression);
 	}
@@ -1821,16 +1821,13 @@
 	]
 	[
 	  LOOKAHEAD(<ID>, { "header".equalsIgnoreCase(getToken(1).image) }) <ID>
-	  [
-	  	header = intVal()
-	  ]
-	  {
-	  	if (header == null) {
-	  		header = 1;
-	  	}
-	  }
+	  { header = true; }
 	]	
 	[
+	  LOOKAHEAD(<ID>, { "encoding".equalsIgnoreCase(getToken(1).image) })
+	  ( <ID> encoding = id() )
+	]
+	[
 		orderBy = orderby(info)
 	]	
 	<RPAREN>
@@ -1842,9 +1839,9 @@
 		TextLine tf = new TextLine();
 		tf.setDelimiter(delimiter);
 		tf.setQuote(quote);
-		tf.setIncludeHeader(header!=null);
+		tf.setIncludeHeader(header);
 		tf.setExpressions(expressions);
-		
+		tf.setEncoding(encoding);
 		String name = generateFunctionName(info, "TEXTAGG");
 		AggregateSymbol agg = new AggregateSymbol(name, "TEXTAGG", false, tf);
 		agg.setOrderBy(orderBy);
@@ -3199,6 +3196,8 @@
 			<RBRACE>
 		)
 		|
+		LOOKAHEAD(<ID> <LPAREN> <FOR>) (expression=textAgg(info))
+		|
 		// Aggregate function
 		LOOKAHEAD(<ID>, {matchesAny(getToken(1).image, "count", "min", "max", "sum", "avg", "every", "STDDEV_POP", "STDDEV_SAMP", "VAR_SAMP", "VAR_POP") != null}) (expression=aggregateSymbol(info))
 		|
@@ -3208,8 +3207,6 @@
 		|
 		(expression=xmlAgg(info))
 		|
-		(expression=textAgg(info))
-		|		
 		// Function
 		LOOKAHEAD(2) (expression=function(info))
 		|

Modified: trunk/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2010-10-28 21:21:51 UTC (rev 2688)
+++ trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2010-10-29 17:21:21 UTC (rev 2689)
@@ -187,13 +187,14 @@
 ERR.015.012.0025 = Command must project at least one symbol
 ERR.015.012.0026 = Expressions of type OBJECT, CLOB, BLOB, or XML cannot be used in SELECT DISTINCT, ORDER BY, GROUP BY, KEYS, or non-all set queries: [{0}]
 ERR.015.012.0027 = Expressions of type OBJECT, CLOB, BLOB, or XML cannot be used in comparison: {0}.
-ValidationVisitor.expression_requires_name = Non-column expressions require a name in XMLATTRIBUTES, XMLFOREST, or QUERYSTRING
+ValidationVisitor.expression_requires_name = Non-column expressions require a name in XMLATTRIBUTES, XMLFOREST, QUERYSTRING, or TEXTAGG with HEADER
 ValidationVisitor.invalid_lookup_key=Expressions of type OBJECT, CLOB, BLOB, or XML cannot be used as LOOKUP key columns: {0}.
 ValidationVisitor.limit_not_valid_for_xml=The limit clause cannot be used on an XML document query.
 ValidationVisitor.translated_or=Translated user criteria must not contain OR criteria
 ValidationVisitor.union_insert = Select into is not allowed under a set operation: {0}.
 ValidationVisitor.multisource_insert = A multi-source table, {0}, cannot be used in an INSERT with query expression or SELECT INTO statement.
 ValidationVisitor.virtual_update_subquery = Subqueries are not allowed in the criteria for a virtual UPDATE/DELETE: {0}
+ValidationVisitor.invalid_encoding = Invalid encoding: {0}.
 ERR.015.012.0029 = INSERT, UPDATE, and DELETE not allowed on XML documents
 ERR.015.012.0030 = Commands used in stored procedure language not allowed on XML documents
 ERR.015.012.0031 = Queries against XML documents can not have a GROUP By clause
@@ -688,13 +689,13 @@
 ValidationVisitor.text_table_invalid_width=For a fixed width text table, all columns must have width set.
 ValidationVisitor.text_table_width=Fixed width text tables should not have DELIMITER, QUOTE, ESCAPE, or HEADER specified.
 ValidationVisitor.text_table_negative=Text table WIDTH, HEADER, or SKIP values must not be negative. 
-ValidationVisitor.text_table_delimiter=Text table DELIMITER cannot be the same as the QUOTE or ESCAPE characters.
-ValidationVisitor.text_table_newline=Text table DELIMITER, QUOTE, and ESCAPE characters cannot be the new line character.
+ValidationVisitor.text_table_delimiter=Text DELIMITER cannot be the same as the QUOTE or ESCAPE characters.
+ValidationVisitor.text_table_newline=Text DELIMITER, QUOTE, and ESCAPE characters cannot be the new line character.
 ValidationVisitor.xml_namespaces=At most only one NO DEFAULT or DEFAULT namespace may be specified.
 ValidationVisitor.xml_namespaces_reserved=The namespaces xmlns and xml are reserved.
 ValidationVisitor.xml_namespaces_null_uri=The null uri, or empty string, is not allowed as the uri value.
 ValidationVisitor.xml_attributes_reserved=The namespace xmlns is reserved.
-ValidationVisitor.xml_content_type=The expression "{0}" is of OBJECT or BLOB type, which cannot be used as an XML content value.
+ValidationVisitor.xml_content_type=The expression "{0}" is of OBJECT or BLOB type, which cannot be used as an XML or TEXT content value.
 ValidationVisitor.xml_invalid_qname=The qname "{0}" is invalid.
 ValidationVisitor.context_item_type=XMLTABLE or XMLQUERY PASSING context item must be an XML value.
 ValidationVisitor.passing_requires_name=XMLTABLE or XMLQUERY PASSING clause can only contain at most 1 unnamed item.

Modified: trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java	2010-10-28 21:21:51 UTC (rev 2688)
+++ trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java	2010-10-29 17:21:21 UTC (rev 2689)
@@ -40,6 +40,7 @@
 import org.teiid.client.metadata.ParameterInfo;
 import org.teiid.core.TeiidException;
 import org.teiid.core.types.DataTypeManager;
+import org.teiid.language.SQLConstants.NonReserved;
 import org.teiid.language.SQLConstants.Reserved;
 import org.teiid.language.SortSpecification.NullOrdering;
 import org.teiid.query.sql.lang.BetweenCriteria;
@@ -6725,29 +6726,16 @@
         tf.setDelimiter(new Character(','));
         tf.setIncludeHeader(true);
         
-        AggregateSymbol as = new AggregateSymbol("foo", Reserved.TEXTAGG, false, tf);
+        AggregateSymbol as = new AggregateSymbol("foo", NonReserved.TEXTAGG, false, tf);
         as.setOrderBy(new OrderBy(Arrays.asList(new ElementSymbol("e2"))));
         
         Query query = new Query();
         query.setSelect(new Select(Arrays.asList(as)));
         
-        String sql = "SELECT TextAgg(e1 as col1, e2 as col2 delimiter ',' header order by e2)"; //$NON-NLS-1$
-        helpTest(sql, "SELECT TEXTAGG(TEXTLINE(e1 AS col1, e2 AS col2 DELIMITER ',' HEADER) ORDER BY e2)", query);
+        String sql = "SELECT TextAgg(FOR e1 as col1, e2 as col2 delimiter ',' header order by e2)"; //$NON-NLS-1$
+        helpTest(sql, "SELECT TEXTAGG(FOR e1 AS col1, e2 AS col2 DELIMITER ',' HEADER ORDER BY e2)", query);
     }    
     
-//    @Test public void testTextForrest() throws Exception {
-//    	List<DerivedColumn> expressions = new ArrayList<DerivedColumn>();
-//    	expressions.add(new DerivedColumn(null, new Constant(1)));
-//    	expressions.add(new DerivedColumn("col2", new ElementSymbol("e2")));
-//                
-//        TextForest tf = new TextForest();
-//        tf.setExpressions(expressions);
-//        tf.setIncludeHeader(true);
-//        
-//        String sql = "textforest(1, e2 as col2 HEADER)"; //$NON-NLS-1$
-//    	helpTestExpression(sql, "TEXTFOREST(1, e2 AS col2 HEADER)", tf);        
-//    }     
-    
     @Test public void testNestedTable() throws Exception {
         String sql = "SELECT * from TABLE(exec foo()) as x"; //$NON-NLS-1$
         Query query = new Query();

Modified: trunk/engine/src/test/java/org/teiid/query/processor/TestTextTable.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/TestTextTable.java	2010-10-28 21:21:51 UTC (rev 2688)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestTextTable.java	2010-10-29 17:21:21 UTC (rev 2689)
@@ -239,7 +239,7 @@
         caps.setCapabilitySupport(Capability.QUERY_AGGREGATES_MAX, true);
         capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$        
         
-        ProcessorPlan plan = helpPlan("select convert(textagg(pm1.g1.e1, pm1.g1.e2 header order by e2), string) as x  from pm1.g1", metadata,  null, capFinder, //$NON-NLS-1$
+        ProcessorPlan plan = helpPlan("select convert(to_chars(textagg(for pm1.g1.e1, pm1.g1.e2 header order by e2), 'UTF-8'), string) as x from pm1.g1", metadata,  null, capFinder, //$NON-NLS-1$
             new String[] { "SELECT g_0.e1, g_0.e2 FROM pm1.g1 AS g_0" }, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
         
         HardcodedDataManager hdm = new HardcodedDataManager();
@@ -248,7 +248,7 @@
                 
         String nl = System.getProperty("line.separator");
         ArrayList list = new ArrayList();
-        list.add("e1,e2"+nl+"b,1"+nl+"z,2"+nl);
+        list.add("\"e1\",\"e2\""+nl+"\"b\",\"1\""+nl+"\"z\",\"2\""+nl);
         List[] expected = new List[] {
         		list,
         };    

Modified: trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java	2010-10-28 21:21:51 UTC (rev 2688)
+++ trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java	2010-10-29 17:21:21 UTC (rev 2689)
@@ -2083,5 +2083,13 @@
     	models.add("pm1");
         helpValidate("insert into pm1.g1 select * from pm1.g1", new String[] {"pm1.g1"}, new MultiSourceMetadataWrapper(FakeMetadataFactory.example1(), models));  //$NON-NLS-1$
     }
+    
+    @Test public void testTextAggEncoding() throws Exception {
+    	helpValidate("select textagg(for e1 encoding abc) from pm1.g1", new String[] {"TEXTAGG(FOR e1 ENCODING abc)"}, FakeMetadataFactory.example1Cached());  //$NON-NLS-1$
+    }
+    
+    @Test public void testTextAggHeader() throws Exception {
+    	helpValidate("select textagg(for e1 || 1 HEADER) from pm1.g1", new String[] {"TEXTAGG(FOR (e1 || 1) HEADER)"}, FakeMetadataFactory.example1Cached());  //$NON-NLS-1$
+    }
 
 }

Modified: trunk/metadata/src/test/java/org/teiid/metadata/index/TestMultipleModelIndexes.java
===================================================================
--- trunk/metadata/src/test/java/org/teiid/metadata/index/TestMultipleModelIndexes.java	2010-10-28 21:21:51 UTC (rev 2688)
+++ trunk/metadata/src/test/java/org/teiid/metadata/index/TestMultipleModelIndexes.java	2010-10-29 17:21:21 UTC (rev 2689)
@@ -42,7 +42,7 @@
 		assertEquals(1, names.size());
 		
 		//ensure that datatypes are set
-		Table t = (Table)tm.getGroupID(names.iterator().next());
+		Table t = tm.getGroupID(names.iterator().next());
 		assertNotNull(t.getColumns().get(0).getDatatype());
 	}
 	



More information about the teiid-commits mailing list