package jeql.syntax; import java.util.ArrayList; import java.util.List; import jeql.api.error.ExecutionException; import jeql.api.table.Table; import jeql.engine.Scope; import jeql.engine.query.SelectEvaluator; import jeql.std.function.ValFunction; /** * A node representing a select expression * * @author Martin Davis * @version 1.0 */ public class SelectNode extends ParseTreeNode { public static final int NOT_SPECIFIED = -1; private SelectItemList selectList; private boolean isDistinct = false; private StatementListNode aliasList; private FromList fromList; private ParseTreeNode whereExpr; private ParseTreeNode splitByExpr; private ParseTreeNode limitExpr = null; private int limitVal = NOT_SPECIFIED; private ParseTreeNode offsetExpr = null; private int offsetVal = NOT_SPECIFIED; // list<TableColumnNode> private List groupByList = null; // list<OrderItem> private List orderList = null; public SelectNode(SelectItemList selectList) { this.selectList = selectList; } public SelectNode(SelectItemList selectList, boolean isDistinct, StatementListNode aliasList, FromList fromList, ParseTreeNode whereExpr, ParseTreeNode splitByExpr, ParseTreeNode limitVal, ParseTreeNode offsetVal, List groupByList, List orderList) { this.selectList = selectList; this.isDistinct = isDistinct; this.aliasList = aliasList; this.fromList = fromList; this.whereExpr = whereExpr; this.splitByExpr = splitByExpr; this.limitExpr = limitVal; this.offsetExpr = offsetVal; if (groupByList == null) this.groupByList = new ArrayList(); else this.groupByList = groupByList; this.orderList = orderList; } public SelectItemList getSelectList() { return selectList; } public boolean hasDistinct() { return isDistinct; } public StatementListNode getAliasList() { return aliasList; } public FromList getFromList() { return fromList; } public ParseTreeNode getWhere() { return whereExpr; } public ParseTreeNode getSplitBy() { return splitByExpr; } public boolean hasLimit() { return ! (limitExpr == null && offsetExpr == null); } public int getLimitValue() { return limitVal; } public int getOffsetValue() { if (offsetExpr == null) return 0; return offsetVal; } public boolean isGrouped() { return groupByList != null && groupByList.size() > 0; } public List getGroupByList() { return groupByList; } public boolean hasOrderBy() { return orderList != null && orderList.size() > 0; } public List getOrderList() { return orderList; } public boolean hasFromList() { return fromList != null && fromList.size() > 0; } public void bind(Scope scope) { // most clause of SelectNodes are bound when they are eval'ed // LIMIT and OFFSET expressions are bound at bind time if (limitExpr != null) limitExpr.bind(scope); if (offsetExpr != null) offsetExpr.bind(scope); return; } /** * @return a Table */ public Object eval(Scope scope) { limitVal = evalInt(limitExpr, scope); offsetVal = evalInt(offsetExpr, scope); if (limitVal < -1) throw new ExecutionException("Invalid Limit value: " + limitVal); if (offsetVal < -1) throw new ExecutionException("Invalid Offset value: " + offsetVal); SelectEvaluator queryEval = new SelectEvaluator(this); return queryEval.eval(scope); } private int evalInt(ParseTreeNode expr, Scope scope) { if (expr == null) return -1; Object val = expr.eval(scope); return ValFunction.toInt(val).intValue(); } public Class getType(Scope scope) { return Table.class; } public String monitorTag() { StringBuilder sb = new StringBuilder(); sb.append("SELECT FROM "); List froms = fromList.getItems(); boolean isJoin = false; for (Object o : froms) { FromItem from = (FromItem) o; if (isJoin) sb.append(" JOIN "); sb.append(from.getTableNameOrAlias()); isJoin = true; } return sb.toString(); } }