Added support of typed indexes over open fields & indexes over nested fields

Open indexes requires user to provide a type along with a indexed field name.
This type would be enforced for all the indexed records, i.e. index cannot be created if in some records a field with provided name has a different type.
Index-specific rewrite rules match provided type with the inferred types of other arguments in join\select statements and trigger index rewrite.

Nested indexes use the same semantics as the regular indexes, with exception that field could be located arbitrarily deep inside nested structure

Change-Id: I53d00aba243ccf7cf79cf7d775dd305813d24f98
Reviewed-on: http://fulliautomatix.ics.uci.edu:8443/97
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Steven Jacobs <sjaco002@ucr.edu>
diff --git a/asterix-aql/src/main/javacc/AQL.jj b/asterix-aql/src/main/javacc/AQL.jj
index e85b56b..7ed63b1 100644
--- a/asterix-aql/src/main/javacc/AQL.jj
+++ b/asterix-aql/src/main/javacc/AQL.jj
@@ -320,13 +320,13 @@
   Map<String,String> properties = null;
   Map<String,String> compactionPolicyProperties = null;
   FunctionSignature appliedFunction = null;
-  List<String> primaryKeyFields = null;
+  List<List<String>> primaryKeyFields = null;
   String nodeGroupName = null;
   Map<String,String> hints = new HashMap<String,String>();
   DatasetDecl dsetDecl = null;
   boolean autogenerated = false;
   String compactionPolicy = null;
-  String filterField = null;
+  List<String> filterField = null;
 }
 {
   (
@@ -361,7 +361,7 @@
     ("on" nodeGroupName = Identifier() )?
     ( "hints" hints = Properties() )?
     ( "using" "compaction" "policy" compactionPolicy = CompactionPolicy() (compactionPolicyProperties = Configuration())? )?
-    ( "with filter on" filterField = FilterField() )?
+    ( "with filter on" filterField = NestedField() )?
       {
         InternalDetailsDecl idd = new InternalDetailsDecl(nodeGroupName != null
                                                             ? new Identifier(nodeGroupName)
@@ -425,24 +425,25 @@
 {
   CreateIndexStatement cis = new CreateIndexStatement();
   String indexName = null;
-  String fieldExpr = null;
   boolean ifNotExists = false;
   Pair<Identifier,Identifier> nameComponents = null;
+  Pair<List<String>, TypeExpression> fieldPair = null;
   IndexParams indexType = null;
+  boolean enforced = false;
 }
 {
   "index" indexName = Identifier()
   ifNotExists = IfNotExists()
   "on" nameComponents = QualifiedName()
-  <LEFTPAREN> ( fieldExpr = Identifier()
+  <LEFTPAREN> ( fieldPair = OpenField()
     {
-      cis.addFieldExpr(fieldExpr);
+      cis.addFieldExprPair(fieldPair);
     }
-  ) (<COMMA> fieldExpr = Identifier()
+  ) (<COMMA> fieldPair = OpenField()
     {
-      cis.addFieldExpr(fieldExpr);
+      cis.addFieldExprPair(fieldPair);
     }
-  )* <RIGHTPAREN> ( "type" indexType = IndexType() )?
+  )* <RIGHTPAREN> ( "type" indexType = IndexType() )? ( "enforced" { enforced = true; } )?
     {
       cis.setIndexName(new Identifier(indexName));
       cis.setIfNotExists(ifNotExists);
@@ -452,6 +453,7 @@
         cis.setIndexType(indexType.type);
         cis.setGramLength(indexType.gramLength);
       }
+      cis.setEnforced(enforced);
       return cis;
     }
 }
@@ -668,17 +670,17 @@
     }
 }
 
-List<String> PrimaryKey() throws ParseException:
+List<List<String>> PrimaryKey() throws ParseException:
 {
-  String tmp = null;
-  List<String> primaryKeyFields = new ArrayList<String>();
+  List<String> tmp = null;
+  List<List<String>> primaryKeyFields = new ArrayList<List<String>>();
 }
 {
-  "primary" "key" tmp = Identifier()
+  "primary" "key" tmp = NestedField()
     {
       primaryKeyFields.add(tmp);
     }
-  ( <COMMA> tmp = Identifier()
+  ( <COMMA> tmp = NestedField()
     {
       primaryKeyFields.add(tmp);
     }
@@ -1016,6 +1018,21 @@
     }
 }
 
+TypeExpression IndexedTypeExpr() throws ParseException:
+{
+  TypeExpression typeExpr = null;
+}
+{
+  (
+      typeExpr = TypeReference()
+    | typeExpr = OrderedListTypeDef()
+    | typeExpr = UnorderedListTypeDef()
+  )
+  {
+    return typeExpr;
+  }
+}
+
 TypeExpression TypeExpr() throws ParseException:
 {
   TypeExpression typeExpr = null;
@@ -1205,6 +1222,42 @@
     }
 }
 
+Pair<List<String>, TypeExpression> OpenField() throws ParseException:
+{
+  TypeExpression fieldType = null;
+  List<String> fieldList = null;
+}
+{
+  fieldList = NestedField()
+  ( <COLON> fieldType =  IndexedTypeExpr() )?
+  {
+    return new Pair<List<String>, TypeExpression>(fieldList, fieldType);
+  }
+}
+
+List<String> NestedField() throws ParseException:
+{
+  List<String> exprList = new ArrayList<String>();
+  String lit = null;
+}
+{
+  lit = Identifier()
+  {
+    exprList.add(lit);
+  }
+  (<DOT>
+    lit = Identifier()
+    {
+      exprList.add(lit);
+    }
+  )*
+  {
+    return exprList;
+  }
+}
+
+
+
 String StringLiteral() throws ParseException:
 {
 }