package jeql.syntax;
import java.util.Iterator;
import java.util.List;
import jeql.api.error.ExecutionException;
import jeql.api.row.Row;
import jeql.api.row.RowIterator;
import jeql.api.row.RowList;
import jeql.api.row.RowSchema;
import jeql.api.table.Table;
import jeql.engine.Scope;
import jeql.util.TypeUtil;
public class InNode
extends ParseTreeNode
{
private static String ERROR_DIFFERENT_TYPEs = "LHS and RHS of IN are of different types";
private ParseTreeNode lhs;
private SelectNode sel;
private List exprList;
private boolean isNegated;
public InNode(ParseTreeNode lhs, SelectNode sel, boolean isNegated)
{
this.lhs = lhs;
this.sel = sel;
this.isNegated = isNegated;
setLoc(lhs);
}
public InNode(ParseTreeNode lhs, List exprList, boolean isNegated)
{
this.lhs = lhs;
this.exprList = exprList;
this.isNegated = isNegated;
setLoc(lhs);
}
public Class getType(Scope scope)
{
return Boolean.class;
}
public void bind(Scope scope)
{
lhs.bind(scope);
if (sel != null)
sel.bind(scope);
else {
for (Iterator i = exprList.iterator(); i.hasNext(); ) {
ParseTreeNode node = (ParseTreeNode) i.next();
node.bind(scope);
}
}
}
public Object eval(Scope scope)
{
Object lhsVal = lhs.eval(scope);
boolean result;
if (sel != null) {
result = evalInSelect(lhsVal, scope);
}
else {
result = evalInExprList(lhsVal, scope);
}
if (isNegated)
result = ! result;
return new Boolean(result);
}
private boolean evalInSelect(Object lhsVal, Scope scope)
{
Table tbl = (Table) sel.eval(scope);
RowList rows = tbl.getRows();
RowSchema schema = rows.getSchema();
if (schema.size() != 1)
throw new ExecutionException(this, "Table on rhs of IN must have single column");
checkSameTypes(lhsVal.getClass(), schema.getType(0));
RowIterator i = rows.iterator();
while (true) {
Row row = i.next();
if (row == null) break;
Object rowVal = row.getValue(0);
if (TypeUtil.isEqual(lhsVal, rowVal)) {
return true;
}
}
return false;
}
private boolean evalInExprList(Object lhsVal, Scope scope)
{
for (Iterator i = exprList.iterator(); i.hasNext(); ) {
ParseTreeNode node = (ParseTreeNode) i.next();
Object eVal = node.eval(scope);
checkSameTypes(lhsVal, eVal);
if (TypeUtil.isEqual(lhsVal, eVal)) {
return true;
}
}
return false;
}
private void checkSameTypes(Object lhsVal, Object rhsVal)
{
if (! TypeUtil.isSameType(lhsVal, rhsVal)) {
throw new ExecutionException(this, ERROR_DIFFERENT_TYPEs);
}
}
}