Fixed issue 152.
git-svn-id: https://asterixdb.googlecode.com/svn/branches/asterix_stabilization@601 eaa15691-b419-025a-1212-ee371bd00084
diff --git a/asterix-app/src/test/resources/runtimets/queries/string/concat1.aql b/asterix-app/src/test/resources/runtimets/queries/string/concat_01.aql
similarity index 81%
rename from asterix-app/src/test/resources/runtimets/queries/string/concat1.aql
rename to asterix-app/src/test/resources/runtimets/queries/string/concat_01.aql
index a6ce63b..2a0b1ab 100644
--- a/asterix-app/src/test/resources/runtimets/queries/string/concat1.aql
+++ b/asterix-app/src/test/resources/runtimets/queries/string/concat_01.aql
@@ -2,7 +2,7 @@
create dataverse test;
use dataverse test;
-write output to nc1:"rttest/string_concat1.adm";
+write output to nc1:"rttest/string_concat_01.adm";
let $x := ["aa", "25991", "bb", "31526"]
let $c := string-concat($x)
diff --git a/asterix-app/src/test/resources/runtimets/queries/string/concat_02.aql b/asterix-app/src/test/resources/runtimets/queries/string/concat_02.aql
new file mode 100644
index 0000000..c716fcb
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/queries/string/concat_02.aql
@@ -0,0 +1,15 @@
+/*
+ * Description : Test concat-string function with nulls in the list which is passed as an argument.
+ * Success : Yes
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+write output to nc1:"rttest/string_concat_02.adm";
+
+let $a := string-concat([null])
+let $b := string-concat([null, "foo"])
+let $c := string-concat(["foo", null])
+return {"a": $a, "b": $b, "c": $c}
\ No newline at end of file
diff --git a/asterix-app/src/test/resources/runtimets/results/string/concat1.adm b/asterix-app/src/test/resources/runtimets/results/string/concat_01.adm
similarity index 100%
rename from asterix-app/src/test/resources/runtimets/results/string/concat1.adm
rename to asterix-app/src/test/resources/runtimets/results/string/concat_01.adm
diff --git a/asterix-app/src/test/resources/runtimets/results/string/concat_02.adm b/asterix-app/src/test/resources/runtimets/results/string/concat_02.adm
new file mode 100644
index 0000000..ba4be9f
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/results/string/concat_02.adm
@@ -0,0 +1 @@
+{ "a": null, "b": null, "c": null }
\ No newline at end of file
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 e95cb6f..552a093 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
@@ -9,6 +9,7 @@
import org.apache.commons.lang3.mutable.Mutable;
import edu.uci.ics.asterix.common.functions.FunctionConstants;
+import edu.uci.ics.asterix.dataflow.data.common.AqlNullableTypeComputer;
import edu.uci.ics.asterix.om.typecomputer.base.IResultTypeComputer;
import edu.uci.ics.asterix.om.typecomputer.impl.ABooleanTypeComputer;
import edu.uci.ics.asterix.om.typecomputer.impl.ACircleTypeComputer;
@@ -530,7 +531,7 @@
add(STRING_TO_CODEPOINT, OrderedListOfAInt32TypeComputer.INSTANCE);
add(CODEPOINT_TO_STRING, AStringTypeComputer.INSTANCE);
- add(STRING_CONCAT, AStringTypeComputer.INSTANCE);
+ add(STRING_CONCAT, OptionalAStringTypeComputer.INSTANCE);
add(SUBSTRING2, Substring2TypeComputer.INSTANCE);
add(STRING_LENGTH, UnaryStringInt32OrNullTypeComputer.INSTANCE);
add(STRING_LOWERCASE, UnaryStringOrNullTypeComputer.INSTANCE);
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/StringConcatDescriptor.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/StringConcatDescriptor.java
index 1c2cee7..2b53f35 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/StringConcatDescriptor.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/StringConcatDescriptor.java
@@ -1,18 +1,20 @@
package edu.uci.ics.asterix.runtime.evaluators.functions;
+import java.io.DataOutput;
+import java.io.IOException;
+
import edu.uci.ics.asterix.common.exceptions.AsterixException;
import edu.uci.ics.asterix.common.functions.FunctionConstants;
-import edu.uci.ics.asterix.dataflow.data.nontagged.serde.AOrderedListSerializerDeserializer;
import edu.uci.ics.asterix.formats.nontagged.AqlSerializerDeserializerProvider;
import edu.uci.ics.asterix.om.base.ANull;
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.core.algebra.functions.FunctionIdentifier;
+import edu.uci.ics.asterix.runtime.evaluators.common.AsterixListAccessor;
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;
@@ -21,8 +23,6 @@
import edu.uci.ics.hyracks.data.std.util.ArrayBackedValueStorage;
import edu.uci.ics.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
import edu.uci.ics.hyracks.dataflow.common.data.util.StringUtils;
-import java.io.DataOutput;
-import java.io.IOException;
/**
* @author Xiaoyu Ma
@@ -37,24 +37,22 @@
return new StringConcatDescriptor();
}
};
- private final static byte SER_NULL_TYPE_TAG = ATypeTag.NULL.serialize();
- private final static byte SER_ORDEREDLIST_TYPE_TAG = ATypeTag.ORDEREDLIST.serialize();
- private final byte stringTypeTag = ATypeTag.STRING.serialize();
-
+
@Override
public ICopyEvaluatorFactory createEvaluatorFactory(final ICopyEvaluatorFactory[] args) {
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 ICopyEvaluatorFactory listEvalFactory = args[0];
- private ArrayBackedValueStorage outInputList = new ArrayBackedValueStorage();
- private ICopyEvaluator evalList = listEvalFactory.createEvaluator(outInputList);
+ private final AsterixListAccessor listAccessor = new AsterixListAccessor();
+ private final DataOutput out = output.getDataOutput();
+ private final ICopyEvaluatorFactory listEvalFactory = args[0];
+ private final ArrayBackedValueStorage outInputList = new ArrayBackedValueStorage();
+ private final ICopyEvaluator evalList = listEvalFactory.createEvaluator(outInputList);
@SuppressWarnings("unchecked")
private ISerializerDeserializer<ANull> nullSerde = AqlSerializerDeserializerProvider.INSTANCE
.getSerializerDeserializer(BuiltinType.ANULL);
@@ -64,32 +62,39 @@
try {
outInputList.reset();
evalList.evaluate(tuple);
- byte[] serOrderedList = outInputList.getByteArray();
- if (serOrderedList[0] == SER_NULL_TYPE_TAG) {
+ byte[] listBytes = outInputList.getByteArray();
+ try {
+ listAccessor.reset(listBytes, 0);
+ } catch (AsterixException e) {
+ throw new AlgebricksException(e);
+ }
+ if (listAccessor.getItemType() == ATypeTag.NULL) {
nullSerde.serialize(ANull.NULL, out);
return;
}
- if (serOrderedList[0] != SER_ORDEREDLIST_TYPE_TAG) {
- throw new AlgebricksException("Expects String List."
- + EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(serOrderedList[0]));
- }
- int size = AOrderedListSerializerDeserializer.getNumberOfItems(serOrderedList);
try {
// calculate length first
- int utf_8_len = 0;
- for (int i = 0; i < size; i++) {
- int itemOffset = AOrderedListSerializerDeserializer
- .getItemOffset(serOrderedList, i);
- utf_8_len += UTF8StringPointable.getUTFLength(serOrderedList, itemOffset);
+ int utf8Len = 0;
+ for (int i = 0; i < listAccessor.size(); i++) {
+ int itemOffset = listAccessor.getItemOffset(i);
+ ATypeTag itemType = listAccessor.getItemType(itemOffset);
+ if (itemType != ATypeTag.STRING) {
+ if (itemType == ATypeTag.NULL) {
+ nullSerde.serialize(ANull.NULL, out);
+ return;
+ }
+ throw new AlgebricksException("Unsupported type " + itemType
+ + " in list passed to string-concat function.");
+ }
+ utf8Len += UTF8StringPointable.getUTFLength(listBytes, itemOffset);
}
- out.writeByte(stringTypeTag);
- StringUtils.writeUTF8Len(utf_8_len, out);
- for (int i = 0; i < size; i++) {
- int itemOffset = AOrderedListSerializerDeserializer
- .getItemOffset(serOrderedList, i);
- utf_8_len = UTF8StringPointable.getUTFLength(serOrderedList, itemOffset);
- for (int j = 0; j < utf_8_len; j++) {
- out.writeByte(serOrderedList[2 + itemOffset + j]);
+ out.writeByte(ATypeTag.STRING.serialize());
+ StringUtils.writeUTF8Len(utf8Len, out);
+ for (int i = 0; i < listAccessor.size(); i++) {
+ int itemOffset = listAccessor.getItemOffset(i);
+ utf8Len = UTF8StringPointable.getUTFLength(listBytes, itemOffset);
+ for (int j = 0; j < utf8Len; j++) {
+ out.writeByte(listBytes[2 + itemOffset + j]);
}
}
} catch (AsterixException ex) {