Merge branch 'yingyi/asterix_fix'
diff --git a/asterix-app/src/test/resources/runtimets/queries/temporal/day_of_week_01/day_of_week_01.1.ddl.aql b/asterix-app/src/test/resources/runtimets/queries/temporal/day_of_week_01/day_of_week_01.1.ddl.aql
new file mode 100644
index 0000000..f92bdd4
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/queries/temporal/day_of_week_01/day_of_week_01.1.ddl.aql
@@ -0,0 +1,7 @@
+/**
+ * day-of-week test case: test the day-of-week function
+ * Expected result: success
+ **/
+
+drop dataverse test if exists;
+create dataverse test;
\ No newline at end of file
diff --git a/asterix-app/src/test/resources/runtimets/queries/temporal/day_of_week_01/day_of_week_01.2.update.aql b/asterix-app/src/test/resources/runtimets/queries/temporal/day_of_week_01/day_of_week_01.2.update.aql
new file mode 100644
index 0000000..cf8a1ae
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/queries/temporal/day_of_week_01/day_of_week_01.2.update.aql
@@ -0,0 +1,4 @@
+/**
+ * day-of-week test case: test the day-of-week function
+ * Expected result: success
+ **/
\ No newline at end of file
diff --git a/asterix-app/src/test/resources/runtimets/queries/temporal/day_of_week_01/day_of_week_01.3.query.aql b/asterix-app/src/test/resources/runtimets/queries/temporal/day_of_week_01/day_of_week_01.3.query.aql
new file mode 100644
index 0000000..fc1e705
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/queries/temporal/day_of_week_01/day_of_week_01.3.query.aql
@@ -0,0 +1,12 @@
+/**
+ * day-of-week test case: test the day-of-week function
+ * Expected result: success
+ **/
+
+use dataverse test;
+
+let $d1 := date("2013-08-06")
+let $d2 := date("-2013-08-06")
+let $dt1 := datetime("1913-08-06T15:53:28Z")
+let $dt2 := datetime("-1913-08-10T15:53:28Z")
+return { "1970-01-01": day-of-week(date("1970-01-01")), "2013-08-06": day-of-week($d1), "-2013-08-06": day-of-week($d2), "1913-08-06T15:53:28Z": day-of-week($dt1), "-1913-08-10T15:53:28Z": day-of-week($dt2), "null": day-of-week(null) }
\ No newline at end of file
diff --git a/asterix-app/src/test/resources/runtimets/results/temporal/day_of_week_01/day_of_week_01.1.adm b/asterix-app/src/test/resources/runtimets/results/temporal/day_of_week_01/day_of_week_01.1.adm
new file mode 100644
index 0000000..dff4aa2
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/results/temporal/day_of_week_01/day_of_week_01.1.adm
@@ -0,0 +1 @@
+{ "1970-01-01": 4, "2013-08-06": 2, "-2013-08-06": 4, "1913-08-06T15:53:28Z": 3, "-1913-08-10T15:53:28Z": 7, "null": null }
\ 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 50948f2..3a2a44e 100644
--- a/asterix-app/src/test/resources/runtimets/testsuite.xml
+++ b/asterix-app/src/test/resources/runtimets/testsuite.xml
@@ -4343,7 +4343,12 @@
     </test-case>
   </test-group>
   <test-group name="temporal">
-  <test-case FilePath="temporal">
+    <test-case FilePath="temporal">
+     <compilation-unit name="day_of_week_01">
+        <output-dir compare="Text">day_of_week_01</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="temporal">
      <compilation-unit name="interval_bin">
         <output-dir compare="Text">interval_bin</output-dir>
       </compilation-unit>
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/functions/AsterixBuiltinFunctions.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/functions/AsterixBuiltinFunctions.java
index 43c43a3..41cf3c1 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/functions/AsterixBuiltinFunctions.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/functions/AsterixBuiltinFunctions.java
@@ -540,6 +540,8 @@
             FunctionConstants.ASTERIX_NS, "adjust-time-for-timezone", 2);
     public final static FunctionIdentifier ADJUST_DATETIME_FOR_TIMEZONE = new FunctionIdentifier(
             FunctionConstants.ASTERIX_NS, "adjust-datetime-for-timezone", 2);
+    public final static FunctionIdentifier DAY_OF_WEEK = new FunctionIdentifier(FunctionConstants.ASTERIX_NS,
+            "day-of-week");
 
     public final static FunctionIdentifier GET_POINT_X_COORDINATE_ACCESSOR = new FunctionIdentifier(
             FunctionConstants.ASTERIX_NS, "get-x", 1);
@@ -855,6 +857,7 @@
         addFunction(GET_DAY_TIME_DURATION, OptionalADayTimeDurationTypeComputer.INSTANCE);
         addFunction(GET_YEAR_MONTH_DURATION, OptionalAYearMonthDurationTypeComputer.INSTANCE);
         addFunction(INTERVAL_BIN, OptionalAIntervalTypeComputer.INSTANCE);
+        addFunction(DAY_OF_WEEK, OptionalAInt32TypeComputer.INSTANCE);
 
         // interval constructors
         addFunction(INTERVAL_CONSTRUCTOR_DATE, OptionalAIntervalTypeComputer.INSTANCE);
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/DayOfWeekDescriptor.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/DayOfWeekDescriptor.java
new file mode 100644
index 0000000..11ba264
--- /dev/null
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/DayOfWeekDescriptor.java
@@ -0,0 +1,150 @@
+/*
+ * 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.runtime.evaluators.functions.temporal;
+
+import java.io.DataOutput;
+
+import edu.uci.ics.asterix.dataflow.data.nontagged.serde.ADateSerializerDeserializer;
+import edu.uci.ics.asterix.dataflow.data.nontagged.serde.ADateTimeSerializerDeserializer;
+import edu.uci.ics.asterix.formats.nontagged.AqlSerializerDeserializerProvider;
+import edu.uci.ics.asterix.om.base.AInt32;
+import edu.uci.ics.asterix.om.base.AMutableInt32;
+import edu.uci.ics.asterix.om.base.ANull;
+import edu.uci.ics.asterix.om.base.temporal.GregorianCalendarSystem;
+import edu.uci.ics.asterix.om.functions.AsterixBuiltinFunctions;
+import edu.uci.ics.asterix.om.functions.IFunctionDescriptor;
+import edu.uci.ics.asterix.om.functions.IFunctionDescriptorFactory;
+import edu.uci.ics.asterix.om.types.ATypeTag;
+import edu.uci.ics.asterix.om.types.BuiltinType;
+import edu.uci.ics.asterix.om.types.EnumDeserializer;
+import edu.uci.ics.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+import edu.uci.ics.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import edu.uci.ics.hyracks.algebricks.runtime.base.ICopyEvaluator;
+import edu.uci.ics.hyracks.algebricks.runtime.base.ICopyEvaluatorFactory;
+import edu.uci.ics.hyracks.api.dataflow.value.ISerializerDeserializer;
+import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
+import edu.uci.ics.hyracks.data.std.api.IDataOutputProvider;
+import edu.uci.ics.hyracks.data.std.util.ArrayBackedValueStorage;
+import edu.uci.ics.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+
+public class DayOfWeekDescriptor extends AbstractScalarFunctionDynamicDescriptor {
+
+    private static final long serialVersionUID = 1L;
+    public final static FunctionIdentifier FID = AsterixBuiltinFunctions.DAY_OF_WEEK;
+
+    // allowed input types
+    private final static byte SER_NULL_TYPE_TAG = ATypeTag.NULL.serialize();
+    private final static byte SER_DATETIME_TYPE_TAG = ATypeTag.DATETIME.serialize();
+    private final static byte SER_DATE_TYPE_TAG = ATypeTag.DATE.serialize();
+
+    // Fixed week day anchor: Thursday, 1 January 1970
+    private final static int ANCHOR_WEEKDAY = 4;
+
+    public final static IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() {
+
+        @Override
+        public IFunctionDescriptor createFunctionDescriptor() {
+            return new DayOfWeekDescriptor();
+        }
+
+    };
+
+    @Override
+    public ICopyEvaluatorFactory createEvaluatorFactory(final ICopyEvaluatorFactory[] args) throws AlgebricksException {
+        return new ICopyEvaluatorFactory() {
+
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public ICopyEvaluator createEvaluator(final IDataOutputProvider output) throws AlgebricksException {
+                return new ICopyEvaluator() {
+
+                    private DataOutput out = output.getDataOutput();
+                    private ArrayBackedValueStorage argOut = new ArrayBackedValueStorage();
+                    private ICopyEvaluator eval = args[0].createEvaluator(argOut);
+
+                    // possible returning types
+                    @SuppressWarnings("unchecked")
+                    private ISerializerDeserializer<AInt32> int32Serde = AqlSerializerDeserializerProvider.INSTANCE
+                            .getSerializerDeserializer(BuiltinType.AINT32);
+                    private AMutableInt32 aInt32 = new AMutableInt32(0);
+
+                    @SuppressWarnings("unchecked")
+                    private ISerializerDeserializer<ANull> nullSerde = AqlSerializerDeserializerProvider.INSTANCE
+                            .getSerializerDeserializer(BuiltinType.ANULL);
+
+                    @Override
+                    public void evaluate(IFrameTupleReference tuple) throws AlgebricksException {
+                        argOut.reset();
+                        eval.evaluate(tuple);
+                        try {
+                            if (argOut.getByteArray()[0] == SER_NULL_TYPE_TAG) {
+                                nullSerde.serialize(ANull.NULL, out);
+                            } else {
+                                int daysSinceAnchor;
+                                int reminder = 0;
+                                if (argOut.getByteArray()[0] == SER_DATETIME_TYPE_TAG) {
+                                    daysSinceAnchor = (int) (ADateTimeSerializerDeserializer.getChronon(
+                                            argOut.getByteArray(), 1) / GregorianCalendarSystem.CHRONON_OF_DAY);
+                                    reminder = (int) (ADateTimeSerializerDeserializer.getChronon(argOut.getByteArray(),
+                                            1) % GregorianCalendarSystem.CHRONON_OF_DAY);
+                                } else if (argOut.getByteArray()[0] == SER_DATE_TYPE_TAG) {
+                                    daysSinceAnchor = ADateSerializerDeserializer.getChronon(argOut.getByteArray(), 1);
+                                } else {
+                                    throw new AlgebricksException(
+                                            FID.getName()
+                                                    + ": expects input type DATETIME/DATE/NULL but got "
+                                                    + EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(argOut
+                                                            .getByteArray()[0]));
+                                }
+
+                                // adjust the day before 1970-01-01
+                                if (daysSinceAnchor < 0 && reminder != 0) {
+                                    daysSinceAnchor -= 1;
+                                }
+
+                                // compute the weekday (0-based, and 0 = Sunday). Adjustment is needed as the anchor day is Thursday 
+                                int weekday = (daysSinceAnchor + ANCHOR_WEEKDAY) % 7;
+
+                                // handle the negative weekday
+                                if (weekday < 0) {
+                                    weekday += 7;
+                                }
+
+                                // convert from 0-based to 1-based (so 7 = Sunday)
+                                if (weekday == 0) {
+                                    weekday = 7;
+                                }
+
+                                aInt32.setValue(weekday);
+
+                                int32Serde.serialize(aInt32, out);
+                            }
+                        } catch (HyracksDataException hex) {
+                            throw new AlgebricksException(hex);
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public FunctionIdentifier getIdentifier() {
+        return FID;
+    }
+
+}
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/formats/NonTaggedDataFormat.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/formats/NonTaggedDataFormat.java
index 47555bd..a13eed3 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/formats/NonTaggedDataFormat.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/formats/NonTaggedDataFormat.java
@@ -222,6 +222,7 @@
 import edu.uci.ics.asterix.runtime.evaluators.functions.temporal.DateFromUnixTimeInDaysDescriptor;
 import edu.uci.ics.asterix.runtime.evaluators.functions.temporal.DatetimeFromDateAndTimeDescriptor;
 import edu.uci.ics.asterix.runtime.evaluators.functions.temporal.DatetimeFromUnixTimeInMsDescriptor;
+import edu.uci.ics.asterix.runtime.evaluators.functions.temporal.DayOfWeekDescriptor;
 import edu.uci.ics.asterix.runtime.evaluators.functions.temporal.DayTimeDurationComparatorDescriptor;
 import edu.uci.ics.asterix.runtime.evaluators.functions.temporal.DurationEqualDescriptor;
 import edu.uci.ics.asterix.runtime.evaluators.functions.temporal.DurationFromMillisecondsDescriptor;
@@ -539,6 +540,7 @@
         temp.add(GetYearMonthDurationDescriptor.FACTORY);
         temp.add(GetDayTimeDurationDescriptor.FACTORY);
         temp.add(IntervalBinDescriptor.FACTORY);
+        temp.add(DayOfWeekDescriptor.FACTORY);
 
         // Interval constructor
         temp.add(AIntervalFromDateConstructorDescriptor.FACTORY);