Ali Alsuliman has uploaded a new change for review. https://asterix-gerrit.ics.uci.edu/2738
Change subject: [NO ISSUE][FUN] Implement array_insert() function ...................................................................... [NO ISSUE][FUN] Implement array_insert() function - user model changes: no - storage format changes: no - interface changes: no details: This is part of implementing array functions. Change-Id: I57d53f63086da7e9b3412bb12f9901f5f2088c54 --- A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.1.ddl.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.2.update.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.3.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.4.ddl.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_insert/array_insert.3.adm M asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml M asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java A asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AbstractAListOrNullTypeComputer.java M asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayAppendTypeComputer.java A asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayInsertTypeComputer.java A asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayInsertDescriptor.java M asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java M asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java 13 files changed, 445 insertions(+), 36 deletions(-) git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb refs/changes/38/2738/1 diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.1.ddl.sqlpp new file mode 100755 index 0000000..257c4dd --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.1.ddl.sqlpp @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 at + * + * 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. + */ + +drop dataverse TinySocial if exists; +create dataverse TinySocial; + +use TinySocial; + + +create type TinySocial.TwitterUserType as +{ + `screen-name` : string, + lang : string, + friends_count : bigint, + statuses_count : bigint, + name : string, + followers_count : bigint +}; + +create type TinySocial.TweetMessageType as + closed { + tweetid : string, + user : TwitterUserType, + `sender-location` : point?, + `send-time` : datetime, + `referred-topics` : {{string}}, + `message-text` : string +}; + +create dataset TweetMessages(TweetMessageType) primary key tweetid hints (`CARDINALITY`=`100`); \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.2.update.sqlpp new file mode 100755 index 0000000..4a0e7ed --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.2.update.sqlpp @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 at + * + * 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. + */ + +use TinySocial; + +load dataset TweetMessages using localfs ((`path`=`asterix_nc1://data/tinysocial/twm.adm`),(`format`=`adm`)); diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.3.query.sqlpp new file mode 100755 index 0000000..9118fdc --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.3.query.sqlpp @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 at + * + * 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. + */ + +use TinySocial; + +{ + "t1": (array_insert([1,2,3], 0, "a")), + "t2": (array_insert([1,2,3], 3, "a")), + "t3": (array_insert([1,1,2,4], 3, "a")), + "t4": (array_insert([1,2,3], 4, "a")), // should be null + "t5": (array_insert([1,2,3], -1, "a")), + "t6": (array_insert([1,2,3], -4, "a")), // should be null + "t7": (array_insert("non_array", 5, "val")), // should be null + "t8": (array_insert("non_array", 5, missing)), + "t9": (array_insert([], 5, 10, 12.0, "sth")), // should be null + "t10": (array_insert([6], "a", 9)), // should be null + "t11": (array_insert(null, 3, 9)), + "t12": (select array_insert(t.`referred-topics`, 0, 5) from TweetMessages t order by t.tweetid) +}; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.4.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.4.ddl.sqlpp new file mode 100755 index 0000000..3f8c8ec --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_insert/array_insert.4.ddl.sqlpp @@ -0,0 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 at + * + * 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. + */ + +drop dataverse TinySocial; \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_insert/array_insert.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_insert/array_insert.3.adm new file mode 100644 index 0000000..f47af9b --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_insert/array_insert.3.adm @@ -0,0 +1 @@ +{ "t1": [ "a", 1, 2, 3 ], "t2": [ 1, 2, 3, "a" ], "t3": [ 1, 1, 2, "a", 4 ], "t4": null, "t5": [ 1, 2, "a", 3 ], "t6": null, "t7": null, "t9": null, "t10": null, "t11": null, "t12": [ { "$1": {{ 5, "t-mobile", "customization" }} }, { "$1": {{ 5, "verizon", "voice-clarity" }} }, { "$1": {{ 5, "iphone", "platform" }} }, { "$1": {{ 5, "samsung", "voice-command" }} }, { "$1": {{ 5, "verizon", "shortcut-menu" }} }, { "$1": {{ 5, "motorola", "speed" }} }, { "$1": {{ 5, "sprint", "voice-command" }} }, { "$1": {{ 5, "motorola", "speed" }} }, { "$1": {{ 5, "iphone", "voice-clarity" }} }, { "$1": {{ 5, "samsung", "platform" }} }, { "$1": {{ 5, "t-mobile", "shortcut-menu" }} }, { "$1": {{ 5, "verizon", "voicemail-service" }} } ] } diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml index a806bf6..cea6aa5 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml +++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml @@ -1012,6 +1012,11 @@ <expected-error>HYR0115: Cannot compare non-primitive values (in line 22, at column 8)</expected-error> </compilation-unit> </test-case> + <test-case FilePath="array_fun"> + <compilation-unit name="array_insert"> + <output-dir compare="Text">array_insert</output-dir> + </compilation-unit> + </test-case> </test-group> <test-group name="boolean"> <test-case FilePath="boolean"> diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java index da45e29..0e24bfa 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java @@ -55,6 +55,7 @@ import org.apache.asterix.om.typecomputer.impl.AYearMonthDurationTypeComputer; import org.apache.asterix.om.typecomputer.impl.AnyTypeComputer; import org.apache.asterix.om.typecomputer.impl.ArrayAppendTypeComputer; +import org.apache.asterix.om.typecomputer.impl.ArrayInsertTypeComputer; import org.apache.asterix.om.typecomputer.impl.ArrayRepeatTypeComputer; import org.apache.asterix.om.typecomputer.impl.BooleanFunctionTypeComputer; import org.apache.asterix.om.typecomputer.impl.BooleanOnlyTypeComputer; @@ -194,6 +195,8 @@ new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-reverse", 1); public static final FunctionIdentifier ARRAY_CONTAINS = new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-contains", 2); + public static final FunctionIdentifier ARRAY_INSERT = + new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "array-insert", FunctionIdentifier.VARARGS); // objects public static final FunctionIdentifier RECORD_MERGE = @@ -1475,6 +1478,7 @@ addFunction(ARRAY_REPEAT, ArrayRepeatTypeComputer.INSTANCE, true); addFunction(ARRAY_REVERSE, AListTypeComputer.INSTANCE, true); addFunction(ARRAY_CONTAINS, ABooleanTypeComputer.INSTANCE, true); + addFunction(ARRAY_INSERT, ArrayInsertTypeComputer.INSTANCE, true); // objects addFunction(RECORD_MERGE, RecordMergeTypeComputer.INSTANCE, true); diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AbstractAListOrNullTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AbstractAListOrNullTypeComputer.java new file mode 100755 index 0000000..ae5d9d5 --- /dev/null +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/AbstractAListOrNullTypeComputer.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 at + * + * 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 org.apache.asterix.om.typecomputer.impl; + +import org.apache.asterix.common.exceptions.CompilationException; +import org.apache.asterix.common.exceptions.ErrorCode; +import org.apache.asterix.om.pointables.base.DefaultOpenFieldType; +import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer; +import org.apache.asterix.om.types.ATypeTag; +import org.apache.asterix.om.types.AUnionType; +import org.apache.asterix.om.types.BuiltinType; +import org.apache.asterix.om.types.IAType; +import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; +import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; +import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression; + +public abstract class AbstractAListOrNullTypeComputer extends AbstractResultTypeComputer { + private final int minNumArgs; + + protected AbstractAListOrNullTypeComputer(int minNumArgs) { + this.minNumArgs = minNumArgs; + } + + @Override + protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException { + if (strippedInputTypes.length < minNumArgs) { + String functionName = ((AbstractFunctionCallExpression) expr).getFunctionIdentifier().getName(); + throw new CompilationException(ErrorCode.COMPILATION_INVALID_NUM_OF_ARGS, expr.getSourceLocation(), + minNumArgs, functionName); + } + // output type should be the same as as the type tag at [0] which is array or multiset but "open" but it's + // nullable since the output could be null due to other invalid arguments or the tag at [0] itself is not list + ATypeTag typeTag = strippedInputTypes[0].getTypeTag(); + if (typeTag == ATypeTag.ARRAY) { + return AUnionType.createNullableType(DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE); + } else if (typeTag == ATypeTag.MULTISET) { + return AUnionType.createNullableType(DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE); + } else { + return BuiltinType.ANY; + } + } +} diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayAppendTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayAppendTypeComputer.java index f2fed42..a8193f1 100755 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayAppendTypeComputer.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayAppendTypeComputer.java @@ -19,36 +19,11 @@ package org.apache.asterix.om.typecomputer.impl; -import org.apache.asterix.common.exceptions.CompilationException; -import org.apache.asterix.common.exceptions.ErrorCode; -import org.apache.asterix.om.pointables.base.DefaultOpenFieldType; -import org.apache.asterix.om.typecomputer.base.AbstractResultTypeComputer; -import org.apache.asterix.om.types.ATypeTag; -import org.apache.asterix.om.types.BuiltinType; -import org.apache.asterix.om.types.IAType; -import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; -import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression; -import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression; - -public class ArrayAppendTypeComputer extends AbstractResultTypeComputer { +public class ArrayAppendTypeComputer extends AbstractAListOrNullTypeComputer { public static final ArrayAppendTypeComputer INSTANCE = new ArrayAppendTypeComputer(); - @Override - protected IAType getResultType(ILogicalExpression expr, IAType... strippedInputTypes) throws AlgebricksException { - if (strippedInputTypes.length < 2) { - String functionName = ((AbstractFunctionCallExpression) expr).getFunctionIdentifier().getName(); - throw new CompilationException(ErrorCode.COMPILATION_INVALID_NUM_OF_ARGS, expr.getSourceLocation(), 2, - functionName); - } - // type tag at [0] should be array or multiset. - ATypeTag typeTag = strippedInputTypes[0].getTypeTag(); - if (typeTag == ATypeTag.ARRAY) { - return DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE; - } else if (typeTag == ATypeTag.MULTISET) { - return DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE; - } else { - return BuiltinType.ANY; - } + private ArrayAppendTypeComputer() { + super(2); } } diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayInsertTypeComputer.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayInsertTypeComputer.java new file mode 100755 index 0000000..5c35202 --- /dev/null +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/typecomputer/impl/ArrayInsertTypeComputer.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 at + * + * 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 org.apache.asterix.om.typecomputer.impl; + +public class ArrayInsertTypeComputer extends AbstractAListOrNullTypeComputer { + + public static final ArrayInsertTypeComputer INSTANCE = new ArrayInsertTypeComputer(); + + private ArrayInsertTypeComputer() { + super(3); + } +} diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayInsertDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayInsertDescriptor.java new file mode 100755 index 0000000..3eefceb --- /dev/null +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayInsertDescriptor.java @@ -0,0 +1,212 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 at + * + * 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 org.apache.asterix.runtime.evaluators.functions; + +import static org.apache.asterix.om.types.EnumDeserializer.ATYPETAGDESERIALIZER; + +import java.io.IOException; +import java.util.Arrays; + +import org.apache.asterix.builders.IAsterixListBuilder; +import org.apache.asterix.builders.OrderedListBuilder; +import org.apache.asterix.builders.UnorderedListBuilder; +import org.apache.asterix.om.functions.BuiltinFunctions; +import org.apache.asterix.om.functions.IFunctionDescriptor; +import org.apache.asterix.om.functions.IFunctionDescriptorFactory; +import org.apache.asterix.om.functions.IFunctionTypeInferer; +import org.apache.asterix.om.pointables.base.DefaultOpenFieldType; +import org.apache.asterix.om.pointables.nonvisitor.AListPointable; +import org.apache.asterix.om.types.ATypeTag; +import org.apache.asterix.om.types.AbstractCollectionType; +import org.apache.asterix.om.types.EnumDeserializer; +import org.apache.asterix.om.types.IAType; +import org.apache.asterix.om.types.hierachy.ATypeHierarchy; +import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor; +import org.apache.asterix.runtime.evaluators.common.ListAccessor; +import org.apache.asterix.runtime.functions.FunctionTypeInferers; +import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; +import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator; +import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory; +import org.apache.hyracks.api.context.IHyracksTaskContext; +import org.apache.hyracks.api.exceptions.HyracksDataException; +import org.apache.hyracks.data.std.api.IPointable; +import org.apache.hyracks.data.std.primitive.TaggedValuePointable; +import org.apache.hyracks.data.std.primitive.VoidPointable; +import org.apache.hyracks.data.std.util.ArrayBackedValueStorage; +import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference; + +public class ArrayInsertDescriptor extends AbstractScalarFunctionDynamicDescriptor { + private static final long serialVersionUID = 1L; + private IAType[] argTypes; + + public static final IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() { + @Override + public IFunctionDescriptor createFunctionDescriptor() { + return new ArrayInsertDescriptor(); + } + + @Override + public IFunctionTypeInferer createFunctionTypeInferer() { + return FunctionTypeInferers.SET_ARGUMENTS_TYPE; + } + }; + + @Override + public FunctionIdentifier getIdentifier() { + return BuiltinFunctions.ARRAY_INSERT; + } + + @Override + public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) + throws AlgebricksException { + return new IScalarEvaluatorFactory() { + private static final long serialVersionUID = 1L; + + @Override + public IScalarEvaluator createScalarEvaluator(final IHyracksTaskContext ctx) throws HyracksDataException { + return new ArrayInsertFunction(args, ctx); + } + }; + } + + @Override + public void setImmutableStates(Object... states) { + argTypes = Arrays.copyOf(states, states.length, IAType[].class); + } + + public class ArrayInsertFunction implements IScalarEvaluator { + private final ArrayBackedValueStorage storage; + private final AListPointable listArg; + private final TaggedValuePointable positionArg; + private final IPointable[] insertedValues; + private final IScalarEvaluator listArgEval; + private final IScalarEvaluator positionArgEval; + private final IScalarEvaluator[] insertedValuesEvals; + private final CastTypeEvaluator caster; + private final ListAccessor listAccessor; + + public ArrayInsertFunction(IScalarEvaluatorFactory[] args, IHyracksTaskContext ctx) + throws HyracksDataException { + listAccessor = new ListAccessor(); + storage = new ArrayBackedValueStorage(); + caster = new CastTypeEvaluator(); + listArg = new AListPointable(); + positionArg = new TaggedValuePointable(); + listArgEval = args[0].createScalarEvaluator(ctx); + positionArgEval = args[1].createScalarEvaluator(ctx); + insertedValues = new IPointable[args.length - 2]; + insertedValuesEvals = new IScalarEvaluator[args.length - 2]; + for (int i = 2; i < args.length; i++) { + insertedValues[i - 2] = new VoidPointable(); + insertedValuesEvals[i - 2] = args[i].createScalarEvaluator(ctx); + } + } + + @Override + public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException { + // 1st arg: a list into which values are to be inserted (new list is returned) + listArgEval.evaluate(tuple, listArg); + // 2nd arg: numeric designating the position where to insert the values + positionArgEval.evaluate(tuple, positionArg); + + ATypeTag listTag = + EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(listArg.getByteArray()[listArg.getStartOffset()]); + // return "null" for certain cases + boolean returnNull = false; + int position = 0; + if (!ATypeHierarchy.isCompatible(ATypeTag.INTEGER, ATYPETAGDESERIALIZER.deserialize(positionArg.getTag())) + || !listTag.isListType()) { + // don't return null right away. Evaluate rest of args as some may be missing, return missing instead + returnNull = true; + } else { + // 1st arg is list, 2nd arg is numeric, check if the position is valid + String name = getIdentifier().getName(); + position = ATypeHierarchy.getIntegerValue(name, 1, positionArg.getByteArray(), + positionArg.getStartOffset()); + int listSize = listArg.getItemCount(); + // adjust position for negative positions + if (position < 0) { + position = listSize + position; + } + // position should always be positive now and should be within [0-list_size] + if (position < 0 || position > listSize) { + returnNull = true; + } + } + + // 3rd args: values to be inserted + IAType defaultOpenType; + for (int i = 0; i < insertedValuesEvals.length; i++) { + // cast to open if necessary + defaultOpenType = DefaultOpenFieldType.getDefaultOpenFieldType(argTypes[i + 2].getTypeTag()); + if (defaultOpenType != null && !returnNull) { + caster.reset(defaultOpenType, argTypes[i + 2], insertedValuesEvals[i]); + caster.evaluate(tuple, insertedValues[i]); + } else { + // either no casting is needed (e.g. int and the like) or avoid unnecessary casting when 1st/2nd arg + // values are not valid and null might be returned in which case evaluate normally to check missings + insertedValuesEvals[i].evaluate(tuple, insertedValues[i]); + } + } + + if (returnNull) { + PointableHelper.setNull(result); + return; + } + + // arguments are good: no nulls/missings and 1st arg is a list, 2nd arg is numeric + IAsterixListBuilder listBuilder; + AbstractCollectionType listType; + if (listTag == ATypeTag.ARRAY) { + listBuilder = new OrderedListBuilder(); + listType = DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE; + } else { + listBuilder = new UnorderedListBuilder(); + listType = DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE; + } + caster.reset(listType, argTypes[0], listArgEval); + caster.evaluate(tuple, listArg); + listBuilder.reset(listType); + listAccessor.reset(listArg.getByteArray(), listArg.getStartOffset()); + try { + int i; + for (i = 0; i < position; i++) { + storage.reset(); + listAccessor.writeItem(i, storage.getDataOutput()); + listBuilder.addItem(storage); + } + // insert the values arguments + for (IPointable appendedValue : insertedValues) { + listBuilder.addItem(appendedValue); + } + for (; i < listAccessor.size(); i++) { + storage.reset(); + listAccessor.writeItem(i, storage.getDataOutput()); + listBuilder.addItem(storage); + } + storage.reset(); + listBuilder.write(storage.getDataOutput(), true); + result.set(storage); + } catch (IOException e) { + throw HyracksDataException.create(e); + } + } + } +} diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java index 7e31951..d1879b2 100644 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/CastTypeEvaluator.java @@ -37,20 +37,18 @@ private IScalarEvaluator argEvaluator; private final IPointable argPointable = new VoidPointable(); - private final PointableAllocator allocator = new PointableAllocator(); private IVisitablePointable inputPointable; private IVisitablePointable resultPointable; + private final ACastVisitor castVisitor = createCastVisitor(); + private final Triple<IVisitablePointable, IAType, Boolean> arg = new Triple<>(null, null, null); - private final ACastVisitor castVisitor; - private final Triple<IVisitablePointable, IAType, Boolean> arg; + public CastTypeEvaluator() { + // reset() should be called after using this constructor before calling any method + } public CastTypeEvaluator(IAType reqType, IAType inputType, IScalarEvaluator argEvaluator) { - this.argEvaluator = argEvaluator; - this.inputPointable = allocatePointable(inputType, reqType); - this.resultPointable = allocatePointable(reqType, inputType); - this.arg = new Triple<>(resultPointable, reqType, Boolean.FALSE); - this.castVisitor = createCastVisitor(); + reset(reqType, inputType, argEvaluator); } public void reset(IAType reqType, IAType inputType, IScalarEvaluator argEvaluator) { @@ -59,6 +57,7 @@ this.resultPointable = allocatePointable(reqType, inputType); this.arg.first = resultPointable; this.arg.second = reqType; + this.arg.third = Boolean.FALSE; } protected ACastVisitor createCastVisitor() { diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java index 199cc40..94638e0 100644 --- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java +++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java @@ -145,6 +145,7 @@ import org.apache.asterix.runtime.evaluators.functions.AnyCollectionMemberDescriptor; import org.apache.asterix.runtime.evaluators.functions.ArrayAppendDescriptor; import org.apache.asterix.runtime.evaluators.functions.ArrayContainsDescriptor; +import org.apache.asterix.runtime.evaluators.functions.ArrayInsertDescriptor; import org.apache.asterix.runtime.evaluators.functions.ArrayPositionDescriptor; import org.apache.asterix.runtime.evaluators.functions.ArrayRepeatDescriptor; import org.apache.asterix.runtime.evaluators.functions.ArrayReverseDescriptor; @@ -381,6 +382,7 @@ fc.addGenerated(ArrayRepeatDescriptor.FACTORY); fc.addGenerated(ArrayReverseDescriptor.FACTORY); fc.addGenerated(ArrayContainsDescriptor.FACTORY); + fc.addGenerated(ArrayInsertDescriptor.FACTORY); // unnesting functions fc.add(TidRunningAggregateDescriptor.FACTORY); -- To view, visit https://asterix-gerrit.ics.uci.edu/2738 To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I57d53f63086da7e9b3412bb12f9901f5f2088c54 Gerrit-PatchSet: 1 Gerrit-Project: asterixdb Gerrit-Branch: master Gerrit-Owner: Ali Alsuliman <[email protected]>
