/*
* 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.dqp.internal.datamgr;
import java.sql.Timestamp;
import java.util.*;
import org.teiid.api.exception.query.QueryMetadataException;
import org.teiid.client.metadata.ParameterInfo;
import org.teiid.common.buffer.TupleBuffer;
import org.teiid.common.buffer.TupleSource;
import org.teiid.core.CoreConstants;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.TeiidRuntimeException;
import org.teiid.core.types.ArrayImpl;
import org.teiid.core.types.DataTypeManager;
import org.teiid.language.*;
import org.teiid.language.Argument.Direction;
import org.teiid.language.Comparison.Operator;
import org.teiid.language.SQLConstants.NonReserved;
import org.teiid.language.SortSpecification.Ordering;
import org.teiid.language.SubqueryComparison.Quantifier;
import org.teiid.language.DerivedColumn;
import org.teiid.language.Select;
import org.teiid.language.WindowSpecification;
import org.teiid.metadata.BaseColumn;
import org.teiid.metadata.Column;
import org.teiid.metadata.Procedure;
import org.teiid.metadata.ProcedureParameter;
import org.teiid.metadata.Table;
import org.teiid.query.QueryPlugin;
import org.teiid.query.function.FunctionDescriptor;
import org.teiid.query.function.FunctionLibrary;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.metadata.TempMetadataID;
import org.teiid.query.optimizer.relational.rules.RulePlaceAccess;
import org.teiid.query.sql.lang.*;
import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.lang.Delete;
import org.teiid.query.sql.lang.GroupBy;
import org.teiid.query.sql.lang.Insert;
import org.teiid.query.sql.lang.Limit;
import org.teiid.query.sql.lang.OrderBy;
import org.teiid.query.sql.lang.SetClause;
import org.teiid.query.sql.lang.SetQuery;
import org.teiid.query.sql.lang.Update;
import org.teiid.query.sql.symbol.*;
import org.teiid.query.sql.symbol.Array;
import org.teiid.query.sql.symbol.Expression;
import org.teiid.query.sql.symbol.Function;
import org.teiid.query.sql.symbol.ScalarSubquery;
import org.teiid.query.sql.symbol.WindowFunction;
import org.teiid.query.util.CommandContext;
import org.teiid.translator.SourceSystemFunctions;
import org.teiid.translator.TranslatorException;
public class LanguageBridgeFactory {
private final class TupleBufferList extends AbstractList<List<?>> implements RandomAccess {
private final TupleBuffer tb;
private TupleBufferList(TupleBuffer tb) {
this.tb = tb;
if (tb.getRowCount() > Integer.MAX_VALUE) {
throw new AssertionError("TupleBuffer too large for TupleBufferList"); //$NON-NLS-1$
}
}
@Override
public List<?> get(int index) {
if (index < 0 || index >= size()) {
throw new IndexOutOfBoundsException(String.valueOf(index));
}
try {
return tb.getBatch(index+1).getTuple(index+1);
} catch (TeiidComponentException e) {
throw new TeiidRuntimeException(QueryPlugin.Event.TEIID30483, e);
}
}
@Override
public int size() {
return (int)tb.getRowCount();
}
}
private final class TupleSourceIterator implements Iterator<List<?>> {
private final TupleSource ts;
List<?> nextRow;
private TupleSourceIterator(TupleSource ts) {
this.ts = ts;
}
@Override
public boolean hasNext() {
if (nextRow == null) {
try {
nextRow = ts.nextTuple();
} catch (TeiidComponentException e) {
throw new TeiidRuntimeException(QueryPlugin.Event.TEIID30484, e);
} catch (TeiidProcessingException e) {
throw new TeiidRuntimeException(QueryPlugin.Event.TEIID30485, e);
}
}
return nextRow != null;
}
@Override
public List<?> next() {
if (nextRow == null && !hasNext()) {
throw new NoSuchElementException();
}
List<?> result = nextRow;
nextRow = null;
return result;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
private RuntimeMetadataImpl metadataFactory = null;
private int valueIndex = 0;
private List<List<?>> allValues = new LinkedList<List<?>>();
private Map<String, List<? extends List<?>>> dependentSets;
private boolean convertIn;
private boolean supportsConcat2;
private boolean supportFromUnixtime;
private int maxInCriteriaSize;
//state to handle with name exclusion
private IdentityHashMap<Object, GroupSymbol> remappedGroups;
private String excludeWithName;
private CommandContext commandContext;
public LanguageBridgeFactory(QueryMetadataInterface metadata) {
if (metadata != null) {
metadataFactory = new RuntimeMetadataImpl(metadata);
}
}
public LanguageBridgeFactory(RuntimeMetadataImpl metadata) {
this.metadataFactory = metadata;
}
public void setConvertIn(boolean convertIn) {
this.convertIn = convertIn;
}
public void setSupportsConcat2(boolean supportsConcat2) {
this.supportsConcat2 = supportsConcat2;
}
public void setSupportFromUnixtime(boolean supportFromUnixtime) {
this.supportFromUnixtime = supportFromUnixtime ;
}
public void setExcludeWithName(String excludeWithName) {
this.excludeWithName = excludeWithName;
}
public org.teiid.language.Command translate(Command command) {
try {
if (command == null) {
return null;
}
if (command instanceof Query) {
Select result = translate((Query)command);
result.setDependentValues(this.dependentSets);
setProjected(result);
return result;
} else if (command instanceof SetQuery) {
org.teiid.language.SetQuery result = translate((SetQuery)command);
setProjected(result);
return result;
} else if (command instanceof Insert) {
return translate((Insert)command);
} else if (command instanceof Update) {
return translate((Update)command);
} else if (command instanceof Delete) {
return translate((Delete)command);
} else if (command instanceof StoredProcedure) {
return translate((StoredProcedure)command);
} else if (command instanceof BatchedUpdateCommand) {
return translate((BatchedUpdateCommand)command);
}
throw new AssertionError(command.getClass().getName() + " " + command); //$NON-NLS-1$
} finally {
this.allValues.clear();
this.dependentSets = null;
this.valueIndex = 0;
}
}
private void setProjected(QueryExpression qe) {
if (qe instanceof Select) {
Select select = (Select)qe;
for (DerivedColumn dc : select.getDerivedColumns()) {
dc.setProjected(true);
}
} else {
org.teiid.language.SetQuery sq = (org.teiid.language.SetQuery)qe;
setProjected(sq.getLeftQuery());
setProjected(sq.getRightQuery());
}
}
QueryExpression translate(QueryCommand command) {
if (command instanceof Query) {
return translate((Query)command);
}
return translate((SetQuery)command);
}
org.teiid.language.SetQuery translate(SetQuery union) {
org.teiid.language.SetQuery result = new org.teiid.language.SetQuery();
result.setWith(translate(union.getWith()));
result.setAll(union.isAll());
switch (union.getOperation()) {
case UNION:
result.setOperation(org.teiid.language.SetQuery.Operation.UNION);
break;
case INTERSECT:
result.setOperation(org.teiid.language.SetQuery.Operation.INTERSECT);
break;
case EXCEPT:
result.setOperation(org.teiid.language.SetQuery.Operation.EXCEPT);
break;
}
result.setLeftQuery(translate(union.getLeftQuery()));
result.setRightQuery(translate(union.getRightQuery()));
result.setOrderBy(translate(union.getOrderBy(), true));
result.setLimit(translate(union.getLimit()));
return result;
}
/* Query */
Select translate(Query query) {
With with = translate(query.getWith());
List<Expression> symbols = query.getSelect().getSymbols();
List<DerivedColumn> translatedSymbols = new ArrayList<DerivedColumn>(symbols.size());
for (Iterator<Expression> i = symbols.iterator(); i.hasNext();) {
Expression symbol = i.next();
String alias = null;
if(symbol instanceof AliasSymbol) {
alias = ((AliasSymbol)symbol).getOutputName();
symbol = ((AliasSymbol)symbol).getSymbol();
}
org.teiid.language.Expression iExp = translate(symbol);
DerivedColumn selectSymbol = new DerivedColumn(alias, iExp);
translatedSymbols.add(selectSymbol);
}
List<TableReference> items = null;
if (query.getFrom() != null) {
List<FromClause> clauses = query.getFrom().getClauses();
items = new ArrayList<TableReference>(clauses.size());
for (Iterator<FromClause> i = clauses.iterator(); i.hasNext();) {
items.add(translate(i.next()));
}
}
Select q = new Select(translatedSymbols, query
.getSelect().isDistinct(), items,
translate(query.getCriteria()), translate(query.getGroupBy()),
translate(query.getHaving()), translate(query.getOrderBy(), false));
q.setLimit(translate(query.getLimit()));
q.setWith(with);
return q;
}
public With translate(List<WithQueryCommand> with) {
if (with == null || with.isEmpty()) {
return null;
}
With result = new With();
ArrayList<WithItem> items = new ArrayList<WithItem>(with.size());
for (WithQueryCommand withQueryCommand : with) {
WithItem item = new WithItem();
GroupSymbol group = withQueryCommand.getGroupSymbol();
if (withQueryCommand.getCommand() != null && excludeWithName != null && excludeWithName.equalsIgnoreCase(group.getName())) {
group = RulePlaceAccess.recontextSymbol(withQueryCommand.getGroupSymbol(), commandContext.getGroups());
group.setDefinition(null);
if (remappedGroups == null) {
remappedGroups = new IdentityHashMap<Object, GroupSymbol>();
}
this.remappedGroups.put(group.getMetadataID(), group);
}
item.setTable(translate(group));
if (withQueryCommand.getColumns() != null) {
List<ColumnReference> translatedElements = new ArrayList<ColumnReference>(withQueryCommand.getColumns().size());
for (ElementSymbol es: withQueryCommand.getColumns()) {
ColumnReference cr = translate(es);
translatedElements.add(cr);
if (withQueryCommand.getCommand() == null) {
//we want to convey the metadata to the source layer if possible
Object mid = es.getMetadataID();
if (mid instanceof TempMetadataID) {
TempMetadataID tid = (TempMetadataID)mid;
mid = tid.getOriginalMetadataID();
}
if (mid instanceof Column) {
cr.setMetadataObject((Column)mid);
}
}
}
item.setColumns(translatedElements);
}
if (withQueryCommand.getCommand() != null) {
item.setSubquery(translate(withQueryCommand.getCommand()));
} else {
item.setDependentValues(new TupleBufferList(withQueryCommand.getTupleBuffer()));
}
item.setRecusive(withQueryCommand.isRecursive());
items.add(item);
}
result.setItems(items);
return result;
}
public TableReference translate(FromClause clause) {
if (clause == null) {
return null;
}
if (clause instanceof JoinPredicate) {
return translate((JoinPredicate)clause);
} else if (clause instanceof SubqueryFromClause) {
return translate((SubqueryFromClause)clause);
} else if (clause instanceof UnaryFromClause) {
return translate((UnaryFromClause)clause);
}
throw new AssertionError(clause.getClass().getName() + " " + clause); //$NON-NLS-1$
}
Join translate(JoinPredicate join) {
List crits = join.getJoinCriteria();
Criteria crit = null;
if (crits.size() == 1) {
crit = (Criteria)crits.get(0);
} else if (crits.size() > 1) {
crit = new CompoundCriteria(crits);
}
Join.JoinType joinType = Join.JoinType.INNER_JOIN;
if(join.getJoinType().equals(JoinType.JOIN_INNER)) {
joinType = Join.JoinType.INNER_JOIN;
} else if(join.getJoinType().equals(JoinType.JOIN_LEFT_OUTER)) {
joinType = Join.JoinType.LEFT_OUTER_JOIN;
} else if(join.getJoinType().equals(JoinType.JOIN_RIGHT_OUTER)) {
joinType = Join.JoinType.RIGHT_OUTER_JOIN;
} else if(join.getJoinType().equals(JoinType.JOIN_FULL_OUTER)) {
joinType = Join.JoinType.FULL_OUTER_JOIN;
} else if(join.getJoinType().equals(JoinType.JOIN_CROSS)) {
joinType = Join.JoinType.CROSS_JOIN;
}
return new Join(translate(join.getLeftClause()),
translate(join.getRightClause()),
joinType,
translate(crit));
}
TableReference translate(SubqueryFromClause clause) {
if (clause.getCommand() instanceof StoredProcedure) {
NamedProcedureCall result = new NamedProcedureCall(translate((StoredProcedure)clause.getCommand()), clause.getOutputName());
result.setLateral(clause.isLateral());
result.getCall().setTableReference(true);
return result;
}
DerivedTable result = new DerivedTable(translate((QueryCommand)clause.getCommand()), clause.getOutputName());
result.setLateral(clause.isLateral());
return result;
}
NamedTable translate(UnaryFromClause clause) {
return translate(clause.getGroup());
}
public Condition translate(Criteria criteria) {
if (criteria == null) {
return null;
}
if (criteria instanceof CompareCriteria) {
return translate((CompareCriteria)criteria);
} else if (criteria instanceof CompoundCriteria) {
return translate((CompoundCriteria)criteria);
} else if (criteria instanceof ExistsCriteria) {
return translate((ExistsCriteria)criteria);
} else if (criteria instanceof IsNullCriteria) {
return translate((IsNullCriteria)criteria);
}else if (criteria instanceof MatchCriteria) {
return translate((MatchCriteria)criteria);
} else if (criteria instanceof NotCriteria) {
return translate((NotCriteria)criteria);
} else if (criteria instanceof SetCriteria) {
return translate((SetCriteria)criteria);
} else if (criteria instanceof SubqueryCompareCriteria) {
return translate((SubqueryCompareCriteria)criteria);
} else if (criteria instanceof SubquerySetCriteria) {
return translate((SubquerySetCriteria)criteria);
} else if (criteria instanceof DependentSetCriteria) {
return translate((DependentSetCriteria)criteria);
}
throw new AssertionError(criteria.getClass().getName() + " " + criteria); //$NON-NLS-1$
}
org.teiid.language.Comparison translate(DependentSetCriteria criteria) {
Operator operator = Operator.EQ;
org.teiid.language.Expression arg = null;
final TupleBuffer tb = criteria.getDependentValueSource().getTupleBuffer();
if (criteria.getValueExpression() instanceof Array) {
Array array = (Array)criteria.getValueExpression();
List<org.teiid.language.Expression> params = new ArrayList<org.teiid.language.Expression>();
Class<?> baseType = null;
for (Expression ex : array.getExpressions()) {
if (baseType == null) {
baseType = ex.getType();
} else if (!baseType.equals(ex.getType())) {
baseType = DataTypeManager.DefaultDataClasses.OBJECT;
}
params.add(createParameter(criteria, tb, ex));
}
arg = new org.teiid.language.Array(baseType, params);
} else {
Expression ex = criteria.getValueExpression();
arg = createParameter(criteria, tb, ex);
}
if (this.dependentSets == null) {
this.dependentSets = new HashMap<String, List<? extends List<?>>>();
}
this.dependentSets.put(criteria.getContextSymbol(), new TupleBufferList(tb));
Comparison result = new org.teiid.language.Comparison(translate(criteria.getExpression()),
arg, operator);
return result;
}
private Parameter createParameter(DependentSetCriteria criteria,
final TupleBuffer tb, Expression ex) {
Parameter p = new Parameter();
p.setType(ex.getType());
p.setValueIndex(tb.getSchema().indexOf(ex));
p.setDependentValueId(criteria.getContextSymbol());
return p;
}
org.teiid.language.Comparison translate(CompareCriteria criteria) {
Operator operator = Operator.EQ;
switch(criteria.getOperator()) {
case CompareCriteria.EQ:
operator = Operator.EQ;
break;
case CompareCriteria.NE:
operator = Operator.NE;
break;
case CompareCriteria.LT:
operator = Operator.LT;
break;
case CompareCriteria.LE:
operator = Operator.LE;
break;
case CompareCriteria.GT:
operator = Operator.GT;
break;
case CompareCriteria.GE:
operator = Operator.GE;
break;
}
return new org.teiid.language.Comparison(translate(criteria.getLeftExpression()),
translate(criteria.getRightExpression()), operator);
}
AndOr translate(CompoundCriteria criteria) {
List nestedCriteria = criteria.getCriteria();
int size = nestedCriteria.size();
AndOr.Operator op = criteria.getOperator() == CompoundCriteria.AND?AndOr.Operator.AND:AndOr.Operator.OR;
AndOr result = new AndOr(translate((Criteria)nestedCriteria.get(size - 2)), translate((Criteria)nestedCriteria.get(size - 1)), op);
for (int i = nestedCriteria.size() - 3; i >= 0; i--) {
result = new AndOr(translate((Criteria)nestedCriteria.get(i)), result, op);
}
return result;
}
Condition translate(ExistsCriteria criteria) {
Exists exists = new Exists(translate(criteria.getCommand()));
if (criteria.isNegated()) {
return new Not(exists);
}
return exists;
}
IsNull translate(IsNullCriteria criteria) {
return new IsNull(translate(criteria.getExpression()), criteria.isNegated());
}
Like translate(MatchCriteria criteria) {
Character escapeChar = null;
if(criteria.getEscapeChar() != MatchCriteria.NULL_ESCAPE_CHAR) {
escapeChar = new Character(criteria.getEscapeChar());
}
Like like = new Like(translate(criteria.getLeftExpression()),
translate(criteria.getRightExpression()),
escapeChar,
criteria.isNegated());
like.setMode(criteria.getMode());
return like;
}
Condition translate(SetCriteria criteria) {
Collection expressions = criteria.getValues();
List<org.teiid.language.Expression> translatedExpressions = translateExpressionList(expressions);
org.teiid.language.Expression expr = translate(criteria.getExpression());
if (convertIn) {
Condition condition = null;
for (org.teiid.language.Expression expression : translatedExpressions) {
if (condition == null) {
condition = new Comparison(expr, expression, criteria.isNegated()?Operator.NE:Operator.EQ);
} else {
condition = new AndOr(new Comparison(expr, expression, criteria.isNegated()?Operator.NE:Operator.EQ), condition, criteria.isNegated()?AndOr.Operator.AND:AndOr.Operator.OR);
}
}
return condition;
}
if (maxInCriteriaSize > 0 && translatedExpressions.size() > maxInCriteriaSize) {
Condition condition = null;
int count = translatedExpressions.size()/maxInCriteriaSize + ((translatedExpressions.size()%maxInCriteriaSize!=0)?1:0);
for (int i = 0; i < count; i++) {
List<org.teiid.language.Expression> subList = translatedExpressions.subList(maxInCriteriaSize*i, Math.min(translatedExpressions.size(), maxInCriteriaSize*(i+1)));
List<org.teiid.language.Expression> translatedExpressionsSubList = new ArrayList<org.teiid.language.Expression>(subList);
if (condition == null) {
condition = new In(expr, translatedExpressionsSubList, criteria.isNegated());
} else {
condition = new AndOr(condition, new In(expr, translatedExpressionsSubList, criteria.isNegated()), criteria.isNegated()?AndOr.Operator.AND:AndOr.Operator.OR);
}
}
return condition;
}
return new In(expr,
translatedExpressions,
criteria.isNegated());
}
SubqueryComparison translate(SubqueryCompareCriteria criteria) {
Quantifier quantifier = Quantifier.ALL;
switch(criteria.getPredicateQuantifier()) {
case SubqueryCompareCriteria.ALL:
quantifier = Quantifier.ALL;
break;
case SubqueryCompareCriteria.ANY:
quantifier = Quantifier.SOME;
break;
case SubqueryCompareCriteria.SOME:
quantifier = Quantifier.SOME;
break;
}
Operator operator = Operator.EQ;
switch(criteria.getOperator()) {
case SubqueryCompareCriteria.EQ:
operator = Operator.EQ;
break;
case SubqueryCompareCriteria.NE:
operator = Operator.NE;
break;
case SubqueryCompareCriteria.LT:
operator = Operator.LT;
break;
case SubqueryCompareCriteria.LE:
operator = Operator.LE;
break;
case SubqueryCompareCriteria.GT:
operator = Operator.GT;
break;
case SubqueryCompareCriteria.GE:
operator = Operator.GE;
break;
}
return new SubqueryComparison(translate(criteria.getLeftExpression()),
operator,
quantifier,
translate(criteria.getCommand()));
}
SubqueryIn translate(SubquerySetCriteria criteria) {
return new SubqueryIn(translate(criteria.getExpression()),
criteria.isNegated(),
translate(criteria.getCommand()));
}
Not translate(NotCriteria criteria) {
return new Not(translate(criteria.getCriteria()));
}
public org.teiid.language.GroupBy translate(GroupBy groupBy) {
if(groupBy == null){
return null;
}
List items = groupBy.getSymbols();
List<org.teiid.language.Expression> translatedItems = new ArrayList<org.teiid.language.Expression>();
for (Iterator i = items.iterator(); i.hasNext();) {
translatedItems.add(translate((Expression)i.next()));
}
org.teiid.language.GroupBy result = new org.teiid.language.GroupBy(translatedItems);
result.setRollup(groupBy.isRollup());
return result;
}
public org.teiid.language.OrderBy translate(OrderBy orderBy, boolean set) {
if(orderBy == null){
return null;
}
List<OrderByItem> items = orderBy.getOrderByItems();
List<SortSpecification> translatedItems = new ArrayList<SortSpecification>();
for (int i = 0; i < items.size(); i++) {
Expression symbol = items.get(i).getSymbol();
Ordering direction = items.get(i).isAscending() ? Ordering.ASC: Ordering.DESC;
SortSpecification orderByItem = null;
if(!set && (items.get(i).isUnrelated() || symbol instanceof ElementSymbol)){
orderByItem = new SortSpecification(direction, translate(symbol));
} else {
orderByItem = new SortSpecification(direction, new ColumnReference(null, Symbol.getShortName(((Symbol)symbol).getOutputName()), null, symbol.getType()));
}
orderByItem.setNullOrdering(items.get(i).getNullOrdering());
translatedItems.add(orderByItem);
}
return new org.teiid.language.OrderBy(translatedItems);
}
/* Expressions */
public org.teiid.language.Expression translate(Expression expr) {
if (expr == null) {
return null;
}
if (expr instanceof Constant) {
return translate((Constant)expr);
} else if (expr instanceof AggregateSymbol) {
return translate((AggregateSymbol)expr);
} else if (expr instanceof Function) {
return translate((Function)expr);
} else if (expr instanceof ScalarSubquery) {
return translate((ScalarSubquery)expr);
} else if (expr instanceof SearchedCaseExpression) {
return translate((SearchedCaseExpression)expr);
} else if (expr instanceof ElementSymbol) {
return translate((ElementSymbol)expr);
} else if (expr instanceof ExpressionSymbol) {
return translate((ExpressionSymbol)expr);
} else if (expr instanceof Criteria) {
Condition c = translate((Criteria)expr);
c.setExpression(true);
return c;
} else if (expr instanceof WindowFunction) {
return translate((WindowFunction)expr);
} else if (expr instanceof Array) {
return translate((Array)expr);
}
throw new AssertionError(expr.getClass().getName() + " " + expr); //$NON-NLS-1$
}
org.teiid.language.Array translate(Array array) {
return new org.teiid.language.Array(array.getComponentType(), translateExpressionList(array.getExpressions()));
}
org.teiid.language.WindowFunction translate(WindowFunction windowFunction) {
org.teiid.language.WindowFunction result = new org.teiid.language.WindowFunction();
result.setFunction(translate(windowFunction.getFunction()));
WindowSpecification ws = new WindowSpecification();
ws.setOrderBy(translate(windowFunction.getWindowSpecification().getOrderBy(), false));
List<Expression> partition = windowFunction.getWindowSpecification().getPartition();
if (partition != null) {
ArrayList<org.teiid.language.Expression> partitionList = translateExpressionList(partition);
ws.setPartition(partitionList);
}
result.setWindowSpecification(ws);
return result;
}
private ArrayList<org.teiid.language.Expression> translateExpressionList(
Collection<? extends Expression> list) {
ArrayList<org.teiid.language.Expression> result = new ArrayList<org.teiid.language.Expression>(list.size());
for (Expression ex : list) {
result.add(translate(ex));
}
return result;
}
org.teiid.language.Expression translate(Constant constant) {
if (constant.isMultiValued()) {
Parameter result = new Parameter();
result.setType(constant.getType());
final List<?> values = (List<?>)constant.getValue();
allValues.add(values);
result.setValueIndex(valueIndex++);
return result;
}
if (constant.getValue() instanceof ArrayImpl) {
//TODO: we could check if there is a common base type (also needs to be in the dependent logic)
// and expand binding options in the translators
//we currently support the notion of a mixed type array, since we consider object a common base type
//that will not work for all sources, so instead of treating this as a single array (as commented out below),
//we just turn it into an array of parameters
//Literal result = new Literal(av.getValues(), org.teiid.language.Array.class);
//result.setBindEligible(constant.isBindEligible());
//return result;
ArrayImpl av = (ArrayImpl)constant.getValue();
List<Constant> vals = new ArrayList<Constant>();
Class<?> baseType = null;
for (Object o : av.getValues()) {
Constant c = new Constant(o);
c.setBindEligible(constant.isBindEligible());
vals.add(c);
if (baseType == null) {
baseType = c.getType();
} else if (!baseType.equals(c.getType())) {
baseType = DataTypeManager.DefaultDataClasses.OBJECT;
}
}
return new org.teiid.language.Array(baseType, translateExpressionList(vals));
}
Literal result = new Literal(constant.getValue(), constant.getType());
result.setBindEligible(constant.isBindEligible());
return result;
}
org.teiid.language.Expression translate(Function function) {
Expression [] args = function.getArgs();
List<org.teiid.language.Expression> params = new ArrayList<org.teiid.language.Expression>(args.length);
for (int i = 0; i < args.length; i++) {
params.add(translate(args[i]));
}
String name = function.getName();
if (function.getFunctionDescriptor() != null) {
name = function.getFunctionDescriptor().getName();
if (!supportsConcat2 && function.getFunctionDescriptor().getMethod().getParent() == null && name.equalsIgnoreCase(SourceSystemFunctions.CONCAT2)) {
Expression[] newArgs = new Expression[args.length];
boolean useCase = true;
for(int i=0; i<args.length; i++) {
if (args[i] instanceof Constant) {
newArgs[i] = args[i];
useCase = false;
} else {
Function f = new Function(SourceSystemFunctions.IFNULL, new Expression[] {args[i], new Constant("")}); //$NON-NLS-1$
newArgs[i] = f;
f.setType(args[i].getType());
FunctionDescriptor descriptor =
metadataFactory.getMetadata().getFunctionLibrary().findFunction(SourceSystemFunctions.IFNULL, new Class[] { args[i].getType(), DataTypeManager.DefaultDataClasses.STRING });
f.setFunctionDescriptor(descriptor);
}
}
Function concat = new Function(SourceSystemFunctions.CONCAT, newArgs);
concat.setType(DataTypeManager.DefaultDataClasses.STRING);
if (!useCase) {
return translate(concat);
}
FunctionDescriptor descriptor =
metadataFactory.getMetadata().getFunctionLibrary().findFunction(SourceSystemFunctions.CONCAT, new Class[] { DataTypeManager.DefaultDataClasses.STRING, DataTypeManager.DefaultDataClasses.STRING });
concat.setFunctionDescriptor(descriptor);
List<CompoundCriteria> when = Arrays.asList(new CompoundCriteria(CompoundCriteria.AND, new IsNullCriteria(args[0]), new IsNullCriteria(args[1])));
Constant nullConstant = new Constant(null, DataTypeManager.DefaultDataClasses.STRING);
List<Constant> then = Arrays.asList(nullConstant);
SearchedCaseExpression caseExpr = new SearchedCaseExpression(when, then);
caseExpr.setElseExpression(concat);
caseExpr.setType(DataTypeManager.DefaultDataClasses.STRING);
return translate(caseExpr);
} else if(!supportFromUnixtime && function.getFunctionDescriptor().getMethod().getParent() == null && name.equalsIgnoreCase(SourceSystemFunctions.FROM_UNIXTIME)) {
// from_unixtime(a) => timestampadd(SQL_TSI_SECOND, a, new Timestamp(0))
Function result = new Function(FunctionLibrary.TIMESTAMPADD, new Expression[] {new Constant(NonReserved.SQL_TSI_SECOND), function.getArg(0), new Constant(new Timestamp(0)) });
// resolve the function
FunctionDescriptor descriptor =
metadataFactory.getMetadata().getFunctionLibrary().findFunction(FunctionLibrary.TIMESTAMPADD, new Class[] { DataTypeManager.DefaultDataClasses.STRING, DataTypeManager.DefaultDataClasses.INTEGER, DataTypeManager.DefaultDataClasses.TIMESTAMP });
result.setFunctionDescriptor(descriptor);
result.setType(DataTypeManager.DefaultDataClasses.TIMESTAMP);
return translate(result);
}
//check for translator pushdown functions, and use the name in source if possible
if (function.getFunctionDescriptor().getMethod().getNameInSource() != null &&
(CoreConstants.SYSTEM_MODEL.equals(function.getFunctionDescriptor().getSchema())
|| (function.getFunctionDescriptor().getMethod().getParent() != null && function.getFunctionDescriptor().getMethod().getParent().isPhysical())) ) {
name = function.getFunctionDescriptor().getMethod().getNameInSource();
}
} else {
name = Symbol.getShortName(name);
}
//if there is any ambiguity in the function name it will be up to the translator logic to check the
//metadata
org.teiid.language.Function result = new org.teiid.language.Function(name, params, function.getType());
if (function.getFunctionDescriptor() != null) {
result.setMetadataObject(function.getFunctionDescriptor().getMethod());
}
return result;
}
SearchedCase translate(SearchedCaseExpression expr) {
ArrayList<SearchedWhenClause> whens = new ArrayList<SearchedWhenClause>();
for (int i = 0; i < expr.getWhenCount(); i++) {
whens.add(new SearchedWhenClause(translate(expr.getWhenCriteria(i)), translate(expr.getThenExpression(i))));
}
return new SearchedCase(whens,
translate(expr.getElseExpression()),
expr.getType());
}
org.teiid.language.Expression translate(ScalarSubquery ss) {
return new org.teiid.language.ScalarSubquery(translate(ss.getCommand()));
}
org.teiid.language.Expression translate(AliasSymbol symbol) {
return translate(symbol.getSymbol());
}
ColumnReference translate(ElementSymbol symbol) {
ColumnReference element = new ColumnReference(translate(symbol.getGroupSymbol()), Symbol.getShortName(symbol.getOutputName()), null, symbol.getType());
if (element.getTable().getMetadataObject() == null) {
//handle procedure resultset columns
if (symbol.getMetadataID() instanceof TempMetadataID) {
TempMetadataID tid = (TempMetadataID)symbol.getMetadataID();
if (tid.getOriginalMetadataID() instanceof Column && !(((Column)tid.getOriginalMetadataID()).getParent() instanceof Table)) {
element.setMetadataObject(metadataFactory.getElement(tid.getOriginalMetadataID()));
}
}
return element;
}
Object mid = symbol.getMetadataID();
element.setMetadataObject(metadataFactory.getElement(mid));
return element;
}
AggregateFunction translate(AggregateSymbol symbol) {
List<org.teiid.language.Expression> params = new ArrayList<org.teiid.language.Expression>(symbol.getArgs().length);
for (Expression expression : symbol.getArgs()) {
params.add(translate(expression));
}
String name = symbol.getAggregateFunction().name();
if (symbol.getAggregateFunction() == AggregateSymbol.Type.USER_DEFINED) {
name = symbol.getName();
}
AggregateFunction af = new AggregateFunction(name,
symbol.isDistinct(),
params,
symbol.getType());
af.setCondition(translate(symbol.getCondition()));
af.setOrderBy(translate(symbol.getOrderBy(), false));
return af;
}
org.teiid.language.Expression translate(ExpressionSymbol symbol) {
return translate(symbol.getExpression());
}
/* Insert */
org.teiid.language.Insert translate(Insert insert) {
List<ElementSymbol> elements = insert.getVariables();
List<ColumnReference> translatedElements = new ArrayList<ColumnReference>();
for (ElementSymbol elementSymbol : elements) {
translatedElements.add(translate(elementSymbol));
}
Iterator<List<?>> parameterValues = null;
InsertValueSource valueSource = null;
if (insert.getQueryExpression() != null) {
valueSource = translate(insert.getQueryExpression());
} else if (insert.getTupleSource() != null) {
final TupleSource ts = insert.getTupleSource();
parameterValues = new TupleSourceIterator(ts);
List<org.teiid.language.Expression> translatedValues = new ArrayList<org.teiid.language.Expression>();
for (int i = 0; i < insert.getVariables().size(); i++) {
ElementSymbol es = insert.getVariables().get(i);
Parameter param = new Parameter();
param.setType(es.getType());
param.setValueIndex(i);
translatedValues.add(param);
}
valueSource = new ExpressionValueSource(translatedValues);
} else {
// This is for the simple one row insert.
List values = insert.getValues();
List<org.teiid.language.Expression> translatedValues = new ArrayList<org.teiid.language.Expression>();
for (Iterator i = values.iterator(); i.hasNext();) {
translatedValues.add(translate((Expression)i.next()));
}
valueSource = new ExpressionValueSource(translatedValues);
}
org.teiid.language.Insert result = new org.teiid.language.Insert(translate(insert.getGroup()),
translatedElements,
valueSource);
result.setParameterValues(parameterValues);
setBatchValues(result);
result.setUpsert(insert.isUpsert());
return result;
}
private void setBatchValues(BatchedCommand bc) {
if (valueIndex == 0) {
return;
}
if (bc.getParameterValues() != null) {
throw new IllegalStateException("Already set batch values"); //$NON-NLS-1$
}
int rowCount = allValues.get(0).size();
List<List<?>> result = new ArrayList<List<?>>(rowCount);
for (int i = 0; i < rowCount; i++) {
List<Object> row = new ArrayList<Object>(allValues.size());
for (List<?> vals : allValues) {
row.add(vals.get(i));
}
result.add(row);
}
bc.setParameterValues(result.iterator());
}
/* Update */
org.teiid.language.Update translate(Update update) {
org.teiid.language.Update result = new org.teiid.language.Update(translate(update.getGroup()),
translate(update.getChangeList()),
translate(update.getCriteria()));
setBatchValues(result);
return result;
}
List<org.teiid.language.SetClause> translate(SetClauseList setClauseList) {
List<org.teiid.language.SetClause> clauses = new ArrayList<org.teiid.language.SetClause>(setClauseList.getClauses().size());
for (SetClause setClause : setClauseList.getClauses()) {
clauses.add(translate(setClause));
}
return clauses;
}
org.teiid.language.SetClause translate(SetClause setClause) {
return new org.teiid.language.SetClause(translate(setClause.getSymbol()), translate(setClause.getValue()));
}
/* Delete */
org.teiid.language.Delete translate(Delete delete) {
org.teiid.language.Delete deleteImpl = new org.teiid.language.Delete(translate(delete.getGroup()),
translate(delete.getCriteria()));
setBatchValues(deleteImpl);
return deleteImpl;
}
/* Execute */
Call translate(StoredProcedure sp) {
Procedure proc = null;
if(sp.getProcedureID() != null) {
try {
proc = this.metadataFactory.getProcedure(sp.getGroup().getName());
} catch (TranslatorException e) {
throw new TeiidRuntimeException(QueryPlugin.Event.TEIID30486, e);
}
}
Class<?> returnType = null;
List<Argument> translatedParameters = new ArrayList<Argument>();
for (SPParameter param : sp.getParameters()) {
Direction direction = Direction.IN;
switch(param.getParameterType()) {
case ParameterInfo.IN:
direction = Direction.IN;
break;
case ParameterInfo.INOUT:
direction = Direction.INOUT;
break;
case ParameterInfo.OUT:
direction = Direction.OUT;
break;
case ParameterInfo.RESULT_SET:
continue; //already part of the metadata
case ParameterInfo.RETURN_VALUE:
returnType = param.getClassType();
continue;
}
if (param.isUsingDefault() && "omit".equalsIgnoreCase(metadataFactory.getMetadata().getExtensionProperty(param.getMetadataID(), BaseColumn.DEFAULT_HANDLING, false))) {
continue;
}
ProcedureParameter metadataParam = metadataFactory.getParameter(param);
//we can assume for now that all arguments will be literals, which may be multivalued
org.teiid.language.Expression value = null;
if (direction != Direction.OUT) {
if (param.isVarArg()) {
ArrayImpl av = (ArrayImpl) ((Constant)param.getExpression()).getValue();
if (av != null) {
for (Object obj : av.getValues()) {
Argument arg = new Argument(direction, new Literal(obj, param.getClassType().getComponentType()), param.getClassType().getComponentType(), metadataParam);
translatedParameters.add(arg);
}
}
break;
}
value = translate(param.getExpression());
}
Argument arg = new Argument(direction, value, param.getClassType(), metadataParam);
translatedParameters.add(arg);
}
Call call = new Call(removeSchemaName(sp.getProcedureName()), translatedParameters, proc);
call.setReturnType(returnType);
return call;
}
public NamedTable translate(GroupSymbol symbol) {
String alias = null;
String fullGroup = symbol.getOutputName();
if(symbol.getOutputDefinition() != null) {
alias = symbol.getOutputName();
fullGroup = symbol.getOutputDefinition();
if (remappedGroups != null) {
GroupSymbol remappedGroup = remappedGroups.get(symbol.getMetadataID());
if (remappedGroup != null && remappedGroup != symbol) {
fullGroup = remappedGroup.getName();
}
}
}
fullGroup = removeSchemaName(fullGroup);
NamedTable group = new NamedTable(fullGroup, alias, null);
try {
group.setMetadataObject(metadataFactory.getGroup(symbol.getMetadataID()));
} catch (QueryMetadataException e) {
throw new TeiidRuntimeException(QueryPlugin.Event.TEIID30487, e);
} catch (TeiidComponentException e) {
throw new TeiidRuntimeException(QueryPlugin.Event.TEIID30488, e);
}
return group;
}
private String removeSchemaName(String fullGroup) {
//remove the model name
int index = fullGroup.indexOf(Symbol.SEPARATOR);
if (index > 0) {
fullGroup = fullGroup.substring(index + 1);
}
return fullGroup;
}
/* Batched Updates */
BatchedUpdates translate(BatchedUpdateCommand command) {
List<Command> updates = command.getUpdateCommands();
List<org.teiid.language.Command> translatedUpdates = new ArrayList<org.teiid.language.Command>(updates.size());
for (Iterator<Command> i = updates.iterator(); i.hasNext();) {
translatedUpdates.add(translate(i.next()));
}
BatchedUpdates batchedUpdates = new BatchedUpdates(translatedUpdates);
batchedUpdates.setSingleResult(command.isSingleResult());
return batchedUpdates;
}
org.teiid.language.Limit translate(Limit limit) {
if (limit == null) {
return null;
}
int rowOffset = 0;
if (limit.getOffset() != null) {
Literal c1 = (Literal)translate(limit.getOffset());
rowOffset = ((Integer)c1.getValue()).intValue();
}
Literal c2 = (Literal)translate(limit.getRowLimit());
int rowLimit = Integer.MAX_VALUE;
if (c2 != null) {
rowLimit = ((Integer)c2.getValue()).intValue();
}
return new org.teiid.language.Limit(rowOffset, rowLimit);
}
public void setMaxInPredicateSize(int maxInCriteriaSize) {
this.maxInCriteriaSize = maxInCriteriaSize;
}
public void setCommandContext(CommandContext commandContext) {
this.commandContext = commandContext;
}
}