/*
* 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.olingo.service;
import static org.teiid.language.SQLConstants.Reserved.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Stack;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.core.edm.primitivetype.SingletonPrimitiveType;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.uri.*;
import org.apache.olingo.server.api.uri.queryoption.expression.*;
import org.apache.olingo.server.core.RequestURLHierarchyVisitor;
import org.teiid.core.TeiidException;
import org.teiid.core.TeiidRuntimeException;
import org.teiid.core.types.DataTypeManager;
import org.teiid.core.types.JDBCSQLTypeInfo;
import org.teiid.core.util.Assertion;
import org.teiid.metadata.Column;
import org.teiid.metadata.ForeignKey;
import org.teiid.metadata.MetadataStore;
import org.teiid.odata.api.SQLParameter;
import org.teiid.olingo.ODataExpressionVisitor;
import org.teiid.olingo.ODataPlugin;
import org.teiid.olingo.ProjectedColumn;
import org.teiid.olingo.common.ODataTypeManager;
import org.teiid.olingo.service.ODataSQLBuilder.URLParseService;
import org.teiid.olingo.service.TeiidServiceHandler.UniqueNameGenerator;
import org.teiid.query.sql.lang.*;
import org.teiid.query.sql.symbol.AggregateSymbol;
import org.teiid.query.sql.symbol.AliasSymbol;
import org.teiid.query.sql.symbol.CaseExpression;
import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Function;
import org.teiid.query.sql.symbol.GroupSymbol;
import org.teiid.query.sql.symbol.Reference;
import org.teiid.query.sql.symbol.ScalarSubquery;
import org.teiid.translator.SourceSystemFunctions;
public class ODataExpressionToSQLVisitor extends RequestURLHierarchyVisitor implements ODataExpressionVisitor{
private final Stack<org.teiid.query.sql.symbol.Expression> stack = new Stack<org.teiid.query.sql.symbol.Expression>();
private List<SQLParameter> params;
private boolean prepared = false;
private final UriInfo uriInfo;
private MetadataStore metadata;
private DocumentNode ctxQuery;
private DocumentNode ctxExpression;
private DocumentNode ctxLambda;
private UniqueNameGenerator nameGenerator;
private URLParseService parseService;
private String lastPropertyType;
private OData odata;
private boolean root;
public ODataExpressionToSQLVisitor(DocumentNode resource,
boolean prepared, UriInfo info, MetadataStore metadata, OData odata,
UniqueNameGenerator nameGenerator,
List<SQLParameter> params, URLParseService parseService) {
this.ctxQuery = resource;
this.prepared = prepared;
this.uriInfo = info;
this.metadata = metadata;
this.nameGenerator = nameGenerator;
this.params = params;
this.parseService = parseService;
this.ctxExpression = this.ctxQuery;
this.odata = odata;
}
public org.teiid.query.sql.symbol.Expression getExpression(Expression expr) throws TeiidException {
try {
accept(expr);
} catch (TeiidRuntimeException e) {
if (e.getCause() instanceof TeiidException) {
throw (TeiidException)e.getCause();
}
throw e;
}
return this.stack.pop();
}
public org.teiid.query.sql.symbol.Expression getExpression(UriInfoResource info) throws TeiidException {
try {
visit(info);
} catch (TeiidRuntimeException e) {
if (e.getCause() instanceof TeiidException) {
throw (TeiidException)e.getCause();
}
throw e;
}
return this.stack.pop();
}
public DocumentNode getEntityResource() {
return this.ctxQuery;
}
@Override
public void visit(Alias expr) {
String strValue = this.uriInfo.getValueForAlias(expr.getParameterName());
try {
if (strValue == null) {
this.stack.add(new Constant(null));
}
else if (strValue.startsWith("$root")) {
this.stack.add(new ScalarSubquery(this.parseService.parse(strValue)));
}
else {
String type = "Edm.String";
if (this.lastPropertyType != null) {
EdmPrimitiveTypeKind kind = ODataTypeManager.odataType(this.lastPropertyType);
type = kind.getFullQualifiedName().getFullQualifiedNameAsString();
this.lastPropertyType = null;
}
Object value = ODataTypeManager.parseLiteral(type, strValue);
if (this.prepared) {
stack.add(new Reference(this.params.size()));
this.params.add(new SQLParameter(value, JDBCSQLTypeInfo.getSQLTypeFromClass(value.getClass().getName())));
} else {
this.stack.add(new Constant(value));
}
}
} catch (TeiidException e) {
throw new TeiidRuntimeException(e);
}
}
@Override
public void visit(Binary expr) {
accept(expr.getLeftOperand());
org.teiid.query.sql.symbol.Expression lhs = this.stack.pop();
accept(expr.getRightOperand());
org.teiid.query.sql.symbol.Expression rhs = this.stack.pop();
org.teiid.query.sql.symbol.Expression binaryExpr = null;
switch (expr.getOperator()) {
case HAS:
// TODO: not supported. What would be SQL equivalent?
throw new TeiidRuntimeException(new TeiidNotImplementedException(
ODataPlugin.Event.TEIID16036,
ODataPlugin.Util.gs(ODataPlugin.Event.TEIID16036)));
case MUL:
binaryExpr = new Function("*", new org.teiid.query.sql.symbol.Expression[] { lhs, rhs }); //$NON-NLS-1$
break;
case DIV:
binaryExpr = new Function("/", new org.teiid.query.sql.symbol.Expression[] { lhs, rhs }); //$NON-NLS-1$
break;
case MOD:
binaryExpr = new Function("MOD", new org.teiid.query.sql.symbol.Expression[] { lhs, rhs }); //$NON-NLS-1$
break;
case ADD:
binaryExpr = new Function("+", new org.teiid.query.sql.symbol.Expression[] { lhs, rhs }); //$NON-NLS-1$
break;
case SUB:
binaryExpr = new Function("-", new org.teiid.query.sql.symbol.Expression[] { lhs, rhs }); //$NON-NLS-1$
break;
case GT:
binaryExpr = new CompareCriteria(lhs, CompareCriteria.GT, rhs);
break;
case GE:
binaryExpr = new CompareCriteria(lhs, CompareCriteria.GE, rhs);
break;
case LT:
binaryExpr = new CompareCriteria(lhs, CompareCriteria.LT, rhs);
break;
case LE:
binaryExpr = new CompareCriteria(lhs, CompareCriteria.LE, rhs);
break;
case EQ:
if (rhs instanceof Constant && ((Constant) rhs).getType() == DataTypeManager.DefaultDataClasses.NULL) {
binaryExpr = new IsNullCriteria(lhs);
} else {
binaryExpr = new CompareCriteria(lhs, CompareCriteria.EQ, rhs);
}
break;
case NE:
if (rhs instanceof Constant && ((Constant) rhs).getType() == DataTypeManager.DefaultDataClasses.NULL) {
IsNullCriteria crit = new IsNullCriteria(lhs);
crit.setNegated(true);
binaryExpr = crit;
} else {
binaryExpr = new CompareCriteria(lhs, CompareCriteria.NE, rhs);
}
break;
case AND:
binaryExpr = new CompoundCriteria(CompoundCriteria.AND, (Criteria) lhs, (Criteria) rhs);
break;
case OR:
binaryExpr = new CompoundCriteria(CompoundCriteria.OR, (Criteria) lhs, (Criteria) rhs);
break;
}
this.stack.push(binaryExpr);
}
@Override
public void visit(Enumeration expr) {
throw new TeiidRuntimeException(new TeiidException("unsupported option"));//$NON-NLS-1$
}
@Override
public void visit(LambdaRef expr) {
// TODO: any and All implementations
}
@Override
public void visit(Literal expr) {
try {
Object value = null;
if (expr.getText() != null && !expr.getText().equalsIgnoreCase("null")) {
String type = expr.getType().getFullQualifiedName().getFullQualifiedNameAsString();
value = ODataTypeManager.parseLiteral(type, expr.getText());
}
if (this.prepared) {
if (value == null) {
this.stack.add(new Constant(value));
} else {
Function ref = new Function(
CONVERT,
new org.teiid.query.sql.symbol.Expression[] {
new Reference(this.params.size()),
new Constant(DataTypeManager.getDataTypeName(value.getClass())) });
stack.add(ref);
this.params.add(new SQLParameter(value,
JDBCSQLTypeInfo.getSQLTypeFromClass(value.getClass().getName())));
}
} else {
this.stack.add(new Constant(value));
}
} catch (TeiidException e) {
throw new TeiidRuntimeException(e);
}
}
@Override
public void visit(Member expr) {
// this is seg way into RequestURLHierarchyVisitor based parsing
visit(expr.getResourcePath());
}
private org.teiid.query.sql.symbol.Expression addOne(
org.teiid.query.sql.symbol.Expression expr) {
org.teiid.query.sql.symbol.Expression when = new CompareCriteria(expr,
CompareCriteria.LT, new Constant(0));
CaseExpression caseExpr = new CaseExpression(expr, Arrays.asList(when),
Arrays.asList(expr));
caseExpr.setElseExpression(new Function("+",
new org.teiid.query.sql.symbol.Expression[] { expr, new Constant(1) }));
return caseExpr;
}
private org.teiid.query.sql.symbol.Expression minusOne(
org.teiid.query.sql.symbol.Expression expr) {
return new Function("-", new org.teiid.query.sql.symbol.Expression[] {
expr, new Constant(1) });
}
@Override
public void visit(Method expr) {
List<org.teiid.query.sql.symbol.Expression> teiidExprs = new ArrayList<org.teiid.query.sql.symbol.Expression>();
for (Expression exp : expr.getParameters()) {
accept(exp);
teiidExprs.add(this.stack.pop());
}
switch (expr.getMethod()) {
case CONTAINS:
CompareCriteria criteria = new CompareCriteria(new Function("LOCATE",
new org.teiid.query.sql.symbol.Expression[] {
teiidExprs.get(1), teiidExprs.get(0), new Constant(1) }),
CompareCriteria.GE, new Constant(1)); //$NON-NLS-1$
this.stack.push(criteria);
break;
case STARTSWITH:
criteria = new CompareCriteria(new Function("LOCATE",
new org.teiid.query.sql.symbol.Expression[] {
teiidExprs.get(1), teiidExprs.get(0), new Constant(1) }),
CompareCriteria.EQ, new Constant(1)); //$NON-NLS-1$
this.stack.push(criteria);
break;
case ENDSWITH:
criteria = new CompareCriteria(new Function("ENDSWITH",
new org.teiid.query.sql.symbol.Expression[] {teiidExprs.get(1), teiidExprs.get(0) }),
CompareCriteria.EQ, new Constant(Boolean.TRUE));//$NON-NLS-1$
this.stack.push(criteria);
break;
case LENGTH:
this.stack.push(new Function("LENGTH",
new org.teiid.query.sql.symbol.Expression[] { teiidExprs.get(0) })); //$NON-NLS-1$
break;
case INDEXOF:
stack.push(minusOne(new Function("LOCATE", new org.teiid.query.sql.symbol.Expression[]
{ teiidExprs.get(1), teiidExprs.get(0)}))); //$NON-NLS-1$
break;
case SUBSTRING:
org.teiid.query.sql.symbol.Expression[] exprs =
teiidExprs.toArray(new org.teiid.query.sql.symbol.Expression[teiidExprs.size()]);
exprs[1] = addOne(exprs[1]);
this.stack.push(new Function("SUBSTRING", exprs)); //$NON-NLS-1$
break;
case TOLOWER:
this.stack.push(new Function("LCASE",
new org.teiid.query.sql.symbol.Expression[] { teiidExprs.get(0) })); //$NON-NLS-1$
break;
case TOUPPER:
this.stack.push(new Function("UCASE",
new org.teiid.query.sql.symbol.Expression[] { teiidExprs.get(0) })); //$NON-NLS-1$
break;
case TRIM:
this.stack.push(new Function("TRIM",
new org.teiid.query.sql.symbol.Expression[] { new Constant("BOTH"),
new Constant(' '), teiidExprs.get(0) })); //$NON-NLS-1$ //$NON-NLS-2$
break;
case CONCAT:
this.stack.push(new Function("CONCAT2", new org.teiid.query.sql.symbol.Expression[]
{ teiidExprs.get(0), teiidExprs.get(1) })); //$NON-NLS-1$
break;
case YEAR:
this.stack.push(new Function("YEAR", new org.teiid.query.sql.symbol.Expression[]
{ teiidExprs.get(0) })); //$NON-NLS-1$
break;
case MONTH:
this.stack.push(new Function("MONTH", new org.teiid.query.sql.symbol.Expression[]
{ teiidExprs.get(0) })); //$NON-NLS-1$
break;
case DAY:
this.stack.push(new Function("DAYOFMONTH", new org.teiid.query.sql.symbol.Expression[]
{ teiidExprs.get(0) })); //$NON-NLS-1$
break;
case HOUR:
this.stack.push(new Function("HOUR", new org.teiid.query.sql.symbol.Expression[]
{ teiidExprs.get(0) })); //$NON-NLS-1$
break;
case MINUTE:
this.stack.push(new Function("MINUTE", new org.teiid.query.sql.symbol.Expression[]
{ teiidExprs.get(0) })); //$NON-NLS-1$
break;
case SECOND:
this.stack.push(new Function("SECOND", new org.teiid.query.sql.symbol.Expression[]
{ teiidExprs.get(0) })); //$NON-NLS-1$
break;
case NOW:
this.stack.push(new Function("NOW", new org.teiid.query.sql.symbol.Expression[] {})); //$NON-NLS-1$
break;
case ROUND:
stack.push(new Function("ROUND", new org.teiid.query.sql.symbol.Expression[]
{ teiidExprs.get(0), new Constant(0) })); //$NON-NLS-1$
break;
case FLOOR:
this.stack.push(new Function("FLOOR", new org.teiid.query.sql.symbol.Expression[]
{ teiidExprs.get(0) })); //$NON-NLS-1$
break;
case CEILING:
this.stack.push(new Function("CEILING", new org.teiid.query.sql.symbol.Expression[]
{ teiidExprs.get(0) })); //$NON-NLS-1$
break;
case CAST:
this.stack.push(new Function(CONVERT,new org.teiid.query.sql.symbol.Expression[]
{teiidExprs.get(0), teiidExprs.get(1) }));
break;
case DATE:
this.stack.push(new Function(CONVERT,new org.teiid.query.sql.symbol.Expression[]
{teiidExprs.get(0), new Constant(DataTypeManager.DefaultDataTypes.DATE)}));
break;
case TIME:
this.stack.push(new Function(CONVERT,new org.teiid.query.sql.symbol.Expression[]
{teiidExprs.get(0), new Constant(DataTypeManager.DefaultDataTypes.TIME)}));
break;
case FRACTIONALSECONDS:
case TOTALSECONDS:
case TOTALOFFSETMINUTES:
case MINDATETIME:
case MAXDATETIME:
case GEODISTANCE:
case GEOLENGTH:
case GEOINTERSECTS:
case ISOF:
default:
throw new TeiidRuntimeException(new TeiidNotImplementedException(
ODataPlugin.Event.TEIID16027,
ODataPlugin.Util.gs(ODataPlugin.Event.TEIID16027, expr.getMethod())));
}
}
@Override
public void visit(TypeLiteral expr) {
this.stack.push(new Constant(ODataTypeManager.teiidType((SingletonPrimitiveType) expr.getType(), false)));
}
@Override
public void visit(Unary expr) {
accept(expr.getOperand());
org.teiid.query.sql.symbol.Expression teiidExpr = this.stack.pop();
switch (expr.getOperator()) {
case MINUS:
this.stack.push(new Function(SourceSystemFunctions.MULTIPLY_OP,
new org.teiid.query.sql.symbol.Expression[] {new Constant(-1), teiidExpr }));
break;
case NOT:
this.stack.push(new NotCriteria(new ExpressionCriteria(teiidExpr)));
break;
}
}
private void accept(Expression expr) {
if (expr instanceof Alias) {
visit((Alias) expr);
} else if (expr instanceof Binary) {
visit((Binary) expr);
} else if (expr instanceof Enumeration) {
visit((Enumeration) expr);
} else if (expr instanceof LambdaRef) {
visit((LambdaRef) expr);
} else if (expr instanceof Literal) {
visit((Literal) expr);
} else if (expr instanceof Member) {
visit((Member) expr);
} else if (expr instanceof Method) {
visit((Method) expr);
} else if (expr instanceof TypeLiteral) {
visit((TypeLiteral) expr);
} else if (expr instanceof Unary) {
visit((Unary) expr);
}
}
/////////////////////////////////////////////////////////////////////////
//RequestURLHierarchyVisitor specific methods
/////////////////////////////////////////////////////////////////////////
@Override
public void visit(UriResourcePrimitiveProperty info) {
if (this.root) {
this.stack.add(new ScalarSubquery(buildRootSubQuery(info.getProperty().getName(), this.ctxExpression)));
root = false;
}
else {
this.stack.add(new ElementSymbol(info.getProperty().getName(), this.ctxExpression.getGroupSymbol()));
}
// hack to resolve the property type.
Column c = this.ctxExpression.getColumnByName(info.getProperty().getName());
this.lastPropertyType = c.getRuntimeType();
//revert back to the query context
this.ctxExpression = this.ctxQuery;
}
@Override
public void visit(UriResourceCount option) {
}
@Override
public void visit(UriResourceNavigation info) {
try {
DocumentNode navigationResource = DocumentNode.build(
(EdmEntityType) info.getType(), info.getKeyPredicates(), this.metadata, this.odata,
this.nameGenerator, true, getUriInfo(), this.parseService);
Query query = new Query();
query.setSelect(new Select(Arrays.asList(new AggregateSymbol(AggregateSymbol.Type.COUNT.name(), false, null))));
query.setFrom(new From(Arrays.asList(navigationResource.getFromClause())));
Criteria criteria = null;
ForeignKey fk = null;
if (info.isCollection()) {
fk = DocumentNode.joinFK(navigationResource, this.ctxQuery, info.getProperty());
}
else {
fk = DocumentNode.joinFK(this.ctxQuery, navigationResource, info.getProperty());
}
if (fk != null) {
List<String> lhsColumns = DocumentNode.getColumnNames(fk.getColumns());
List<String> rhsColumns = fk.getReferenceColumns();
GroupSymbol leftSymbol = this.ctxQuery.getGroupSymbol();
GroupSymbol rightSymbol = navigationResource.getGroupSymbol();
if (info.isCollection()) {
leftSymbol = navigationResource.getGroupSymbol();
rightSymbol = this.ctxQuery.getGroupSymbol();
}
for (int i = 0; i < lhsColumns.size(); i++) {
if (criteria == null) {
criteria = new CompareCriteria(new ElementSymbol(lhsColumns.get(i), leftSymbol),
CompareCriteria.EQ, new ElementSymbol(rhsColumns.get(i), rightSymbol));
} else {
Criteria subcriteria = new CompareCriteria(new ElementSymbol(lhsColumns.get(i), leftSymbol),
CompareCriteria.EQ, new ElementSymbol(rhsColumns.get(i), rightSymbol));
criteria = new CompoundCriteria(CompoundCriteria.AND, criteria, subcriteria);
}
}
}
else {
throw new TeiidException(ODataPlugin.Event.TEIID16037, ODataPlugin.Util.gs(ODataPlugin.Event.TEIID16037));
}
query.setCriteria(criteria);
this.stack.add(new ScalarSubquery(query));
} catch (TeiidException e) {
throw new TeiidRuntimeException(e);
}
}
@Override
public void visit(UriResourceLambdaAll all) {
accept(all.getExpression());
if (this.ctxLambda != null) {
org.teiid.query.sql.symbol.Expression predicate = this.stack.pop();
predicate = new SubqueryCompareCriteria(new Constant(true), buildSubquery(
this.ctxLambda, predicate), CompareCriteria.EQ,
SubqueryCompareCriteria.ALL);
this.stack.push(predicate);
}
this.ctxLambda = null;
}
@Override
public void visit(UriResourceLambdaAny any) {
accept(any.getExpression());
if (this.ctxLambda != null) {
org.teiid.query.sql.symbol.Expression predicate = this.stack.pop();
Query q = buildSubquery(this.ctxLambda, new Constant(1));
Criteria crit = null;
if (predicate instanceof Criteria) {
crit = (Criteria)predicate;
} else {
crit = new ExpressionCriteria(predicate);
}
q.setCriteria(Criteria.combineCriteria(q.getCriteria(), crit));
predicate = new ExistsCriteria(q);
this.stack.push(predicate);
}
this.ctxLambda = null;
}
@Override
public void visit(UriResourceLambdaVariable resource) {
try {
if (this.ctxLambda == null) {
DocumentNode lambda = DocumentNode.build(
(EdmEntityType) resource.getType(), null, this.metadata, this.odata,
this.nameGenerator, false, this.uriInfo,
this.parseService);
lambda.setGroupSymbol(new GroupSymbol(resource.getVariableName(), lambda.getFullName()));
this.ctxLambda = lambda;
}
this.ctxExpression = ctxLambda;
} catch (TeiidException e) {
throw new TeiidRuntimeException(e);
}
}
private Query buildSubquery(DocumentNode eResource,
org.teiid.query.sql.symbol.Expression projected) {
Select s1 = new Select();
s1.addSymbol(projected);
Query q = new Query();
From from = new From();
from.addGroup(eResource.getGroupSymbol());
q.setFrom(from);
q.setCriteria(DocumentNode.buildJoinCriteria(eResource, this.ctxQuery));
q.setSelect(s1);
return q;
}
@Override
public void visit(UriResourceIt info) {
if (info.getType() instanceof SingletonPrimitiveType) {
org.teiid.query.sql.symbol.Expression ex = null;
if (this.ctxQuery.getIterator() == null) {
String group = this.nameGenerator.getNextGroup();
GroupSymbol groupSymbol = new GroupSymbol(group);
StoredProcedure procedure = new StoredProcedure();
procedure.setProcedureName("arrayiterate");
//the projected should only be the collection property at this point
//we may need more checks here to ensure that is valid
Collection<ProjectedColumn> values = this.ctxQuery.getProjectedColumns().values();
Assertion.assertTrue(values.size() == 1);
ProjectedColumn projectedColumn = values.iterator().next();
ElementSymbol projectedEs = (ElementSymbol)projectedColumn.getExpression();
List<SPParameter> params = new ArrayList<SPParameter>();
SPParameter param = new SPParameter(1, SPParameter.IN, "val");
param.setExpression(projectedEs);
params.add(param);
procedure.setParameter(param);
SubqueryFromClause fromClause = new SubqueryFromClause(group, procedure);
fromClause.setLateral(true);
ElementSymbol es = new ElementSymbol("col", groupSymbol);
String type = ODataTypeManager.teiidType((SingletonPrimitiveType)info.getType(), false);
Function castFunction = new Function(CAST,new org.teiid.query.sql.symbol.Expression[] {es, new Constant(type)});
DocumentNode itResource = new DocumentNode();
org.teiid.query.sql.symbol.Expression clone = (org.teiid.query.sql.symbol.Expression) castFunction.clone();
AggregateSymbol symbol = new AggregateSymbol(AggregateSymbol.Type.ARRAY_AGG.name(), false, clone);
AliasSymbol expression = new AliasSymbol(projectedEs.getShortName(), symbol);
itResource.setFromClause(fromClause);
itResource.setGroupSymbol(groupSymbol);
itResource.addProjectedColumn(expression, info.getType(), projectedColumn.getProperty(), true);
this.ctxQuery.getProjectedColumns().remove(projectedColumn.getExpression());
this.ctxQuery.setIterator(itResource);
ex = castFunction;
} else {
GroupSymbol groupSymbol = this.ctxQuery.getIterator().getGroupSymbol();
ElementSymbol es = new ElementSymbol("col", groupSymbol);
String type = ODataTypeManager.teiidType((SingletonPrimitiveType)info.getType(), false);
ex = new Function(CAST,new org.teiid.query.sql.symbol.Expression[] {es, new Constant(type)});
}
this.stack.push(ex);
}
else {
boolean ex = true;
if (this.ctxQuery instanceof ExpandDocumentNode) {
ExpandDocumentNode node = (ExpandDocumentNode)this.ctxQuery;
DocumentNode parent = node.getCollectionContext();
if (parent != null) {
this.ctxExpression = parent;
ex = false;
}
}
if (ex) {
throw new TeiidRuntimeException(new TeiidNotImplementedException(
ODataPlugin.Event.TEIID16010,
ODataPlugin.Util.gs(ODataPlugin.Event.TEIID16010)));
}
}
}
@Override
public void visit(UriResourceRoot info) {
this.root = true;
}
@Override
public void visit(UriResourceEntitySet info) {
EdmEntityType edmEntityType = info.getEntitySet().getEntityType();
if (this.root) {
try {
this.ctxExpression = DocumentNode.build(edmEntityType,
info.getKeyPredicates(), this.metadata, this.odata, this.nameGenerator,
true, getUriInfo(), null);
} catch (TeiidException e) {
throw new TeiidRuntimeException(e);
}
}
else {
if (this.ctxQuery.getEdmEntityType().getFullQualifiedName().equals(edmEntityType.getFullQualifiedName())) {
this.ctxExpression = this.ctxQuery;
}
else {
for (DocumentNode er: this.ctxQuery.getSibilings()) {
if (er.getEdmEntityType().getFullQualifiedName().equals(edmEntityType.getFullQualifiedName())) {
this.ctxExpression = er;
break;
}
}
}
}
}
public QueryCommand buildRootSubQuery(String element, DocumentNode resource) {
Select s1 = new Select();
s1.addSymbol(new ElementSymbol(element, resource.getGroupSymbol()));
From f1 = new From();
f1.addGroup(resource.getGroupSymbol());
Query q1 = new Query();
q1.setSelect(s1);
q1.setFrom(f1);
q1.setCriteria(resource.getCriteria());
return q1;
}
}