Range connector update with order by hint.

Change-Id: I1b36f6dea801950c39bf63f27a0ec70d3584c5b7
Reviewed-on: https://asterix-gerrit.ics.uci.edu/254
Reviewed-by: Ildar Absalyamov <ildar.absalyamov@gmail.com>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Steven Jacobs <sjaco002@ucr.edu>
diff --git a/asterix-aql/src/main/java/edu/uci/ics/asterix/aql/expression/OrderbyClause.java b/asterix-aql/src/main/java/edu/uci/ics/asterix/aql/expression/OrderbyClause.java
index 4418df9..90e8724 100644
--- a/asterix-aql/src/main/java/edu/uci/ics/asterix/aql/expression/OrderbyClause.java
+++ b/asterix-aql/src/main/java/edu/uci/ics/asterix/aql/expression/OrderbyClause.java
@@ -21,10 +21,12 @@
 import edu.uci.ics.asterix.aql.expression.visitor.IAqlExpressionVisitor;
 import edu.uci.ics.asterix.aql.expression.visitor.IAqlVisitorWithVoidReturn;
 import edu.uci.ics.asterix.common.exceptions.AsterixException;
+import edu.uci.ics.hyracks.dataflow.common.data.partition.range.IRangeMap;
 
 public class OrderbyClause implements Clause {
     private List<Expression> orderbyList;
     private List<OrderModifier> modifierList;
+    private IRangeMap rangeMap;
     private int numFrames = -1;
     private int numTuples = -1;
 
@@ -86,4 +88,12 @@
     public void setNumTuples(int numTuples) {
         this.numTuples = numTuples;
     }
+
+    public IRangeMap getRangeMap() {
+        return rangeMap;
+    }
+
+    public void setRangeMap(IRangeMap rangeMap) {
+        this.rangeMap = rangeMap;
+    }
 }
diff --git a/asterix-aql/src/main/java/edu/uci/ics/asterix/aql/rewrites/CloneAndSubstituteVariablesVisitor.java b/asterix-aql/src/main/java/edu/uci/ics/asterix/aql/rewrites/CloneAndSubstituteVariablesVisitor.java
index 1e6747e..edb080c 100644
--- a/asterix-aql/src/main/java/edu/uci/ics/asterix/aql/rewrites/CloneAndSubstituteVariablesVisitor.java
+++ b/asterix-aql/src/main/java/edu/uci/ics/asterix/aql/rewrites/CloneAndSubstituteVariablesVisitor.java
@@ -311,6 +311,9 @@
             List<VariableSubstitution> arg) throws AsterixException {
         List<Expression> exprList = visitAndCloneExprList(oc.getOrderbyList(), arg);
         OrderbyClause oc2 = new OrderbyClause(exprList, oc.getModifierList());
+        oc2.setNumFrames(oc.getNumFrames());
+        oc2.setNumTuples(oc.getNumTuples());
+        oc2.setRangeMap(oc.getRangeMap());
         return new Pair<IAqlExpression, List<VariableSubstitution>>(oc2, arg);
     }
 
diff --git a/asterix-aql/src/main/java/edu/uci/ics/asterix/aql/util/RangeMapBuilder.java b/asterix-aql/src/main/java/edu/uci/ics/asterix/aql/util/RangeMapBuilder.java
new file mode 100644
index 0000000..223358c
--- /dev/null
+++ b/asterix-aql/src/main/java/edu/uci/ics/asterix/aql/util/RangeMapBuilder.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2009-2013 by The Regents of the University of California
+ * Licensed 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 from
+ *
+ *     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 edu.uci.ics.asterix.aql.util;
+
+import java.io.DataOutput;
+import java.util.List;
+
+import edu.uci.ics.asterix.aql.base.Expression;
+import edu.uci.ics.asterix.aql.base.Expression.Kind;
+import edu.uci.ics.asterix.aql.base.Literal;
+import edu.uci.ics.asterix.aql.base.Statement;
+import edu.uci.ics.asterix.aql.expression.ListConstructor;
+import edu.uci.ics.asterix.aql.expression.LiteralExpr;
+import edu.uci.ics.asterix.aql.expression.Query;
+import edu.uci.ics.asterix.aql.literal.DoubleLiteral;
+import edu.uci.ics.asterix.aql.literal.FloatLiteral;
+import edu.uci.ics.asterix.aql.literal.IntegerLiteral;
+import edu.uci.ics.asterix.aql.literal.LongIntegerLiteral;
+import edu.uci.ics.asterix.aql.literal.StringLiteral;
+import edu.uci.ics.asterix.aql.parser.AQLParser;
+import edu.uci.ics.asterix.aql.parser.ParseException;
+import edu.uci.ics.asterix.common.exceptions.AsterixException;
+import edu.uci.ics.asterix.formats.nontagged.AqlBinaryComparatorFactoryProvider;
+import edu.uci.ics.asterix.formats.nontagged.AqlSerializerDeserializerProvider;
+import edu.uci.ics.asterix.om.base.AMutableDouble;
+import edu.uci.ics.asterix.om.base.AMutableFloat;
+import edu.uci.ics.asterix.om.base.AMutableInt32;
+import edu.uci.ics.asterix.om.base.AMutableInt64;
+import edu.uci.ics.asterix.om.base.AMutableString;
+import edu.uci.ics.asterix.om.types.ATypeTag;
+import edu.uci.ics.asterix.om.types.BuiltinType;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.NotImplementedException;
+import edu.uci.ics.hyracks.api.dataflow.value.IBinaryComparator;
+import edu.uci.ics.hyracks.api.dataflow.value.IBinaryComparatorFactory;
+import edu.uci.ics.hyracks.api.dataflow.value.ISerializerDeserializer;
+import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
+import edu.uci.ics.hyracks.data.std.util.ArrayBackedValueStorage;
+import edu.uci.ics.hyracks.dataflow.common.data.partition.range.IRangeMap;
+import edu.uci.ics.hyracks.dataflow.common.data.partition.range.RangeMap;
+
+public abstract class RangeMapBuilder {
+
+    public static IRangeMap parseHint(Object hint) throws ParseException {
+        ArrayBackedValueStorage abvs = new ArrayBackedValueStorage();
+        DataOutput out = abvs.getDataOutput();;
+        abvs.reset();
+
+        AQLParser parser = new AQLParser((String) hint);
+        List<Statement> hintStatements = parser.parse();
+        if (hintStatements.size() != 1) {
+            throw new ParseException("Only one range statement is allowed for the range hint.");
+        }
+
+        // Translate the query into a Range Map
+        if (hintStatements.get(0).getKind() != Statement.Kind.QUERY) {
+            throw new ParseException("Not a proper query for the range hint.");
+        }
+        Query q = (Query) hintStatements.get(0);
+
+        if (q.getBody().getKind() != Kind.LIST_CONSTRUCTOR_EXPRESSION) {
+            throw new ParseException("The range hint must be a list.");
+        }
+        List<Expression> el = (List<Expression>) ((ListConstructor) q.getBody()).getExprList();
+        int offsets[] = new int[el.size()];
+
+        // Loop over list of literals
+        for (int i = 0; i < el.size(); ++i) {
+            Expression item = el.get(i);
+            if (item.getKind() == Kind.LITERAL_EXPRESSION) {
+                parseLiteralToBytes(item, out);
+                offsets[i] = abvs.getLength();
+            }
+            // TODO Add support for composite fields.
+        }
+
+        return new RangeMap(1, abvs.getByteArray(), offsets);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static void parseLiteralToBytes(Expression item, DataOutput out) throws ParseException {
+        AMutableDouble aDouble = new AMutableDouble(0);
+        AMutableFloat aFloat = new AMutableFloat(0);
+        AMutableInt64 aInt64 = new AMutableInt64(0);
+        AMutableInt32 aInt32 = new AMutableInt32(0);
+        AMutableString aString = new AMutableString("");
+        @SuppressWarnings("rawtypes")
+        ISerializerDeserializer serde;
+
+        Literal l = (Literal) ((LiteralExpr) item).getValue();
+        try {
+            switch (l.getLiteralType()) {
+                case DOUBLE:
+                    DoubleLiteral dl = (DoubleLiteral) l;
+                    serde = AqlSerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ADOUBLE);
+                    aDouble.setValue(dl.getValue());
+                    serde.serialize(aDouble, out);
+                    break;
+                case FLOAT:
+                    FloatLiteral fl = (FloatLiteral) l;
+                    serde = AqlSerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AFLOAT);
+                    aFloat.setValue(fl.getValue());
+                    serde.serialize(aFloat, out);
+                    break;
+                case INTEGER:
+                    IntegerLiteral il = (IntegerLiteral) l;
+                    serde = AqlSerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AINT32);
+                    aInt32.setValue(il.getValue());
+                    serde.serialize(aInt32, out);
+                    break;
+                case LONG:
+                    LongIntegerLiteral lil = (LongIntegerLiteral) l;
+                    serde = AqlSerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AINT64);
+                    aInt64.setValue(lil.getValue());
+                    serde.serialize(aInt64, out);
+                    break;
+                case STRING:
+                    StringLiteral sl = (StringLiteral) l;
+                    serde = AqlSerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.ASTRING);
+                    aString.setValue(sl.getValue());
+                    serde.serialize(aString, out);
+                    break;
+                default:
+                    throw new NotImplementedException("The range map builder has not been implemented for "
+                            + item.getKind() + " type of expressions.");
+            }
+        } catch (HyracksDataException e) {
+            throw new ParseException(e.getMessage());
+        }
+    }
+
+    public static void verifyRangeOrder(IRangeMap rangeMap, boolean ascending) throws AsterixException {
+        // TODO Add support for composite fields.
+        int fieldIndex = 0;
+        int fieldType = rangeMap.getTag(0, 0);
+        AqlBinaryComparatorFactoryProvider comparatorFactory = AqlBinaryComparatorFactoryProvider.INSTANCE;
+        IBinaryComparatorFactory bcf = comparatorFactory.getBinaryComparatorFactory(
+                ATypeTag.VALUE_TYPE_MAPPING[fieldType], ascending);
+        IBinaryComparator comparator = bcf.createBinaryComparator();
+        int c = 0;
+        for (int split = 1; split < rangeMap.getSplitCount(); ++split) {
+            if (fieldType != rangeMap.getTag(fieldIndex, split)) {
+                throw new AsterixException("Range field contains more than a single type of items (" + fieldType
+                        + " and " + rangeMap.getTag(fieldIndex, split) + ").");
+            }
+            int previousSplit = split - 1;
+            try {
+                c = comparator.compare(rangeMap.getByteArray(fieldIndex, previousSplit),
+                        rangeMap.getStartOffset(fieldIndex, previousSplit),
+                        rangeMap.getLength(fieldIndex, previousSplit), rangeMap.getByteArray(fieldIndex, split),
+                        rangeMap.getStartOffset(fieldIndex, split), rangeMap.getLength(fieldIndex, split));
+            } catch (HyracksDataException e) {
+                throw new AsterixException(e);
+            }
+            if (c >= 0) {
+                throw new AsterixException("Range fields are not in sorted order.");
+            }
+        }
+    }
+}
diff --git a/asterix-aql/src/main/javacc/AQL.jj b/asterix-aql/src/main/javacc/AQL.jj
index 7ed63b1..3e64da4 100644
--- a/asterix-aql/src/main/javacc/AQL.jj
+++ b/asterix-aql/src/main/javacc/AQL.jj
@@ -10,45 +10,125 @@
 
 package edu.uci.ics.asterix.aql.parser;
 
-import java.io.*;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-
+// For AQLParserTokenManager
 import org.apache.xerces.util.IntStack;
 
-import edu.uci.ics.asterix.aql.literal.FloatLiteral;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import edu.uci.ics.asterix.aql.base.Clause;
+import edu.uci.ics.asterix.aql.base.Expression;
+import edu.uci.ics.asterix.aql.base.Literal;
+import edu.uci.ics.asterix.aql.base.Statement;
+import edu.uci.ics.asterix.aql.context.RootScopeFactory;
+import edu.uci.ics.asterix.aql.context.Scope;
+import edu.uci.ics.asterix.aql.expression.AbstractAccessor;
+import edu.uci.ics.asterix.aql.expression.CallExpr;
+import edu.uci.ics.asterix.aql.expression.CompactStatement;
+import edu.uci.ics.asterix.aql.expression.ConnectFeedStatement;
+import edu.uci.ics.asterix.aql.expression.CreateDataverseStatement;
+import edu.uci.ics.asterix.aql.expression.CreateFeedStatement;
+import edu.uci.ics.asterix.aql.expression.CreateFunctionStatement;
+import edu.uci.ics.asterix.aql.expression.CreateIndexStatement;
+import edu.uci.ics.asterix.aql.expression.DatasetDecl;
+import edu.uci.ics.asterix.aql.expression.DataverseDecl;
+import edu.uci.ics.asterix.aql.expression.DataverseDropStatement;
+import edu.uci.ics.asterix.aql.expression.DeleteStatement;
+import edu.uci.ics.asterix.aql.expression.DisconnectFeedStatement;
+import edu.uci.ics.asterix.aql.expression.DistinctClause;
+import edu.uci.ics.asterix.aql.expression.DropStatement;
+import edu.uci.ics.asterix.aql.expression.ExternalDetailsDecl;
+import edu.uci.ics.asterix.aql.expression.FLWOGRExpression;
+import edu.uci.ics.asterix.aql.expression.FeedDropStatement;
+import edu.uci.ics.asterix.aql.expression.FieldAccessor;
+import edu.uci.ics.asterix.aql.expression.FieldBinding;
+import edu.uci.ics.asterix.aql.expression.ForClause;
+import edu.uci.ics.asterix.aql.expression.FunctionDecl;
+import edu.uci.ics.asterix.aql.expression.FunctionDropStatement;
+import edu.uci.ics.asterix.aql.expression.GbyVariableExpressionPair;
+import edu.uci.ics.asterix.aql.expression.GroupbyClause;
+import edu.uci.ics.asterix.aql.expression.Identifier;
+import edu.uci.ics.asterix.aql.expression.IfExpr;
+import edu.uci.ics.asterix.aql.expression.IndexAccessor;
+import edu.uci.ics.asterix.aql.expression.IndexDropStatement;
+import edu.uci.ics.asterix.aql.expression.InsertStatement;
+import edu.uci.ics.asterix.aql.expression.InternalDetailsDecl;
+import edu.uci.ics.asterix.aql.expression.LetClause;
+import edu.uci.ics.asterix.aql.expression.LimitClause;
+import edu.uci.ics.asterix.aql.expression.ListConstructor;
+import edu.uci.ics.asterix.aql.expression.LiteralExpr;
+import edu.uci.ics.asterix.aql.expression.LoadStatement;
+import edu.uci.ics.asterix.aql.expression.NodeGroupDropStatement;
+import edu.uci.ics.asterix.aql.expression.NodegroupDecl;
+import edu.uci.ics.asterix.aql.expression.OperatorExpr;
+import edu.uci.ics.asterix.aql.expression.OrderbyClause;
+import edu.uci.ics.asterix.aql.expression.OrderedListTypeDefinition;
+import edu.uci.ics.asterix.aql.expression.QuantifiedExpression;
+import edu.uci.ics.asterix.aql.expression.QuantifiedPair;
+import edu.uci.ics.asterix.aql.expression.Query;
+import edu.uci.ics.asterix.aql.expression.RecordConstructor;
+import edu.uci.ics.asterix.aql.expression.RecordTypeDefinition;
+import edu.uci.ics.asterix.aql.expression.RefreshExternalDatasetStatement;
+import edu.uci.ics.asterix.aql.expression.RunStatement;
+import edu.uci.ics.asterix.aql.expression.SetStatement;
+import edu.uci.ics.asterix.aql.expression.TypeDecl;
+import edu.uci.ics.asterix.aql.expression.TypeDropStatement;
+import edu.uci.ics.asterix.aql.expression.TypeExpression;
+import edu.uci.ics.asterix.aql.expression.TypeReferenceExpression;
+import edu.uci.ics.asterix.aql.expression.UnaryExpr;
+import edu.uci.ics.asterix.aql.expression.UnaryExpr.Sign;
+import edu.uci.ics.asterix.aql.expression.UnionExpr;
+import edu.uci.ics.asterix.aql.expression.UnorderedListTypeDefinition;
+import edu.uci.ics.asterix.aql.expression.UpdateClause;
+import edu.uci.ics.asterix.aql.expression.UpdateStatement;
+import edu.uci.ics.asterix.aql.expression.VarIdentifier;
+import edu.uci.ics.asterix.aql.expression.VariableExpr;
+import edu.uci.ics.asterix.aql.expression.WhereClause;
+import edu.uci.ics.asterix.aql.expression.WriteStatement;
 import edu.uci.ics.asterix.aql.literal.DoubleLiteral;
 import edu.uci.ics.asterix.aql.literal.FalseLiteral;
-import edu.uci.ics.asterix.aql.base.Literal;
-import edu.uci.ics.asterix.aql.literal.IntegerLiteral;
+import edu.uci.ics.asterix.aql.literal.FloatLiteral;
 import edu.uci.ics.asterix.aql.literal.LongIntegerLiteral;
 import edu.uci.ics.asterix.aql.literal.NullLiteral;
 import edu.uci.ics.asterix.aql.literal.StringLiteral;
 import edu.uci.ics.asterix.aql.literal.TrueLiteral;
-import edu.uci.ics.asterix.metadata.bootstrap.MetadataConstants;
-
-import edu.uci.ics.asterix.aql.base.*;
-import edu.uci.ics.asterix.aql.expression.*;
+import edu.uci.ics.asterix.aql.util.RangeMapBuilder;
+import edu.uci.ics.asterix.common.annotations.AutoDataGen;
+import edu.uci.ics.asterix.common.annotations.DateBetweenYearsDataGen;
+import edu.uci.ics.asterix.common.annotations.DatetimeAddRandHoursDataGen;
+import edu.uci.ics.asterix.common.annotations.DatetimeBetweenYearsDataGen;
+import edu.uci.ics.asterix.common.annotations.FieldIntervalDataGen;
+import edu.uci.ics.asterix.common.annotations.FieldValFileDataGen;
+import edu.uci.ics.asterix.common.annotations.FieldValFileSameIndexDataGen;
+import edu.uci.ics.asterix.common.annotations.IRecordFieldDataGen;
+import edu.uci.ics.asterix.common.annotations.InsertRandIntDataGen;
+import edu.uci.ics.asterix.common.annotations.ListDataGen;
+import edu.uci.ics.asterix.common.annotations.ListValFileDataGen;
+import edu.uci.ics.asterix.common.annotations.SkipSecondaryIndexSearchExpressionAnnotation;
+import edu.uci.ics.asterix.common.annotations.TypeDataGen;
+import edu.uci.ics.asterix.common.annotations.UndeclaredFieldsDataGen;
 import edu.uci.ics.asterix.common.config.DatasetConfig.DatasetType;
 import edu.uci.ics.asterix.common.config.DatasetConfig.IndexType;
-import edu.uci.ics.asterix.aql.expression.visitor.AQLPrintVisitor;
-import edu.uci.ics.asterix.aql.expression.UnaryExpr.Sign;
-import edu.uci.ics.asterix.aql.expression.TypeExpression.TypeExprKind;
-import edu.uci.ics.asterix.aql.base.Statement.Kind;
-import edu.uci.ics.asterix.aql.context.Scope;
-import edu.uci.ics.asterix.aql.context.RootScopeFactory;
-import edu.uci.ics.asterix.common.annotations.*;
 import edu.uci.ics.asterix.common.exceptions.AsterixException;
-import edu.uci.ics.asterix.om.functions.AsterixFunction;
 import edu.uci.ics.asterix.common.functions.FunctionSignature;
+import edu.uci.ics.asterix.metadata.bootstrap.MetadataConstants;
+import edu.uci.ics.hyracks.algebricks.common.utils.Pair;
+import edu.uci.ics.hyracks.algebricks.common.utils.Triple;
 import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.IExpressionAnnotation;
 import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.IndexedNLJoinExpressionAnnotation;
 import edu.uci.ics.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
-import edu.uci.ics.hyracks.algebricks.common.utils.Pair;
-import edu.uci.ics.hyracks.algebricks.common.utils.Triple;
+import edu.uci.ics.hyracks.dataflow.common.data.partition.range.IRangeMap;
 
 
 
@@ -56,22 +136,23 @@
 public class AQLParser extends ScopeChecker {
 
     // optimizer hints
-    private static final String HASH_GROUP_BY_HINT = "hash";
-    private static final String SKIP_SECONDARY_INDEX_SEARCH_HINT = "skip-index";
+    private static final String AUTO_HINT = "auto";
     private static final String BROADCAST_JOIN_HINT = "bcast";
-    private static final String INDEXED_NESTED_LOOP_JOIN_HINT = "indexnl";
-    private static final String INMEMORY_HINT = "inmem";
-    private static final String VAL_FILE_HINT = "val-files";
-    private static final String VAL_FILE_SAME_INDEX_HINT = "val-file-same-idx";
-    private static final String INTERVAL_HINT = "interval";
     private static final String COMPOSE_VAL_FILES_HINT = "compose-val-files";
-    private static final String INSERT_RAND_INT_HINT = "insert-rand-int";
-    private static final String LIST_VAL_FILE_HINT = "list-val-file";
-    private static final String LIST_HINT = "list";
-    private static final String DATETIME_BETWEEN_YEARS_HINT = "datetime-between-years";
     private static final String DATE_BETWEEN_YEARS_HINT = "date-between-years";
     private static final String DATETIME_ADD_RAND_HOURS_HINT = "datetime-add-rand-hours";
-    private static final String AUTO_HINT = "auto";
+    private static final String DATETIME_BETWEEN_YEARS_HINT = "datetime-between-years";
+    private static final String HASH_GROUP_BY_HINT = "hash";
+    private static final String INDEXED_NESTED_LOOP_JOIN_HINT = "indexnl";
+    private static final String INMEMORY_HINT = "inmem";
+    private static final String INSERT_RAND_INT_HINT = "insert-rand-int";
+    private static final String INTERVAL_HINT = "interval";
+    private static final String LIST_HINT = "list";
+    private static final String LIST_VAL_FILE_HINT = "list-val-file";
+    private static final String RANGE_HINT = "range";
+    private static final String SKIP_SECONDARY_INDEX_SEARCH_HINT = "skip-index";
+    private static final String VAL_FILE_HINT = "val-files";
+    private static final String VAL_FILE_SAME_INDEX_HINT = "val-file-same-idx";
 
     private static final String GEN_FIELDS_HINT = "gen-fields";
 
@@ -2083,24 +2164,29 @@
 
 Clause OrderbyClause()throws ParseException :
 {
-  OrderbyClause oc = new OrderbyClause();
-  Expression orderbyExpr;
-  List<Expression> orderbyList = new ArrayList<Expression>();
-  List<OrderbyClause.OrderModifier> modifierList = new ArrayList<OrderbyClause.OrderModifier >();
-  int numOfOrderby = 0;
+    OrderbyClause oc = new OrderbyClause();
+    Expression orderbyExpr;
+    List<Expression> orderbyList = new ArrayList<Expression>();
+    List<OrderbyClause.OrderModifier> modifierList = new ArrayList<OrderbyClause.OrderModifier >();
+    int numOfOrderby = 0;
 }
 {
   (
     <ORDER>
       {
-         String hint = getHint(token);
-         if (hint != null && hint.startsWith(INMEMORY_HINT)) {
-           String splits[] = hint.split(" +");
-           int numFrames = Integer.parseInt(splits[1]);
-           int numTuples = Integer.parseInt(splits[2]);
-           oc.setNumFrames(numFrames);
-           oc.setNumTuples(numTuples);
-         }
+        String hint = getHint(token);
+        if (hint != null) {
+          if (hint.startsWith(INMEMORY_HINT)) {
+            String splits[] = hint.split(" +");
+            int numFrames = Integer.parseInt(splits[1]);
+            int numTuples = Integer.parseInt(splits[2]);
+            oc.setNumFrames(numFrames);
+            oc.setNumTuples(numTuples);
+          }
+          if (hint.startsWith(RANGE_HINT)) {
+            oc.setRangeMap(RangeMapBuilder.parseHint(hint.substring(RANGE_HINT.length())));
+          }
+        }
       }
     <BY> orderbyExpr = Expression()
     {