Fixed issue 207. Thanks for the review, Yingyi.

git-svn-id: https://asterixdb.googlecode.com/svn/branches/asterix_stabilization@1016 eaa15691-b419-025a-1212-ee371bd00084
diff --git a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/base/FuzzyUtils.java b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/base/FuzzyUtils.java
index 89d78f2..baf16c2 100644
--- a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/base/FuzzyUtils.java
+++ b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/base/FuzzyUtils.java
@@ -35,6 +35,7 @@
                 return AsterixBuiltinFunctions.COUNTHASHED_WORD_TOKENS;
             case UNORDEREDLIST:
             case ORDEREDLIST:
+            case ANY:
                 return null;
             default:
                 throw new NotImplementedException("No tokenizer for type " + inputTag);
diff --git a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/FuzzyEqRule.java b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/FuzzyEqRule.java
index 77c719d..345f68a 100644
--- a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/FuzzyEqRule.java
+++ b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/FuzzyEqRule.java
@@ -99,9 +99,16 @@
                     inputExprTypes.add(t.getTypeTag());
                 } else if (inputExp.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
                     // Hack to make sure that we will add the func call as is, without wrapping a tokenizer around.
-                    inputTypeTag = ATypeTag.UNORDEREDLIST;
+                    IAType type = (IAType) context.getExpressionTypeComputer().getType(inputExp, metadataProvider, env);
+                    inputTypeTag = type.getTypeTag();
+                    // Only auto-tokenize strings.
+                    if (inputTypeTag == ATypeTag.STRING) {
+                        // Strings will be auto-tokenized.
+                        inputTypeTag = ATypeTag.UNORDEREDLIST;
+                    } else {
+                        useExprAsIs = true;
+                    }
                     inputExprTypes.add(inputTypeTag);
-                    useExprAsIs = true;
                 } else if (inputExp.getExpressionTag() == LogicalExpressionTag.CONSTANT) {
                     ConstantExpression inputConst = (ConstantExpression) inputExp;
                     AsterixConstantValue constVal = (AsterixConstantValue) inputConst.getValue();
diff --git a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/FuzzyJoinRule.java b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/FuzzyJoinRule.java
index 035f1df..8936425 100644
--- a/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/FuzzyJoinRule.java
+++ b/asterix-algebra/src/main/java/edu/uci/ics/asterix/optimizer/rules/FuzzyJoinRule.java
@@ -191,6 +191,10 @@
 
         List<LogicalVariable> leftInputPKs = context.findPrimaryKey(leftInputVar);
         List<LogicalVariable> rightInputPKs = context.findPrimaryKey(rightInputVar);
+        // Bail if primary keys could not be inferred.
+        if (leftInputPKs == null || rightInputPKs == null) {
+            return false;
+        }
         // primary key has only one variable
         if (leftInputPKs.size() != 1 || rightInputPKs.size() != 1) {
             return false;
diff --git a/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-aqlplus_2.aql b/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-aqlplus_2.aql
new file mode 100644
index 0000000..7bf7d5f
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/queries/fuzzyjoin/dblp-aqlplus_2.aql
@@ -0,0 +1,32 @@
+/*
+ * Description    : Tests that a proper error messags is returned for this scenario.
+ *                  Since we cannot statically know the type of the field 'title', the FuzzyEqRule
+ *                  cannot auto-inject a tokenizer, and hence we expect an error saying that we cannot
+ *                  scan over a string as if it were a collection.
+ *                  Guards against regression to issue 207.
+ * Success        : Yes
+ */
+
+drop dataverse fuzzyjoin if exists;
+create dataverse fuzzyjoin;
+use dataverse fuzzyjoin;
+
+create type DBLPType as open {
+  id: int32
+}
+
+create dataset DBLP(DBLPType) partitioned by key id;
+
+load dataset DBLP 
+using "edu.uci.ics.asterix.external.dataset.adapter.NCFileSystemAdapter"
+(("path"="nc1://data/dblp-small/dblp-small.adm"),("format"="adm"));
+
+write output to nc1:'rttest/fuzzyjoin_dblp-aqlplus_2.adm';
+
+set simthreshold '.5f';
+
+for $dblp in dataset('DBLP')
+for $dblp2 in dataset('DBLP')
+where $dblp.title ~= $dblp2.title and $dblp.id < $dblp2.id
+order by $dblp.id, $dblp2.id
+return {'dblp': $dblp, 'dblp2': $dblp2}
diff --git a/asterix-app/src/test/resources/runtimets/queries/records/field-access-on-open-field.aql b/asterix-app/src/test/resources/runtimets/queries/records/field-access-on-open-field.aql
new file mode 100644
index 0000000..2592c67
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/queries/records/field-access-on-open-field.aql
@@ -0,0 +1,24 @@
+/*
+ * Description    : Tests whether a field access on an open field (statically of type ANY) succeeds.
+ *                  Guards against regression to issue 207.
+ * Success        : Yes
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+create type TestType as open {
+  id : int32,
+  name : string
+}
+
+create dataset testds(TestType) partitioned by key id;
+
+insert into dataset testds({"id": 123, "name": "John Doe", "address": { "zip": 92617} });
+
+write output to nc1:"rttest/records_field-access-on-open-field.adm";
+
+for $l in dataset("testds")
+let $a := $l.address
+return $a.zip
\ No newline at end of file
diff --git a/asterix-app/src/test/resources/runtimets/results/fuzzyjoin/dblp-aqlplus_2.adm b/asterix-app/src/test/resources/runtimets/results/fuzzyjoin/dblp-aqlplus_2.adm
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/results/fuzzyjoin/dblp-aqlplus_2.adm
diff --git a/asterix-app/src/test/resources/runtimets/results/records/field-access-on-open-field.adm b/asterix-app/src/test/resources/runtimets/results/records/field-access-on-open-field.adm
new file mode 100644
index 0000000..d4edf93
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/results/records/field-access-on-open-field.adm
@@ -0,0 +1 @@
+92617
\ No newline at end of file
diff --git a/asterix-app/src/test/resources/runtimets/testsuite.xml b/asterix-app/src/test/resources/runtimets/testsuite.xml
index 145ef62..2d740be 100644
--- a/asterix-app/src/test/resources/runtimets/testsuite.xml
+++ b/asterix-app/src/test/resources/runtimets/testsuite.xml
@@ -1474,6 +1474,12 @@
       </compilation-unit>
     </test-case>
     <test-case FilePath="fuzzyjoin">
+      <compilation-unit name="dblp-aqlplus_2">
+        <output-file compare="Text">dblp-aqlplus_2.adm</output-file>
+        <expected-error>edu.uci.ics.asterix.common.exceptions.AsterixException</expected-error>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="fuzzyjoin">
       <compilation-unit name="dblp-csx-2_1">
         <output-file compare="Text">dblp-csx-2_1.adm</output-file>
       </compilation-unit>
@@ -2561,6 +2567,11 @@
       </compilation-unit>
     </test-case>
     <test-case FilePath="records">
+      <compilation-unit name="field-access-on-open-field">
+        <output-file compare="Text">field-access-on-open-field.adm</output-file>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="records">
       <compilation-unit name="open-record-constructor_01">
         <output-file compare="Text">open-record-constructor_01.adm</output-file>
       </compilation-unit>
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/FieldAccessByIndexResultType.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/FieldAccessByIndexResultType.java
index dbe338d..d4b11fa 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/FieldAccessByIndexResultType.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/FieldAccessByIndexResultType.java
@@ -38,6 +38,9 @@
         }
         IAType type0 = (IAType) obj;
         ARecordType t0 = NonTaggedFieldAccessByNameResultType.getRecordTypeFromType(type0, expression);
+        if (t0 == null) {
+            return BuiltinType.ANY;
+        }
         ILogicalExpression arg1 = f.getArguments().get(1).getValue();
         if (arg1.getExpressionTag() != LogicalExpressionTag.CONSTANT) {
             return BuiltinType.ANY;
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/NonTaggedFieldAccessByNameResultType.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/NonTaggedFieldAccessByNameResultType.java
index 4b8b32a..a0c35b6 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/NonTaggedFieldAccessByNameResultType.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/typecomputer/impl/NonTaggedFieldAccessByNameResultType.java
@@ -9,7 +9,6 @@
 import edu.uci.ics.asterix.om.types.BuiltinType;
 import edu.uci.ics.asterix.om.types.IAType;
 import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
-import edu.uci.ics.hyracks.algebricks.common.exceptions.NotImplementedException;
 import edu.uci.ics.hyracks.algebricks.core.algebra.base.ILogicalExpression;
 import edu.uci.ics.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
 import edu.uci.ics.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
@@ -36,6 +35,9 @@
         }
         IAType type0 = (IAType) obj;
         ARecordType t0 = getRecordTypeFromType(type0, expression);
+        if (t0 == null) {
+            return BuiltinType.ANY;
+        }
 
         AbstractLogicalExpression arg1 = (AbstractLogicalExpression) f.getArguments().get(1).getValue();
         if (arg1.getExpressionTag() != LogicalExpressionTag.CONSTANT) {
@@ -58,7 +60,7 @@
                 return (ARecordType) type0;
             }
             case ANY: {
-                throw new NotImplementedException();
+                return null;
             }
             case UNION: {
                 AUnionType u = (AUnionType) type0;
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/common/AsterixListAccessor.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/common/AsterixListAccessor.java
index fd6b691..58cbd07 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/common/AsterixListAccessor.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/common/AsterixListAccessor.java
@@ -51,7 +51,7 @@
 	public void reset(byte[] listBytes, int start) throws AsterixException {
 		this.listBytes = listBytes;
 		this.start = start;
-		listType = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(listBytes[start]);		
+		listType = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(listBytes[start]);
 		if (listType != ATypeTag.UNORDEREDLIST && listType != ATypeTag.ORDEREDLIST) {
 			throw new AsterixException("Unsupported type: " + listType);
 		}