[teiid-commits] teiid SVN: r2684 - in trunk: build/kits/jboss-container and 14 other directories.
teiid-commits at lists.jboss.org
teiid-commits at lists.jboss.org
Tue Oct 26 22:16:54 EDT 2010
Author: rareddy
Date: 2010-10-26 22:16:50 -0400 (Tue, 26 Oct 2010)
New Revision: 2684
Added:
trunk/engine/src/main/java/org/teiid/query/function/aggregate/TextAgg.java
trunk/engine/src/main/java/org/teiid/query/sql/symbol/TextLine.java
Modified:
trunk/api/src/main/java/org/teiid/language/SQLConstants.java
trunk/build/kits/jboss-container/teiid-releasenotes.html
trunk/documentation/reference/src/main/docbook/en-US/content/sql_support.xml
trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java
trunk/engine/src/main/java/org/teiid/query/processor/relational/GroupingNode.java
trunk/engine/src/main/java/org/teiid/query/processor/xml/XMLUtil.java
trunk/engine/src/main/java/org/teiid/query/sql/LanguageVisitor.java
trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java
trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.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/test/java/org/teiid/query/parser/TestParser.java
trunk/engine/src/test/java/org/teiid/query/processor/TestTextTable.java
Log:
TEIID-962: Adding TextAgg function that aggregates expression values into textline using delimiter and header.
Modified: trunk/api/src/main/java/org/teiid/language/SQLConstants.java
===================================================================
--- trunk/api/src/main/java/org/teiid/language/SQLConstants.java 2010-10-26 20:44:55 UTC (rev 2683)
+++ trunk/api/src/main/java/org/teiid/language/SQLConstants.java 2010-10-27 02:16:50 UTC (rev 2684)
@@ -319,6 +319,7 @@
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/build/kits/jboss-container/teiid-releasenotes.html
===================================================================
--- trunk/build/kits/jboss-container/teiid-releasenotes.html 2010-10-26 20:44:55 UTC (rev 2683)
+++ trunk/build/kits/jboss-container/teiid-releasenotes.html 2010-10-27 02:16:50 UTC (rev 2684)
@@ -42,7 +42,8 @@
<LI><B>Improved clustering support</B> - see the Admin Guide chapter on clustering.
<LI><B>IPv6 support</B> - Teiid can started using IPv6 bind address and can be used with JDBC connection.
<LI><B>SESSION_ID</B> - A new system function "SESSION_ID" is added to the system function library.
- <LI><B>Assignment Syntax Improvements<B> - Teiid's procedure syntax for assignments was clarified so that the assignment value must be a proper expression. INSERT/UPDATE/DELETE update counts must be obtained from VARIABLES.ROWCOUNT, scalar values must be obtained via a scalar subquery.
+ <LI><B>Assignment Syntax Improvements<B> - Teiid's procedure syntax for assignments was clarified so that the assignment value must be a proper expression. INSERT/UPDATE/DELETE update counts must be obtained from VARIABLES.ROWCOUNT, scalar values must be obtained via a scalar subquery.
+ <LI><B>TEXTAGG</B> - SQL support for Text aggregation. Using this function expression values can be aggregated into a single line of text with delimiter and header, that can be optionally saved to a text file.
The parser will continue to accept the old syntax and convert the query into the proper form.
</UL>
Modified: trunk/documentation/reference/src/main/docbook/en-US/content/sql_support.xml
===================================================================
--- trunk/documentation/reference/src/main/docbook/en-US/content/sql_support.xml 2010-10-26 20:44:55 UTC (rev 2683)
+++ trunk/documentation/reference/src/main/docbook/en-US/content/sql_support.xml 2010-10-27 02:16:50 UTC (rev 2684)
@@ -238,8 +238,15 @@
<para>STDDEV_SAMP(x) – sample standar deviation (excluding null) logically equals SQRT(VAR_SAMP(x))</para>
</listitem>
<listitem>
+ <para>TEXTAGG((expression [as name], ... [DELIMITER char] [QUOTE char] [HEADER]
+ <link linkend="orderby_clause">[ORDER BY ...]</link>) – Text concatination of all expressions in a group (excluding null).
+ When DELIMITER is not specified, by default comma(,) is used as delimiter. Use QUOTE, to quote the each expression value with
+ provided character. If HEADER is specified, the result contains the header row as first line. This aggregation returns a Clob.
+ </para>
+ </listitem>
+ <listitem>
<para>XMLAGG(xml_expr <link linkend="orderby_clause">[ORDER BY ...]</link>) – xml concatination of all xml expressions in a group (excluding null)</para>
- </listitem>
+ </listitem>
</itemizedlist>
<itemizedlist>
<para>Syntax Rules:
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-26 20:44:55 UTC (rev 2683)
+++ trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java 2010-10-27 02:16:50 UTC (rev 2684)
@@ -98,6 +98,7 @@
import org.teiid.query.sql.symbol.ScalarSubquery;
import org.teiid.query.sql.symbol.SearchedCaseExpression;
import org.teiid.query.sql.symbol.SingleElementSymbol;
+import org.teiid.query.sql.symbol.TextLine;
import org.teiid.query.sql.symbol.XMLElement;
import org.teiid.query.sql.symbol.XMLForest;
import org.teiid.query.sql.symbol.XMLNamespaces;
@@ -647,6 +648,8 @@
return evaluate((ScalarSubquery) expression, tuple);
} else if (expression instanceof Criteria) {
return evaluate((Criteria)expression, tuple);
+ } else if (expression instanceof TextLine){
+ return evaluateTextForest(tuple, (TextLine)expression);
} else if (expression instanceof XMLElement){
return evaluateXMLElement(tuple, (XMLElement)expression);
} else if (expression instanceof XMLForest){
@@ -809,7 +812,14 @@
InputStreamFactory isf = getInputStreamFactory(value);
return new ClobType(new ClobImpl(isf, -1));
}
+
+ private Object evaluateTextForest(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());
+ }
+
private Object evaluateXMLForest(List<?> tuple, XMLForest function)
throws ExpressionEvaluationException, BlockedException,
TeiidComponentException, FunctionExecutionException {
Added: trunk/engine/src/main/java/org/teiid/query/function/aggregate/TextAgg.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/aggregate/TextAgg.java (rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/function/aggregate/TextAgg.java 2010-10-27 02:16:50 UTC (rev 2684)
@@ -0,0 +1,119 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+package org.teiid.query.function.aggregate;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.sql.SQLException;
+import java.util.List;
+
+import javax.sql.rowset.serial.SerialClob;
+
+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.Streamable;
+import org.teiid.query.processor.xml.XMLUtil.FileStoreInputStreamFactory;
+import org.teiid.query.sql.symbol.TextLine;
+import org.teiid.query.util.CommandContext;
+
+/**
+ * Aggregates Text entries
+ */
+public class TextAgg extends AggregateFunction {
+
+ private FileStoreInputStreamFactory result;
+ private CommandContext context;
+ private TextLine textLine;
+
+ public TextAgg(CommandContext context, TextLine textLine) {
+ this.context = context;
+ this.textLine = textLine;
+ }
+
+ private FileStoreInputStreamFactory buildResult(CommandContext context, TextLine textLine) throws TeiidProcessingException {
+ try {
+ FileStore fs = context.getBufferManager().createFileStore("textagg"); //$NON-NLS-1$
+ FileStoreInputStreamFactory fisf = new FileStoreInputStreamFactory(fs, Streamable.ENCODING);
+ Writer w = fisf.getWriter();
+ if (textLine.isIncludeHeader()) {
+ w.write(TextLine.getHeader(textLine.getExpressions(), textLine.getDelimiter(), textLine.getQuote()));
+ }
+ w.close();
+ return fisf;
+ } catch (IOException e) {
+ throw new TeiidProcessingException(e);
+ }
+ }
+
+ public void reset() {
+ this.result = null;
+ }
+
+ /**
+ * @throws TeiidProcessingException
+ * @throws TeiidComponentException
+ * @see org.teiid.query.function.aggregate.AggregateFunction#addInputDirect(Object, List)
+ */
+ public void addInputDirect(Object input, List<?> tuple) throws TeiidComponentException, TeiidProcessingException {
+ try {
+ if (this.result == null) {
+ this.result = buildResult(this.context, this.textLine);
+ }
+ String in = (String)input;
+ Writer w = result.getWriter();
+ w.write(in);
+ w.close();
+ } catch (IOException e) {
+ throw new TeiidProcessingException(e);
+ }
+ }
+
+ /**
+ * @see org.teiid.query.function.aggregate.AggregateFunction#getResult()
+ */
+ public Object getResult() throws TeiidProcessingException{
+ if (this.result == null) {
+ this.result = buildResult(this.context, this.textLine);
+ }
+
+ try {
+ FileStoreOutputStream fs = this.result.getOuputStream();
+ fs.close();
+
+ if (fs.bytesWritten()) {
+ return new ClobType(new ClobImpl(result, -1));
+ }
+ // 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()));
+ } catch (IOException e) {
+ throw new TeiidProcessingException(e);
+ } catch (SQLException e) {
+ throw new TeiidProcessingException(e);
+ }
+ }
+}
\ No newline at end of file
Property changes on: trunk/engine/src/main/java/org/teiid/query/function/aggregate/TextAgg.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
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-26 20:44:55 UTC (rev 2683)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java 2010-10-27 02:16:50 UTC (rev 2684)
@@ -65,6 +65,7 @@
import org.teiid.query.sql.symbol.QueryString;
import org.teiid.query.sql.symbol.ScalarSubquery;
import org.teiid.query.sql.symbol.SearchedCaseExpression;
+import org.teiid.query.sql.symbol.TextLine;
import org.teiid.query.sql.symbol.XMLAttributes;
import org.teiid.query.sql.symbol.XMLElement;
import org.teiid.query.sql.symbol.XMLForest;
@@ -117,6 +118,11 @@
}
@Override
+ public void visit(TextLine obj) {
+ markInvalid(obj, "Pushdown of TextForest not allowed"); //$NON-NLS-1$
+ }
+
+ @Override
public void visit(XMLForest obj) {
markInvalid(obj, "Pushdown of XMLForest not allowed"); //$NON-NLS-1$
}
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java 2010-10-26 20:44:55 UTC (rev 2683)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java 2010-10-27 02:16:50 UTC (rev 2684)
@@ -741,7 +741,10 @@
nestedAggregates.add(countAgg);
nestedAggregates.add(sumAgg);
nestedAggregates.add(sumSqAgg);
- } else {
+ } else if (aggFunction == Type.TEXTAGG) {
+ continue;
+ }
+ else {
//AGG(X) -> AGG(AGG(X))
newExpression = new AggregateSymbol("stagedAgg", aggFunction.name(), false, partitionAgg); //$NON-NLS-1$
nestedAggregates.add(partitionAgg);
Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/GroupingNode.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/GroupingNode.java 2010-10-26 20:44:55 UTC (rev 2683)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/GroupingNode.java 2010-10-27 02:16:50 UTC (rev 2684)
@@ -22,7 +22,8 @@
package org.teiid.query.processor.relational;
-import static org.teiid.query.analysis.AnalysisRecord.*;
+import static org.teiid.query.analysis.AnalysisRecord.PROP_GROUP_COLS;
+import static org.teiid.query.analysis.AnalysisRecord.PROP_SORT_MODE;
import java.util.ArrayList;
import java.util.Arrays;
@@ -50,6 +51,7 @@
import org.teiid.query.function.aggregate.Min;
import org.teiid.query.function.aggregate.StatsFunction;
import org.teiid.query.function.aggregate.Sum;
+import org.teiid.query.function.aggregate.TextAgg;
import org.teiid.query.function.aggregate.XMLAgg;
import org.teiid.query.processor.BatchCollector;
import org.teiid.query.processor.ProcessorDataManager;
@@ -60,6 +62,7 @@
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Expression;
import org.teiid.query.sql.symbol.SingleElementSymbol;
+import org.teiid.query.sql.symbol.TextLine;
import org.teiid.query.sql.symbol.AggregateSymbol.Type;
import org.teiid.query.util.CommandContext;
@@ -186,6 +189,9 @@
case XMLAGG:
functions[i] = new XMLAgg(context);
break;
+ case TEXTAGG:
+ functions[i] = new TextAgg(context, (TextLine)ex);
+ break;
default:
functions[i] = new StatsFunction(function);
Modified: trunk/engine/src/main/java/org/teiid/query/processor/xml/XMLUtil.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/xml/XMLUtil.java 2010-10-26 20:44:55 UTC (rev 2683)
+++ trunk/engine/src/main/java/org/teiid/query/processor/xml/XMLUtil.java 2010-10-27 02:16:50 UTC (rev 2684)
@@ -26,7 +26,6 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;
@@ -79,7 +78,7 @@
return new OutputStreamWriter(fsos, Charset.forName(encoding));
}
- public OutputStream getOuputStream() {
+ public FileStoreOutputStream getOuputStream() {
return fsos;
}
Modified: trunk/engine/src/main/java/org/teiid/query/sql/LanguageVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/LanguageVisitor.java 2010-10-26 20:44:55 UTC (rev 2683)
+++ trunk/engine/src/main/java/org/teiid/query/sql/LanguageVisitor.java 2010-10-27 02:16:50 UTC (rev 2684)
@@ -129,6 +129,7 @@
public void visit(XMLForest obj) {}
public void visit(XMLNamespaces obj) {}
public void visit(TextTable obj) {}
+ public void visit(TextLine obj) {}
public void visit(XMLTable obj) {}
public void visit(DerivedColumn obj) {}
public void visit(XMLSerialize obj) {}
Modified: trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java 2010-10-26 20:44:55 UTC (rev 2683)
+++ trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java 2010-10-27 02:16:50 UTC (rev 2684)
@@ -97,6 +97,7 @@
import org.teiid.query.sql.symbol.Reference;
import org.teiid.query.sql.symbol.ScalarSubquery;
import org.teiid.query.sql.symbol.SearchedCaseExpression;
+import org.teiid.query.sql.symbol.TextLine;
import org.teiid.query.sql.symbol.XMLAttributes;
import org.teiid.query.sql.symbol.XMLElement;
import org.teiid.query.sql.symbol.XMLForest;
@@ -541,6 +542,13 @@
}
@Override
+ public void visit(TextLine obj) {
+ preVisitVisitor(obj);
+ visitNodes(obj.getExpressions());
+ postVisitVisitor(obj);
+ }
+
+ @Override
public void visit(XMLForest obj) {
preVisitVisitor(obj);
visitNode(obj.getNamespaces());
Modified: trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java 2010-10-26 20:44:55 UTC (rev 2683)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java 2010-10-27 02:16:50 UTC (rev 2684)
@@ -60,6 +60,7 @@
MIN,
MAX,
XMLAGG,
+ TEXTAGG,
ANY,
SOME,
EVERY,
Added: trunk/engine/src/main/java/org/teiid/query/sql/symbol/TextLine.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/symbol/TextLine.java (rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/TextLine.java 2010-10-27 02:16:50 UTC (rev 2684)
@@ -0,0 +1,196 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+package org.teiid.query.sql.symbol;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.teiid.core.types.DataTypeManager;
+import org.teiid.core.util.EquivalenceUtil;
+import org.teiid.core.util.HashCodeUtil;
+import org.teiid.query.eval.Evaluator;
+import org.teiid.query.sql.LanguageVisitor;
+import org.teiid.query.sql.visitor.SQLStringVisitor;
+
+public class TextLine implements Expression {
+ public static String nl = System.getProperty("line.separator"); //$NON-NLS-1$
+
+ private Character delimiter = null;
+ private Character quote = null;
+ private boolean includeHeader;
+ private List<DerivedColumn> expressions;
+
+ public Character getDelimiter() {
+ return delimiter;
+ }
+
+ public void setDelimiter(Character delimiter) {
+ this.delimiter = delimiter;
+ }
+
+ public Character getQuote() {
+ return quote;
+ }
+
+ public void setQuote(Character quote) {
+ this.quote = quote;
+ }
+
+ public boolean isIncludeHeader() {
+ return includeHeader;
+ }
+
+ public void setIncludeHeader(boolean includeHeader) {
+ this.includeHeader = includeHeader;
+ }
+
+ public List<DerivedColumn> getExpressions() {
+ return expressions;
+ }
+
+ public void setExpressions(List<DerivedColumn> expressions) {
+ this.expressions = expressions;
+ }
+
+ @Override
+ public Class<?> getType() {
+ return DataTypeManager.DefaultDataClasses.CLOB;
+ }
+
+ @Override
+ public boolean isResolved() {
+ for (DerivedColumn arg : this.expressions) {
+ if (!arg.getExpression().isResolved()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void acceptVisitor(LanguageVisitor visitor) {
+ visitor.visit(this);
+ }
+
+ @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.includeHeader = this.includeHeader;
+ return clone;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof TextLine)) {
+ return false;
+ }
+ TextLine other = (TextLine)obj;
+ return EquivalenceUtil.areEqual(this.expressions, other.expressions)
+ && EquivalenceUtil.areEqual(this.delimiter, other.delimiter)
+ && EquivalenceUtil.areEqual(this.quote, other.quote)
+ && this.includeHeader == other.includeHeader;
+ }
+
+ @Override
+ public int hashCode() {
+ return HashCodeUtil.expHashCode(0, this.expressions);
+ }
+
+ @Override
+ public String toString() {
+ return SQLStringVisitor.getSQLString(this);
+ }
+
+ public static String evaluate(final Evaluator.NameValuePair[] values, Character delimeter, Character quote) {
+
+ if (delimeter == null) {
+ delimeter = new Character(',');
+ }
+
+ 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);
+ }
+ if (i < values.length-1) {
+ 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);
+ }
+ }
+}
Property changes on: trunk/engine/src/main/java/org/teiid/query/sql/symbol/TextLine.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
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-26 20:44:55 UTC (rev 2683)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java 2010-10-27 02:16:50 UTC (rev 2684)
@@ -116,6 +116,7 @@
import org.teiid.query.sql.symbol.SearchedCaseExpression;
import org.teiid.query.sql.symbol.SelectSymbol;
import org.teiid.query.sql.symbol.SingleElementSymbol;
+import org.teiid.query.sql.symbol.TextLine;
import org.teiid.query.sql.symbol.XMLAttributes;
import org.teiid.query.sql.symbol.XMLElement;
import org.teiid.query.sql.symbol.XMLForest;
@@ -1591,6 +1592,32 @@
registerNodes(obj.getArgs(), 0);
append(")"); //$NON-NLS-1$
}
+
+ @Override
+ public void visit( TextLine obj ) {
+ append("TEXTLINE"); //$NON-NLS-1$
+ append("("); //$NON-NLS-1$
+ registerNodes(obj.getExpressions(), 0);
+
+ if (obj.getDelimiter() != null) {
+ append(SPACE);
+ append(NonReserved.DELIMITER);
+ append(SPACE);
+ visitNode(new Constant(obj.getDelimiter()));
+ }
+ if (obj.getQuote() != null) {
+ append(SPACE);
+ append(NonReserved.QUOTE);
+ append(SPACE);
+ visitNode(new Constant(obj.getQuote()));
+ }
+ if (obj.isIncludeHeader()) {
+ append(SPACE);
+ append(NonReserved.HEADER);
+ }
+
+ append(")"); //$NON-NLS-1$
+ }
@Override
public void visit( XMLNamespaces obj ) {
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-26 20:44:55 UTC (rev 2683)
+++ trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java 2010-10-27 02:16:50 UTC (rev 2684)
@@ -117,6 +117,7 @@
import org.teiid.query.sql.symbol.Reference;
import org.teiid.query.sql.symbol.ScalarSubquery;
import org.teiid.query.sql.symbol.SingleElementSymbol;
+import org.teiid.query.sql.symbol.TextLine;
import org.teiid.query.sql.symbol.XMLAttributes;
import org.teiid.query.sql.symbol.XMLElement;
import org.teiid.query.sql.symbol.XMLForest;
@@ -1238,6 +1239,18 @@
validateXMLContentTypes(dc.getExpression(), obj);
}
}
+
+ @Override
+ public void visit(TextLine obj) {
+ validateDerivedColumnNames(obj, obj.getExpressions());
+ for (DerivedColumn dc : obj.getExpressions()) {
+ if (dc.getAlias() == null) {
+ continue;
+ }
+ validateQName(obj, dc.getAlias());
+ validateXMLContentTypes(dc.getExpression(), obj);
+ }
+ }
private String[] validateQName(LanguageObject obj, String name) {
try {
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-26 20:44:55 UTC (rev 2683)
+++ trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj 2010-10-27 02:16:50 UTC (rev 2684)
@@ -260,6 +260,7 @@
| <SYSTEM_USER: "system_user">
| <TABLE: "table">
| <TEMPORARY: "temporary">
+| <TEXTAGG: "textagg">
| <THEN: "then">
| <TIMEZONE_HOUR: "timezone_hour">
| <TIMEZONE_MINUTE: "timezone_minute">
@@ -1788,6 +1789,69 @@
}
}
+
+AggregateSymbol textAgg(ParseInfo info) :
+{
+ DerivedColumn expression = null;
+ Character delimiter = null;
+ Character quote = null;
+ Integer header = null;
+ List<DerivedColumn> expressions = new ArrayList<DerivedColumn>();
+ OrderBy orderBy = null;
+}
+{
+ <TEXTAGG> <LPAREN>
+ expression = derivedColumn(info)
+ {
+ expressions.add(expression);
+ }
+ (<COMMA>
+ expression = derivedColumn(info)
+ {
+ expressions.add(expression);
+ }
+ )*
+ [
+ LOOKAHEAD(<ID>, { "delimiter".equalsIgnoreCase(getToken(1).image) }) <ID>
+ delimiter = charVal(info, "DELMITER")
+ ]
+ [
+ LOOKAHEAD(<ID>, { "quote".equalsIgnoreCase(getToken(1).image) })
+ ( <ID> quote = charVal(info, "QUOTE") )
+ ]
+ [
+ LOOKAHEAD(<ID>, { "header".equalsIgnoreCase(getToken(1).image) }) <ID>
+ [
+ header = intVal()
+ ]
+ {
+ if (header == null) {
+ header = 1;
+ }
+ }
+ ]
+ [
+ orderBy = orderby(info)
+ ]
+ <RPAREN>
+ {
+ if(! info.aggregatesAllowed) {
+ throw new ParseException(QueryPlugin.Util.getString("SQLParser.Aggregate_only_top_level")); //$NON-NLS-1$
+ }
+
+ TextLine tf = new TextLine();
+ tf.setDelimiter(delimiter);
+ tf.setQuote(quote);
+ tf.setIncludeHeader(header!=null);
+ tf.setExpressions(expressions);
+
+ String name = generateFunctionName(info, "TEXTAGG");
+ AggregateSymbol agg = new AggregateSymbol(name, "TEXTAGG", false, tf);
+ agg.setOrderBy(orderBy);
+ return agg;
+ }
+}
+
AggregateSymbol aggregateSymbol(ParseInfo info) :
{
String func = null;
@@ -3144,6 +3208,8 @@
|
(expression=xmlAgg(info))
|
+ (expression=textAgg(info))
+ |
// Function
LOOKAHEAD(2) (expression=function(info))
|
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-26 20:44:55 UTC (rev 2683)
+++ trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java 2010-10-27 02:16:50 UTC (rev 2684)
@@ -22,7 +22,9 @@
package org.teiid.query.parser;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
@@ -114,6 +116,7 @@
import org.teiid.query.sql.symbol.SearchedCaseExpression;
import org.teiid.query.sql.symbol.TestCaseExpression;
import org.teiid.query.sql.symbol.TestSearchedCaseExpression;
+import org.teiid.query.sql.symbol.TextLine;
import org.teiid.query.sql.symbol.XMLAttributes;
import org.teiid.query.sql.symbol.XMLElement;
import org.teiid.query.sql.symbol.XMLForest;
@@ -6712,6 +6715,39 @@
helpTest(sql, "SELECT XMLAGG(1 ORDER BY e2)", query);
}
+ @Test public void testTextAggWithOrderBy() throws Exception {
+ List<DerivedColumn> expressions = new ArrayList<DerivedColumn>();
+ expressions.add(new DerivedColumn("col1", new ElementSymbol("e1")));
+ expressions.add(new DerivedColumn("col2", new ElementSymbol("e2")));
+
+ TextLine tf = new TextLine();
+ tf.setExpressions(expressions);
+ tf.setDelimiter(new Character(','));
+ tf.setIncludeHeader(true);
+
+ AggregateSymbol as = new AggregateSymbol("foo", Reserved.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);
+ }
+
+// @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-26 20:44:55 UTC (rev 2683)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestTextTable.java 2010-10-27 02:16:50 UTC (rev 2684)
@@ -22,8 +22,11 @@
package org.teiid.query.processor;
+import static org.teiid.query.optimizer.TestOptimizer.getTypicalCapabilities;
+import static org.teiid.query.optimizer.TestOptimizer.helpPlan;
import static org.teiid.query.processor.TestProcessor.*;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -33,7 +36,12 @@
import org.teiid.core.types.ClobType;
import org.teiid.core.types.InputStreamFactory;
import org.teiid.core.util.UnitTestUtil;
+import org.teiid.query.optimizer.TestOptimizer.ComparisonMode;
+import org.teiid.query.optimizer.capabilities.BasicSourceCapabilities;
import org.teiid.query.optimizer.capabilities.DefaultCapabilitiesFinder;
+import org.teiid.query.optimizer.capabilities.FakeCapabilitiesFinder;
+import org.teiid.query.optimizer.capabilities.SourceCapabilities.Capability;
+import org.teiid.query.unittest.FakeMetadataFacade;
import org.teiid.query.unittest.FakeMetadataFactory;
@SuppressWarnings({"unchecked", "nls"})
@@ -221,4 +229,31 @@
return new ClobType(new ClobImpl(new InputStreamFactory.FileInputStreamFactory(UnitTestUtil.getTestDataFile(file)), -1));
}
+ @Test public void testTextAgg() throws Exception {
+ FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
+ FakeMetadataFacade metadata = FakeMetadataFactory.example1Cached();
+
+ BasicSourceCapabilities caps = getTypicalCapabilities();
+ caps.setCapabilitySupport(Capability.QUERY_SUBQUERIES_SCALAR, false);
+ caps.setCapabilitySupport(Capability.QUERY_AGGREGATES, true);
+ 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$
+ 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();
+ hdm.addData("SELECT g_0.e1, g_0.e2 FROM pm1.g1 AS g_0", new List[] {Arrays.asList("z", 2), Arrays.asList("b", 1)});
+ hdm.setBlockOnce(true);
+
+ String nl = System.getProperty("line.separator");
+ ArrayList list = new ArrayList();
+ list.add("e1,e2"+nl+"b,1"+nl+"z,2"+nl);
+ List[] expected = new List[] {
+ list,
+ };
+
+ helpProcess(plan, hdm, expected);
+ }
+
}
More information about the teiid-commits
mailing list