You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ja...@apache.org on 2014/01/27 23:15:34 UTC

[18/51] [partial] Initial commit of master branch from github

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/ExistsParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ExistsParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/ExistsParseNode.java
new file mode 100644
index 0000000..aaa1a73
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ExistsParseNode.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+
+
+/**
+ * 
+ * Node representing EXISTS and NOT EXISTS expressions in SQL
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class ExistsParseNode extends BinaryParseNode {
+    private final boolean negate;
+
+    ExistsParseNode(ParseNode l, ParseNode r, boolean negate) {
+        super(l, r);
+        this.negate = negate;
+    }
+    
+    public boolean isNegate() {
+        return negate;
+    }
+
+    @Override
+    public <T> T accept(ParseNodeVisitor<T> visitor) throws SQLException {
+        List<T> l = Collections.emptyList();
+        if (visitor.visitEnter(this)) {
+            l = acceptChildren(visitor);
+        }
+        return visitor.visitLeave(this, l);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/ExplainStatement.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ExplainStatement.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/ExplainStatement.java
new file mode 100644
index 0000000..fc437c5
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ExplainStatement.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+public class ExplainStatement implements BindableStatement {
+    private final BindableStatement statement;
+    
+    public ExplainStatement(BindableStatement statement) {
+        this.statement = statement;
+    }
+
+    public BindableStatement getStatement() {
+        return statement;
+    }
+
+    @Override
+    public int getBindCount() {
+        return statement.getBindCount();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/FamilyWildcardParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/FamilyWildcardParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/FamilyWildcardParseNode.java
new file mode 100644
index 0000000..438146c
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/FamilyWildcardParseNode.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.phoenix.parse;
+
+import java.sql.SQLException;
+
+/**
+ * 
+ * Node representing the selection of all columns of a family (cf.*) in the SELECT clause of SQL
+ *
+ * @author nmaillard
+ * @since 1.2
+ */
+
+public class FamilyWildcardParseNode extends NamedParseNode {
+    private final boolean isRewrite;
+    
+    public FamilyWildcardParseNode(String familyName, boolean isRewrite){
+        super(familyName);
+        this.isRewrite = isRewrite;
+    }
+    
+    public FamilyWildcardParseNode(FamilyWildcardParseNode familyName, boolean isRewrite){
+        super(familyName);
+        this.isRewrite = isRewrite;
+    }
+    
+	@Override
+	public <T> T accept(ParseNodeVisitor<T> visitor) throws SQLException {
+		return visitor.visit(this);
+	}
+
+    public boolean isRewrite() {
+        return isRewrite;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/FilterableStatement.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/FilterableStatement.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/FilterableStatement.java
new file mode 100644
index 0000000..47969d9
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/FilterableStatement.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.util.List;
+
+public interface FilterableStatement extends BindableStatement {
+    public HintNode getHint();
+    public ParseNode getWhere();
+    public boolean isDistinct();
+    public boolean isAggregate();
+    public List<OrderByNode> getOrderBy();
+    public LimitNode getLimit();
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/FloorParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/FloorParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/FloorParseNode.java
new file mode 100644
index 0000000..2f88bf2
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/FloorParseNode.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.phoenix.compile.StatementContext;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.function.FloorDateExpression;
+import org.apache.phoenix.expression.function.FloorDecimalExpression;
+import org.apache.phoenix.expression.function.FloorFunction;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.TypeMismatchException;
+
+/**
+ * Parse node corresponding to {@link FloorFunction}. 
+ * It also acts as a factory for creating the right kind of
+ * floor expression according to the data type of the 
+ * first child.
+ *
+ * @author samarth.jain
+ * @since 3.0.0
+ */
+public class FloorParseNode extends FunctionParseNode {
+
+    FloorParseNode(String name, List<ParseNode> children, BuiltInFunctionInfo info) {
+        super(name, children, info);
+    }
+
+    @Override
+    public Expression create(List<Expression> children, StatementContext context) throws SQLException {
+        return getFloorExpression(children);
+    }
+
+    public static Expression getFloorExpression(List<Expression> children) throws SQLException {
+        final Expression firstChild = children.get(0);
+        final PDataType firstChildDataType = firstChild.getDataType();
+        
+        //FLOOR on timestamp doesn't really care about the nanos part i.e. it just sets it to zero. 
+        //Which is exactly what FloorDateExpression does too. 
+        if(firstChildDataType.isCoercibleTo(PDataType.TIMESTAMP)) {
+            return FloorDateExpression.create(children);
+        } else if(firstChildDataType.isCoercibleTo(PDataType.DECIMAL)) {
+            return new FloorDecimalExpression(children);
+        } else {
+            throw TypeMismatchException.newException(firstChildDataType, "1");
+        }
+    }
+    
+    /**
+     * When rounding off decimals, user need not specify the scale. In such cases, 
+     * we need to prevent the function from getting evaluated as null. This is really
+     * a hack. A better way would have been if {@link org.apache.phoenix.parse.FunctionParseNode.BuiltInFunctionInfo} provided a 
+     * way of associating default values for each permissible data type.
+     * Something like: @ Argument(allowedTypes={PDataType.VARCHAR, PDataType.INTEGER}, defaultValues = {"null", "1"} isConstant=true)
+     * Till then, this will have to do.
+     */
+    @Override
+    public boolean evalToNullIfParamIsNull(StatementContext context, int index) throws SQLException {
+        return index == 0;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/FunctionParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/FunctionParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/FunctionParseNode.java
new file mode 100644
index 0000000..e31a19e
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/FunctionParseNode.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.http.annotation.Immutable;
+
+import com.google.common.collect.ImmutableSet;
+import org.apache.phoenix.compile.StatementContext;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.expression.function.AggregateFunction;
+import org.apache.phoenix.expression.function.FunctionExpression;
+import org.apache.phoenix.schema.ArgumentTypeMismatchException;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.ValueRangeExcpetion;
+import org.apache.phoenix.util.SchemaUtil;
+
+
+
+/**
+ * 
+ * Node representing a function expression in SQL
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class FunctionParseNode extends CompoundParseNode {
+    private final String name;
+    private final BuiltInFunctionInfo info;
+    
+    FunctionParseNode(String name, List<ParseNode> children, BuiltInFunctionInfo info) {
+        super(children);
+        this.name = SchemaUtil.normalizeIdentifier(name);
+        this.info = info;
+    }
+
+    public BuiltInFunctionInfo getInfo() {
+        return info;
+    }
+    
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public <T> T accept(ParseNodeVisitor<T> visitor) throws SQLException {
+        List<T> l = Collections.emptyList();
+        if (visitor.visitEnter(this)) {
+            l = acceptChildren(visitor);
+        }
+        return visitor.visitLeave(this, l);
+    }
+    
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder(name + "(");
+        for (ParseNode child : getChildren()) {
+            buf.append(child.toString());
+            buf.append(',');
+        }
+        buf.setLength(buf.length()-1);
+        buf.append(')');
+        return buf.toString();
+    }
+
+    public boolean isAggregate() {
+        return getInfo().isAggregate();
+    }
+    
+    /**
+     * Determines whether or not we can collapse a function expression to null if a required
+     * parameter is null.
+     * @param context
+     * @param index index of parameter
+     * @return true if when the parameter at index is null, the function always evaluates to null
+     *  and false otherwise.
+     * @throws SQLException
+     */
+    public boolean evalToNullIfParamIsNull(StatementContext context, int index) throws SQLException {
+        return true;
+    }
+    
+
+    private static Constructor<? extends FunctionParseNode> getParseNodeCtor(Class<? extends FunctionParseNode> clazz) {
+        Constructor<? extends FunctionParseNode> ctor;
+        try {
+            ctor = clazz.getDeclaredConstructor(String.class, List.class, BuiltInFunctionInfo.class);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        ctor.setAccessible(true);
+        return ctor;
+    }
+    
+    private static Constructor<? extends FunctionExpression> getExpressionCtor(Class<? extends FunctionExpression> clazz) {
+        Constructor<? extends FunctionExpression> ctor;
+        try {
+            ctor = clazz.getDeclaredConstructor(List.class);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        ctor.setAccessible(true);
+        return ctor;
+    }
+    
+    public List<Expression> validate(List<Expression> children, StatementContext context) throws SQLException {
+        BuiltInFunctionInfo info = this.getInfo();
+        BuiltInFunctionArgInfo[] args = info.getArgs();
+        if (args.length > children.size()) {
+            List<Expression> moreChildren = new ArrayList<Expression>(children);
+            for (int i = children.size(); i < info.getArgs().length; i++) {
+                moreChildren.add(LiteralExpression.newConstant(null, args[i].allowedTypes.length == 0 ? null :  args[i].allowedTypes[0], true));
+            }
+            children = moreChildren;
+        }
+        List<ParseNode> nodeChildren = this.getChildren();
+        for (int i = 0; i < children.size(); i++) {
+            BindParseNode bindNode = null;
+            PDataType[] allowedTypes = args[i].getAllowedTypes();
+            // Check if the node is a bind parameter, and set the parameter
+            // metadata based on the function argument annotation. Check to
+            // make sure we're not looking past the end of the list of
+            // child expression nodes, which can happen if the function
+            // invocation hasn't specified all arguments and is using default
+            // values.
+            if (i < nodeChildren.size() && nodeChildren.get(i) instanceof BindParseNode) {
+                bindNode = (BindParseNode)nodeChildren.get(i);
+            }
+            // If the child type is null, then the expression is unbound.
+            // Skip any validation, since we either 1) have a default value
+            // which has already been validated, 2) attempting to get the
+            // parameter metadata, or 3) have an unbound parameter which
+            // will be detected futher downstream.
+            Expression child = children.get(i);
+            if (child.getDataType() == null /* null used explicitly in query */ || i >= nodeChildren.size() /* argument left off */) {
+                // Replace the unbound expression with the default value expression if specified
+                if (args[i].getDefaultValue() != null) {
+                    Expression defaultValue = args[i].getDefaultValue();
+                    children.set(i, defaultValue);
+                    // Set the parameter metadata if this is a bind parameter
+                    if (bindNode != null) {
+                        context.getBindManager().addParamMetaData(bindNode, defaultValue);
+                    }
+                } else if (bindNode != null) {
+                    // Otherwise if the node is a bind parameter and we have type information
+                    // based on the function argument annonation set the parameter meta data.
+                    if (child.getDataType() == null) {
+                        if (allowedTypes.length > 0) {
+                            context.getBindManager().addParamMetaData(bindNode, LiteralExpression.newConstant(null, allowedTypes[0], true));
+                        }
+                    } else { // Use expression as is, since we already have the data type set
+                        context.getBindManager().addParamMetaData(bindNode, child);
+                    }
+                }
+            } else {
+                if (allowedTypes.length > 0) {
+                    boolean isCoercible = false;
+                    for (PDataType type : allowedTypes) {
+                        if (child.getDataType().isCoercibleTo(type)) {
+                            isCoercible = true;
+                            break;
+                        }
+                    }
+                    if (!isCoercible) {
+                        throw new ArgumentTypeMismatchException(Arrays.toString(args[i].getAllowedTypes()),
+                                child.getDataType().toString(), info.getName() + " argument " + (i + 1));
+                    }
+                    if (child instanceof LiteralExpression) {
+                        LiteralExpression valueExp = (LiteralExpression) child;
+                        LiteralExpression minValue = args[i].getMinValue();
+                        LiteralExpression maxValue = args[i].getMaxValue();
+                        if (minValue != null && minValue.getDataType().compareTo(minValue.getValue(), valueExp.getValue(), valueExp.getDataType()) > 0) {
+                            throw new ValueRangeExcpetion(minValue, maxValue == null ? "" : maxValue, valueExp.getValue(), info.getName() + " argument " + (i + 1));
+                        }
+                        if (maxValue != null && maxValue.getDataType().compareTo(maxValue.getValue(), valueExp.getValue(), valueExp.getDataType()) < 0) {
+                            throw new ValueRangeExcpetion(minValue == null ? "" : minValue, maxValue, valueExp.getValue(), info.getName() + " argument " + (i + 1));
+                        }
+                    }
+                }
+                if (args[i].isConstant() && ! (child instanceof LiteralExpression) ) {
+                    throw new ArgumentTypeMismatchException("constant", child.toString(), info.getName() + " argument " + (i + 1));
+                }
+                if (!args[i].getAllowedValues().isEmpty()) {
+                    Object value = ((LiteralExpression)child).getValue();
+                    if (!args[i].getAllowedValues().contains(value.toString().toUpperCase())) {
+                        throw new ArgumentTypeMismatchException(Arrays.toString(args[i].getAllowedValues().toArray(new String[0])),
+                                value.toString(), info.getName() + " argument " + (i + 1));
+                    }
+                }
+            }
+        }
+        return children;
+    }
+    
+    /**
+     * Entry point for parser to instantiate compiled representation of built-in function
+     * @param children Compiled expressions for child nodes
+     * @param context Query context for accessing state shared across the processing of multiple clauses
+     * @return compiled representation of built-in function
+     * @throws SQLException
+     */
+    public Expression create(List<Expression> children, StatementContext context) throws SQLException {
+        try {
+            return info.getFuncCtor().newInstance(children);
+        } catch (InstantiationException e) {
+            throw new SQLException(e);
+        } catch (IllegalAccessException e) {
+            throw new SQLException(e);
+        } catch (IllegalArgumentException e) {
+            throw new SQLException(e);
+        } catch (InvocationTargetException e) {
+            if (e.getTargetException() instanceof SQLException) {
+                throw (SQLException) e.getTargetException();
+            }
+            throw new SQLException(e);
+        }
+    }
+    
+    /**
+     * Marker used to indicate that a class should be used by DirectFunctionExpressionExec below
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    public
+    @interface BuiltInFunction {
+        String name();
+        Argument[] args() default {};
+        Class<? extends FunctionParseNode> nodeClass() default FunctionParseNode.class;
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    public
+    @interface Argument {
+        PDataType[] allowedTypes() default {};
+        boolean isConstant() default false;
+        String defaultValue() default "";
+        String enumeration() default "";
+        String minValue() default "";
+        String maxValue() default "";
+    }
+    
+    /**
+     * Structure used to hold parse-time information about Function implementation classes
+     */
+    @Immutable
+    public static final class BuiltInFunctionInfo {
+        private final String name;
+        private final Constructor<? extends FunctionExpression> funcCtor;
+        private final Constructor<? extends FunctionParseNode> nodeCtor;
+        private final BuiltInFunctionArgInfo[] args;
+        private final boolean isAggregate;
+        private final int requiredArgCount;
+
+        BuiltInFunctionInfo(Class<? extends FunctionExpression> f, BuiltInFunction d) {
+            this.name = SchemaUtil.normalizeIdentifier(d.name());
+            this.funcCtor = d.nodeClass() == FunctionParseNode.class ? getExpressionCtor(f) : null;
+            this.nodeCtor = d.nodeClass() == FunctionParseNode.class ? null : getParseNodeCtor(d.nodeClass());
+            this.args = new BuiltInFunctionArgInfo[d.args().length];
+            int requiredArgCount = 0;
+            for (int i = 0; i < args.length; i++) {
+                this.args[i] = new BuiltInFunctionArgInfo(d.args()[i]);
+                if (requiredArgCount < i && this.args[i].getDefaultValue() != null) {
+                    requiredArgCount = i;
+                }
+            }
+            this.requiredArgCount = requiredArgCount;
+            this.isAggregate = AggregateFunction.class.isAssignableFrom(f);
+        }
+
+        public int getRequiredArgCount() {
+            return requiredArgCount;
+        }
+        
+        public String getName() {
+            return name;
+        }
+
+        public Constructor<? extends FunctionExpression> getFuncCtor() {
+            return funcCtor;
+        }
+
+        public Constructor<? extends FunctionParseNode> getNodeCtor() {
+            return nodeCtor;
+        }
+
+        public boolean isAggregate() {
+            return isAggregate;
+        }
+        
+        public BuiltInFunctionArgInfo[] getArgs() {
+            return args;
+        }
+    }
+    
+    @Immutable
+    public static class BuiltInFunctionArgInfo {
+        private static final PDataType[] ENUMERATION_TYPES = new PDataType[] {PDataType.VARCHAR};
+        private final PDataType[] allowedTypes;
+        private final boolean isConstant;
+        private final Set<String> allowedValues; // Enumeration of possible values
+        private final LiteralExpression defaultValue;
+        private final LiteralExpression minValue;
+        private final LiteralExpression maxValue;
+        
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        BuiltInFunctionArgInfo(Argument argument) {
+            
+            if (argument.enumeration().length() > 0) {
+                this.isConstant = true;
+                this.defaultValue = null;
+                this.minValue = null;
+                this.maxValue = null;
+                this.allowedTypes = ENUMERATION_TYPES;
+                Class<?> clazz = null;
+                String packageName = FunctionExpression.class.getPackage().getName();
+                try {
+                    clazz = Class.forName(packageName + "." + argument.enumeration());
+                } catch (ClassNotFoundException e) {
+                    try {
+                        clazz = Class.forName(argument.enumeration());
+                    } catch (ClassNotFoundException e1) {
+                    }
+                }
+                if (clazz == null || !clazz.isEnum()) {
+                    throw new IllegalStateException("The enumeration annotation '" + argument.enumeration() + "' does not resolve to a enumeration class");
+                }
+                Class<? extends Enum> enumClass = (Class<? extends Enum>)clazz;
+				Enum[] enums = enumClass.getEnumConstants();
+                ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+                for (Enum en : enums) {
+                    builder.add(en.name());
+                }
+                allowedValues = builder.build();
+            } else {
+                this.allowedValues = Collections.emptySet();
+                this.isConstant = argument.isConstant();
+                this.allowedTypes = argument.allowedTypes();
+                this.defaultValue = getExpFromConstant(argument.defaultValue());
+                this.minValue = getExpFromConstant(argument.minValue());
+                this.maxValue = getExpFromConstant(argument.maxValue());
+            }
+        }
+
+        private LiteralExpression getExpFromConstant(String strValue) {
+            LiteralExpression exp = null;
+            if (strValue.length() > 0) {
+                SQLParser parser = new SQLParser(strValue);
+                try {
+                    LiteralParseNode node = parser.parseLiteral();
+                    LiteralExpression defaultValue = LiteralExpression.newConstant(node.getValue(), this.allowedTypes[0], true);
+                    if (this.getAllowedTypes().length > 0) {
+                        for (PDataType type : this.getAllowedTypes()) {
+                            if (defaultValue.getDataType() == null || defaultValue.getDataType().isCoercibleTo(type, node.getValue())) {
+                                return LiteralExpression.newConstant(node.getValue(), type, true);
+                            }
+                        }
+                        throw new IllegalStateException("Unable to coerce default value " + strValue + " to any of the allowed types of " + Arrays.toString(this.getAllowedTypes()));
+                    }
+                    exp = defaultValue;
+                } catch (SQLException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+            return exp;
+        }
+        
+        public boolean isConstant() {
+            return isConstant;
+        }
+
+        public LiteralExpression getDefaultValue() {
+            return defaultValue;
+        }
+
+        public LiteralExpression getMinValue() {
+            return minValue;
+        }
+        
+        public LiteralExpression getMaxValue() {
+            return maxValue;
+        }
+        
+        public PDataType[] getAllowedTypes() {
+            return allowedTypes;
+        }
+        
+        public Set<String> getAllowedValues() {
+            return allowedValues;
+        }
+    }    
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/GreaterThanOrEqualParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/GreaterThanOrEqualParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/GreaterThanOrEqualParseNode.java
new file mode 100644
index 0000000..4780d56
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/GreaterThanOrEqualParseNode.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import org.apache.hadoop.hbase.filter.CompareFilter;
+import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
+
+
+/**
+ * 
+ * Node representing the greater than or equal to operator (>=) in SQL
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class GreaterThanOrEqualParseNode extends ComparisonParseNode {
+
+    GreaterThanOrEqualParseNode(ParseNode lhs, ParseNode rhs) {
+        super(lhs, rhs);
+    }
+
+    @Override
+    public CompareOp getFilterOp() {
+        return CompareFilter.CompareOp.GREATER_OR_EQUAL;
+    }
+
+
+    @Override
+    public CompareOp getInvertFilterOp() {
+        return CompareOp.LESS_OR_EQUAL;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/GreaterThanParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/GreaterThanParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/GreaterThanParseNode.java
new file mode 100644
index 0000000..ff0442b
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/GreaterThanParseNode.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import org.apache.hadoop.hbase.filter.CompareFilter;
+import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
+
+
+/**
+ * 
+ * Node representing the greater than operator (>) in SQL
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class GreaterThanParseNode extends ComparisonParseNode {
+
+    GreaterThanParseNode(ParseNode lhs, ParseNode rhs) {
+        super(lhs, rhs);
+    }
+
+    @Override
+    public CompareOp getFilterOp() {
+        return CompareFilter.CompareOp.GREATER;
+    }
+
+    @Override
+    public CompareOp getInvertFilterOp() {
+        return CompareOp.LESS;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java
new file mode 100644
index 0000000..fa82382
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.phoenix.util.SchemaUtil;
+
+
+/**
+ * Node representing optimizer hints in SQL
+ */
+public class HintNode {
+    public static final HintNode EMPTY_HINT_NODE = new HintNode();
+    
+    public static final char SEPARATOR = ' ';
+    public static final String PREFIX = "(";
+    public static final String SUFFIX = ")";
+    // Split on whitespace and parenthesis, keeping the parenthesis in the token array
+    private static final String SPLIT_REGEXP = "\\s+|((?<=\\" + PREFIX + ")|(?=\\" + PREFIX + "))|((?<=\\" + SUFFIX + ")|(?=\\" + SUFFIX + "))";
+    
+    public enum Hint {
+        /**
+         * Forces a range scan to be used to process the query.
+         */
+        RANGE_SCAN,
+        /**
+         * Forces a skip scan to be used to process the query.
+         */
+        SKIP_SCAN,
+        /**
+         * Prevents the spawning of multiple threads during
+         * query processing.
+         */
+        NO_INTRA_REGION_PARALLELIZATION,
+        /**
+        * Prevents the usage of indexes, forcing usage
+        * of the data table for a query.
+        */
+       NO_INDEX,
+       /**
+       * Hint of the form INDEX(<table_name> <index_name>...)
+       * to suggest usage of the index if possible. The first
+       * usable index in the list of indexes will be choosen.
+       * Table and index names may be surrounded by double quotes
+       * if they are case sensitive.
+       */
+       INDEX,
+       /**
+        * All things being equal, use the data table instead of
+        * the index table when optimizing.
+        */
+       USE_DATA_OVER_INDEX_TABLE,
+       /**
+        * All things being equal, use the index table instead of
+        * the data table when optimizing.
+        */
+       USE_INDEX_OVER_DATA_TABLE,
+    };
+
+    private final Map<Hint,String> hints;
+
+    public static HintNode create(HintNode hintNode, Hint hint) {
+        return create(hintNode, hint, "");
+    }
+    
+    public static HintNode create(HintNode hintNode, Hint hint, String value) {
+        Map<Hint,String> hints = new HashMap<Hint,String>(hintNode.hints);
+        hints.put(hint, value);
+        return new HintNode(hints);
+    }
+    
+    private HintNode() {
+        hints = new HashMap<Hint,String>();
+    }
+
+    private HintNode(Map<Hint,String> hints) {
+        this.hints = ImmutableMap.copyOf(hints);
+    }
+
+    public HintNode(String hint) {
+        Map<Hint,String> hints = new HashMap<Hint,String>();
+        // Split on whitespace or parenthesis. We do not need to handle escaped or
+        // embedded whitespace/parenthesis, since we are parsing what will be HBase
+        // table names which are not allowed to contain whitespace or parenthesis.
+        String[] hintWords = hint.split(SPLIT_REGEXP);
+        for (int i = 0; i < hintWords.length; i++) {
+            String hintWord = hintWords[i];
+            if (hintWord.isEmpty()) {
+                continue;
+            }
+            try {
+                Hint key = Hint.valueOf(hintWord.toUpperCase());
+                String hintValue = "";
+                if (i+1 < hintWords.length && PREFIX.equals(hintWords[i+1])) {
+                    StringBuffer hintValueBuf = new StringBuffer(hint.length());
+                    hintValueBuf.append(PREFIX);
+                    i+=2;
+                    while (i < hintWords.length && !SUFFIX.equals(hintWords[i])) {
+                        hintValueBuf.append(SchemaUtil.normalizeIdentifier(hintWords[i++]));
+                        hintValueBuf.append(SEPARATOR);
+                    }
+                    // Replace trailing separator with suffix
+                    hintValueBuf.replace(hintValueBuf.length()-1, hintValueBuf.length(), SUFFIX);
+                    hintValue = hintValueBuf.toString();
+                }
+                String oldValue = hints.put(key, hintValue);
+                // Concatenate together any old value with the new value
+                if (oldValue != null) {
+                    hints.put(key, oldValue + hintValue);
+                }
+            } catch (IllegalArgumentException e) { // Ignore unknown/invalid hints
+            }
+        }
+        this.hints = ImmutableMap.copyOf(hints);
+    }
+    
+    public boolean isEmpty() {
+        return hints.isEmpty();
+    }
+
+    /**
+     * Gets the value of the hint or null if the hint is not present.
+     * @param hint the hint
+     * @return the value specified in parenthesis following the hint or null
+     * if the hint is not present.
+     * 
+     */
+    public String getHint(Hint hint) {
+        return hints.get(hint);
+    }
+
+    /**
+     * Tests for the presence of a hint in a query
+     * @param hint the hint
+     * @return true if the hint is present and false otherwise
+     */
+    public boolean hasHint(Hint hint) {
+        return hints.containsKey(hint);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/InListParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/InListParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/InListParseNode.java
new file mode 100644
index 0000000..7632de7
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/InListParseNode.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.phoenix.exception.SQLExceptionCode;
+import org.apache.phoenix.exception.SQLExceptionInfo;
+
+
+
+/**
+ * 
+ * Node representing the IN literal list expression in SQL
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class InListParseNode extends CompoundParseNode {
+    private final boolean negate;
+
+    InListParseNode(List<ParseNode> children, boolean negate) {
+        super(children);
+        // All values in the IN must be constant. First child is the LHS
+        for (int i = 1; i < children.size(); i++) {
+            ParseNode child = children.get(i);
+            if (!child.isStateless()) {
+                throw new ParseException(new SQLExceptionInfo.Builder(SQLExceptionCode.VALUE_IN_LIST_NOT_CONSTANT)
+                .build().buildException());
+            }
+        }
+        this.negate = negate;
+    }
+    
+    public boolean isNegate() {
+        return negate;
+    }
+
+    @Override
+    public <T> T accept(ParseNodeVisitor<T> visitor) throws SQLException {
+        List<T> l = Collections.emptyList();
+        if (visitor.visitEnter(this)) {
+            l = acceptChildren(visitor);
+        }
+        return visitor.visitLeave(this, l);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/InParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/InParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/InParseNode.java
new file mode 100644
index 0000000..d7708fc
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/InParseNode.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+
+
+/**
+ * 
+ * Node representing IN subquery expression in SQL
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class InParseNode extends BinaryParseNode {
+    private final boolean negate;
+
+    InParseNode(ParseNode l, ParseNode r, boolean negate) {
+        super(l, r);
+        this.negate = negate;
+    }
+    
+    public boolean isNegate() {
+        return negate;
+    }
+
+    @Override
+    public <T> T accept(ParseNodeVisitor<T> visitor) throws SQLException {
+        List<T> l = Collections.emptyList();
+        if (visitor.visitEnter(this)) {
+            l = acceptChildren(visitor);
+        }
+        return visitor.visitLeave(this, l);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/IndexKeyConstraint.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/IndexKeyConstraint.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/IndexKeyConstraint.java
new file mode 100644
index 0000000..6dfc744
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/IndexKeyConstraint.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.util.List;
+
+import org.apache.hadoop.hbase.util.Pair;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.phoenix.schema.ColumnModifier;
+
+public class IndexKeyConstraint {
+    private final List<Pair<ColumnParseNode, ColumnModifier>> columnNameToModifier;
+    
+    IndexKeyConstraint(List<Pair<ColumnParseNode, ColumnModifier>> columnNameAndModifier) {
+        this.columnNameToModifier = ImmutableList.copyOf(columnNameAndModifier);
+    }
+
+    public List<Pair<ColumnParseNode, ColumnModifier>> getColumns() {
+        return columnNameToModifier;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/IsNullParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/IsNullParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/IsNullParseNode.java
new file mode 100644
index 0000000..a1afc2e
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/IsNullParseNode.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+
+
+/**
+ * 
+ * Node representing the IS NULL and IS NOT NULL expressions in SQL
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class IsNullParseNode extends UnaryParseNode {
+    private final boolean negate;
+    
+    IsNullParseNode(ParseNode expr, boolean negate) {
+        super(expr);
+        this.negate = negate;
+    }
+    
+    public boolean isNegate() {
+        return negate;
+    }
+
+    @Override
+    public <T> T accept(ParseNodeVisitor<T> visitor) throws SQLException {
+        List<T> l = Collections.emptyList();
+        if (visitor.visitEnter(this)) {
+            l = acceptChildren(visitor);
+        }
+        return visitor.visitLeave(this, l);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/JoinTableNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/JoinTableNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/JoinTableNode.java
new file mode 100644
index 0000000..d6f7f82
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/JoinTableNode.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.sql.SQLException;
+
+
+
+/**
+ * 
+ * Node representing the join specified in the FROM clause of SQL
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class JoinTableNode extends TableNode {
+    public enum JoinType {Inner, Left, Right, Full};
+    
+    private final JoinType type;
+    private final ParseNode on;
+    private final TableNode table;
+    
+    JoinTableNode(JoinType type, ParseNode on, TableNode table) {
+        super(table.getAlias());
+        this.type = type;
+        this.on = on;
+        this.table = table;
+    }
+
+    public JoinType getType() {
+        return type;
+    }
+
+    public ParseNode getOnNode() {
+        return on;
+    }
+    
+    public TableNode getTable() {
+        return table;
+    }
+
+    @Override
+    public void accept(TableNodeVisitor visitor) throws SQLException {
+        visitor.visit(this);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/LessThanOrEqualParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/LessThanOrEqualParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/LessThanOrEqualParseNode.java
new file mode 100644
index 0000000..4fb91dd
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/LessThanOrEqualParseNode.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import org.apache.hadoop.hbase.filter.CompareFilter;
+import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
+
+
+/**
+ * 
+ * Node representing the less than or equal to operator (<=) in SQL
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class LessThanOrEqualParseNode extends ComparisonParseNode {
+
+    LessThanOrEqualParseNode(ParseNode lhs, ParseNode rhs) {
+        super(lhs, rhs);
+    }
+
+    @Override
+    public CompareOp getFilterOp() {
+        return CompareFilter.CompareOp.LESS_OR_EQUAL;
+    }
+
+    @Override
+    public CompareOp getInvertFilterOp() {
+        return CompareOp.GREATER_OR_EQUAL;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/LessThanParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/LessThanParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/LessThanParseNode.java
new file mode 100644
index 0000000..c9f69dc
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/LessThanParseNode.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import org.apache.hadoop.hbase.filter.CompareFilter;
+import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
+
+
+/**
+ * 
+ * Node representing the less than operator (<) in SQL
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class LessThanParseNode extends ComparisonParseNode {
+
+    LessThanParseNode(ParseNode lhs, ParseNode rhs) {
+        super(lhs, rhs);
+    }
+
+    @Override
+    public CompareOp getFilterOp() {
+        return CompareFilter.CompareOp.LESS;
+    }
+
+    @Override
+    public CompareOp getInvertFilterOp() {
+        return CompareOp.GREATER;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/LikeParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/LikeParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/LikeParseNode.java
new file mode 100644
index 0000000..b941d56
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/LikeParseNode.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+
+
+/**
+ * 
+ * Node representing LIKE and NOT LIKE in SQL
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class LikeParseNode extends BinaryParseNode {
+    private final boolean negate;
+
+    LikeParseNode(ParseNode lhs, ParseNode rhs, boolean negate) {
+        super(lhs, rhs);
+        this.negate = negate;
+    }
+    
+    public boolean isNegate() {
+        return negate;
+    }
+
+    @Override
+    public <T> T accept(ParseNodeVisitor<T> visitor) throws SQLException {
+        List<T> l = Collections.emptyList();
+        if (visitor.visitEnter(this)) {
+            l = acceptChildren(visitor);
+        }
+        return visitor.visitLeave(this, l);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/LimitNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/LimitNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/LimitNode.java
new file mode 100644
index 0000000..cd4d6a9
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/LimitNode.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+
+public class LimitNode {
+    private final BindParseNode bindNode;
+    private final LiteralParseNode limitNode;
+    
+    LimitNode(BindParseNode bindNode) {
+        this.bindNode = bindNode;
+        limitNode = null;
+    }
+    
+    LimitNode(LiteralParseNode limitNode) {
+        this.limitNode = limitNode;
+        this.bindNode = null;
+    }
+    
+    public ParseNode getLimitParseNode() {
+        return bindNode == null ? limitNode : bindNode;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/LiteralParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/LiteralParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/LiteralParseNode.java
new file mode 100644
index 0000000..25247ee
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/LiteralParseNode.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.phoenix.schema.PDataType;
+
+
+
+/**
+ * 
+ * Node representing literal expressions such as 1,2.5,'foo', and NULL in SQL
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class LiteralParseNode extends TerminalParseNode {
+    public static final List<ParseNode> STAR = Collections.<ParseNode>singletonList(new LiteralParseNode(1));
+    public static final ParseNode NULL = new LiteralParseNode(null);
+    public static final ParseNode ZERO = new LiteralParseNode(0);
+    public static final ParseNode ONE = new LiteralParseNode(1);
+    
+    private final Object value;
+    private final PDataType type;
+    
+    public LiteralParseNode(Object value) {
+        this.value = value;
+        this.type = PDataType.fromLiteral(value);
+    }
+
+    public PDataType getType() {
+        return type;
+    }
+    
+    public Object getValue() {
+        return value;
+    }
+
+    @Override
+    public boolean isStateless() {
+        return true;
+    }
+    
+    @Override
+    public <T> T accept(ParseNodeVisitor<T> visitor) throws SQLException {
+        return visitor.visit(this);
+    }
+
+    public byte[] getBytes() {
+        return type == null ? null : type.toBytes(value);
+    }
+    
+    @Override
+    public String toString() {
+        return type == PDataType.VARCHAR ? ("'" + value.toString() + "'") : value == null ? "null" : value.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/MaxAggregateParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/MaxAggregateParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/MaxAggregateParseNode.java
new file mode 100644
index 0000000..6f59a72
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/MaxAggregateParseNode.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.phoenix.compile.StatementContext;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.function.FunctionExpression;
+import org.apache.phoenix.expression.function.MaxAggregateFunction;
+
+
+public class MaxAggregateParseNode extends DelegateConstantToCountParseNode {
+
+    public MaxAggregateParseNode(String name, List<ParseNode> children, BuiltInFunctionInfo info) {
+        super(name, children, info);
+    }
+    
+    @Override
+    public FunctionExpression create(List<Expression> children, StatementContext context) throws SQLException {
+        return new MaxAggregateFunction(children, getDelegateFunction(children,context));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/MinAggregateParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/MinAggregateParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/MinAggregateParseNode.java
new file mode 100644
index 0000000..f6450dd
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/MinAggregateParseNode.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.phoenix.compile.StatementContext;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.function.FunctionExpression;
+import org.apache.phoenix.expression.function.MinAggregateFunction;
+
+
+public class MinAggregateParseNode extends DelegateConstantToCountParseNode {
+
+    public MinAggregateParseNode(String name, List<ParseNode> children, BuiltInFunctionInfo info) {
+        super(name, children, info);
+    }
+    
+    @Override
+    public FunctionExpression create(List<Expression> children, StatementContext context) throws SQLException {
+        return new MinAggregateFunction(children, getDelegateFunction(children,context));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/MultiplyParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/MultiplyParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/MultiplyParseNode.java
new file mode 100644
index 0000000..1b100e9
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/MultiplyParseNode.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+
+
+/**
+ * 
+ * Node representing multiplication in a SQL expression
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class MultiplyParseNode extends ArithmeticParseNode {
+
+    MultiplyParseNode(List<ParseNode> children) {
+        super(children);
+    }
+
+    @Override
+    public <T> T accept(ParseNodeVisitor<T> visitor) throws SQLException {
+        List<T> l = Collections.emptyList();
+        if (visitor.visitEnter(this)) {
+            l = acceptChildren(visitor);
+        }
+        return visitor.visitLeave(this, l);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedNode.java
new file mode 100644
index 0000000..9c687aa
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedNode.java
@@ -0,0 +1,45 @@
+package org.apache.phoenix.parse;
+
+import org.apache.phoenix.util.SchemaUtil;
+
+public class NamedNode {
+    private final String name;
+    private final boolean isCaseSensitive;
+    
+    public static NamedNode caseSensitiveNamedNode(String name) {
+        return new NamedNode(name,true);
+    }
+    
+    private NamedNode(String name, boolean isCaseSensitive) {
+        this.name = name;
+        this.isCaseSensitive = isCaseSensitive;
+    }
+
+    NamedNode(String name) {
+        this.name = SchemaUtil.normalizeIdentifier(name);
+        this.isCaseSensitive = name == null ? false : SchemaUtil.isCaseSensitive(name);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public boolean isCaseSensitive() {
+        return isCaseSensitive;
+    }
+    
+    @Override
+    public int hashCode() {
+        return name.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        NamedNode other = (NamedNode)obj;
+        return name.equals(other.name);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedParseNode.java
new file mode 100644
index 0000000..bd1c6cf
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedParseNode.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+
+/**
+ * 
+ * Abstract node representing named nodes such as binds and column expressions in SQL
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public abstract class NamedParseNode extends TerminalParseNode{
+    private final NamedNode namedNode;
+    
+    NamedParseNode(NamedParseNode node) {
+        this.namedNode = node.namedNode;
+    }
+
+    NamedParseNode(String name) {
+        this.namedNode = new NamedNode(name);
+    }
+
+    public String getName() {
+        return namedNode.getName();
+    }
+
+    public boolean isCaseSensitive() {
+        return namedNode.isCaseSensitive();
+    }
+    
+    @Override
+    public String toString() {
+        return getName();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedTableNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedTableNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedTableNode.java
new file mode 100644
index 0000000..4be546d
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/NamedTableNode.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Node representing an explicit table reference in the FROM clause of SQL
+ * 
+ * @author jtaylor
+ * @since 0.1
+ */
+public class NamedTableNode extends ConcreteTableNode {
+
+    private final List<ColumnDef> dynColumns;
+
+    public static NamedTableNode create (String alias, TableName name, List<ColumnDef> dynColumns) {
+        return new NamedTableNode(alias, name, dynColumns);
+    }
+    
+    NamedTableNode(String alias, TableName name) {
+        super(alias, name);
+        dynColumns = Collections.<ColumnDef> emptyList();
+    }
+
+    NamedTableNode(String alias, TableName name, List<ColumnDef> dynColumns) {
+        super(alias, name);
+        if (dynColumns != null) {
+            this.dynColumns = ImmutableList.copyOf(dynColumns);
+        } else {
+            this.dynColumns = Collections.<ColumnDef> emptyList();
+        }
+    }
+
+    @Override
+    public void accept(TableNodeVisitor visitor) throws SQLException {
+        visitor.visit(this);
+    }
+
+    public List<ColumnDef> getDynamicColumns() {
+        return dynColumns;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/NotEqualParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/NotEqualParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/NotEqualParseNode.java
new file mode 100644
index 0000000..7872275
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/NotEqualParseNode.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
+
+
+
+/**
+ * 
+ * Node representing a not equal expression (!=,<>) in SQL
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class NotEqualParseNode extends ComparisonParseNode {
+
+    NotEqualParseNode(ParseNode lhs, ParseNode rhs) {
+        super(lhs, rhs);
+    }
+
+    @Override
+    public CompareOp getFilterOp() {
+        return CompareOp.NOT_EQUAL;
+    }
+
+    @Override
+    public CompareOp getInvertFilterOp() {
+        return CompareOp.NOT_EQUAL;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/NotParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/NotParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/NotParseNode.java
new file mode 100644
index 0000000..580e7ca
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/NotParseNode.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+
+
+/**
+ * 
+ * Node representing the NOT in SQL
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class NotParseNode extends UnaryParseNode {
+
+    NotParseNode(ParseNode expr) {
+        super(expr);
+    }
+
+    @Override
+    public <T> T accept(ParseNodeVisitor<T> visitor) throws SQLException {
+        List<T> l = Collections.emptyList();
+        if (visitor.visitEnter(this)) {
+            l = acceptChildren(visitor);
+        }
+        return visitor.visitLeave(this, l);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/OrParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/OrParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/OrParseNode.java
new file mode 100644
index 0000000..0fe869f
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/OrParseNode.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+
+
+/**
+ * 
+ * Node representing an OR in SQL
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class OrParseNode extends CompoundParseNode {
+
+    OrParseNode(List<ParseNode> children) {
+        super(children);
+    }
+
+    @Override
+    public <T> T accept(ParseNodeVisitor<T> visitor) throws SQLException {
+        List<T> l = Collections.emptyList();
+        if (visitor.visitEnter(this)) {
+            l = acceptChildren(visitor);
+        }
+        return visitor.visitLeave(this, l);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/OrderByNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/OrderByNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/OrderByNode.java
new file mode 100644
index 0000000..6a48d10
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/OrderByNode.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+
+/**
+ * 
+ * Node representing an ORDER BY clause (including asc/desc and nulls first/last) in SQL
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public final class OrderByNode {
+    private final ParseNode child;
+    private final boolean nullsLast;
+    private final boolean orderAscending;
+    
+    OrderByNode(ParseNode child, boolean nullsLast, boolean orderAscending) {
+        this.child = child;
+        this.nullsLast = nullsLast;
+        this.orderAscending = orderAscending;
+    }
+    
+    public boolean isNullsLast() {
+        return nullsLast;
+    }
+    
+    public boolean isAscending() {
+        return orderAscending;
+    }
+    
+    public ParseNode getNode() {
+        return child;
+    }
+    
+    @Override
+    public String toString() {
+        return child.toString() + (orderAscending ? " asc" : " desc") + " nulls " + (nullsLast ? "last" : "first");
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/parse/OuterJoinParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/OuterJoinParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/OuterJoinParseNode.java
new file mode 100644
index 0000000..12ed92b
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/OuterJoinParseNode.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.parse;
+
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+
+
+/**
+ * 
+ * Node representing an outer join qualifier (+) in SQL
+ * TODO: remove Oracle specific syntax
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class OuterJoinParseNode extends UnaryParseNode{
+    OuterJoinParseNode(ParseNode node) {
+        super(node);
+    }
+
+    @Override
+    public <T> T accept(ParseNodeVisitor<T> visitor) throws SQLException {
+        List<T> l = Collections.emptyList();
+        if (visitor.visitEnter(this)) {
+            l = acceptChildren(visitor);
+        }
+        return visitor.visitLeave(this, l);
+    }
+}