[ASTERIXDB-3446][RT] Do not use pools in CastTypeEvaluator

- user model changes: no
- storage format changes: no
- interface changes: no

Details:
Do not use pools in CastTypeEvaluator since that is not
needed.
- Use separate caster that uses pool for array functions.

Ext-ref: MB-62691
Change-Id: I0df95d19e652b97a86144ee5d56ca92596ab5c95
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/18466
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
Reviewed-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
Reviewed-by: Murtadha Hubail <mhubail@apache.org>
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.1.ddl.sqlpp
index 1c55a9a..e2ea074 100755
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.1.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.1.ddl.sqlpp
@@ -52,5 +52,10 @@
 compType: t1
 };
 
+create type t3 AS {
+id: int
+};
+
 create  dataset TweetMessages(TweetMessageType) primary key tweetid hints (`CARDINALITY`=`100`);
-create dataset d1(t2) primary key id;
\ No newline at end of file
+create dataset d1(t2) primary key id;
+create dataset d3(t3) primary key id;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.2.update.sqlpp
index 1c4bad0..e320513 100755
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.2.update.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.2.update.sqlpp
@@ -24,4 +24,9 @@
 insert into d1([
 {"id":1, "compType":{"sth":33}},
 {"id":2, "compType":{"sth":44}, "followers":["John Green", "Emily Jones"]}
+]);
+
+insert into d3([
+{"id":1, "list_f": [99],           "compType":{"sth":33}, "s": 1},
+{"id":2, "list_f": [88, {"a": 8}], "compType":[{"sth":44}, {"sth2": [1,2]}], "s": 2}
 ]);
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.4.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.4.query.sqlpp
new file mode 100755
index 0000000..061dd7f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.4.query.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+FROM d3 AS d
+SELECT array_append(d.list_f, d.compType, d.s) AS append_result
+ORDER BY d.id;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.4.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.9.ddl.sqlpp
similarity index 100%
rename from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.4.ddl.sqlpp
rename to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_append/array_append.9.ddl.sqlpp
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_append/array_append.4.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_append/array_append.4.adm
new file mode 100644
index 0000000..b7e6002
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_append/array_append.4.adm
@@ -0,0 +1,2 @@
+{ "append_result": [ 99, { "sth": 33 }, 1 ] }
+{ "append_result": [ 88, { "a": 8 }, [ { "sth": 44 }, { "sth2": [ 1, 2 ] } ], 2 ] }
\ No newline at end of file
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayAddRemoveEval.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayAddRemoveEval.java
index f65bf30..95c062c 100755
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayAddRemoveEval.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayAddRemoveEval.java
@@ -52,7 +52,7 @@
     private final IPointable[] valuesArgs;
     private final IScalarEvaluator listArgEval;
     private final IScalarEvaluator[] valuesEval;
-    private final CastTypeEvaluator caster;
+    private final TypeCaster caster;
     private final ListAccessor listAccessor;
     private final int listOffset;
     private final int valuesOffset;
@@ -71,7 +71,7 @@
         orderedListBuilder = null;
         unorderedListBuilder = null;
         listAccessor = new ListAccessor();
-        caster = new CastTypeEvaluator(null);
+        caster = new TypeCaster(null);
         storage = new ArrayBackedValueStorage();
         listArg = new VoidPointable();
         tempList = new VoidPointable();
@@ -130,8 +130,10 @@
                 // cast val to open if needed. don't cast if function will return null anyway, e.g. list arg not list
                 defaultOpenType = DefaultOpenFieldType.getDefaultOpenFieldType(argTypes[i + valuesOffset].getTypeTag());
                 if (defaultOpenType != null && !returnNull && makeOpen) {
-                    caster.resetAndAllocate(defaultOpenType, argTypes[i + valuesOffset], valuesEval[i]);
-                    caster.evaluate(tuple, valuesArgs[i]);
+                    valuesEval[i].evaluate(tuple, tempItem);
+                    if (!PointableHelper.checkAndSetMissingOrNull(valuesArgs[i], tempItem)) {
+                        caster.allocateAndCast(tempItem, argTypes[i + valuesOffset], valuesArgs[i], defaultOpenType);
+                    }
                 } else {
                     valuesEval[i].evaluate(tuple, valuesArgs[i]);
                 }
@@ -162,8 +164,7 @@
                 if (makeOpen || argTypes[listOffset].getTypeTag() != ATypeTag.ARRAY) {
                     listType = DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE;
                     // TODO(ali): maybe casting isn't needed if compile-time type=ANY if guaranteed input list is open
-                    caster.resetAndAllocate(listType, argTypes[listOffset], listArgEval);
-                    caster.cast(tempList, listArg);
+                    caster.allocateAndCast(tempList, argTypes[listOffset], listArg, listType);
                 } else {
                     listType = (AbstractCollectionType) argTypes[listOffset];
                     listArg.set(tempList);
@@ -175,8 +176,7 @@
                 listBuilder = unorderedListBuilder;
                 if (makeOpen || argTypes[listOffset].getTypeTag() != ATypeTag.MULTISET) {
                     listType = DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE;
-                    caster.resetAndAllocate(listType, argTypes[listOffset], listArgEval);
-                    caster.cast(tempList, listArg);
+                    caster.allocateAndCast(tempList, argTypes[listOffset], listArg, listType);
                 } else {
                     listType = (AbstractCollectionType) argTypes[listOffset];
                     listArg.set(tempList);
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayProcessArraysEval.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayProcessArraysEval.java
index 052b79d..401f9fc 100755
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayProcessArraysEval.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArrayProcessArraysEval.java
@@ -56,7 +56,7 @@
     private final IObjectPool<IPointable, Void> pointablePool;
     private final IObjectPool<IMutableValueStorage, Void> storageAllocator;
     private final IAType[] argTypes;
-    private final CastTypeEvaluator caster;
+    private final TypeCaster caster;
     private OrderedListBuilder orderedListBuilder;
     private UnorderedListBuilder unorderedListBuilder;
 
@@ -68,7 +68,7 @@
         storageAllocator = new ListObjectPool<>(ObjectFactories.STORAGE_FACTORY);
         finalResult = new ArrayBackedValueStorage();
         listAccessor = new ListAccessor();
-        caster = new CastTypeEvaluator(null);
+        caster = new TypeCaster(sourceLoc);
         tempList = new VoidPointable();
         listsArgs = new IPointable[args.length];
         listsEval = new IScalarEvaluator[args.length];
@@ -111,9 +111,7 @@
                         if (outList == null) {
                             outList = (AbstractCollectionType) DefaultOpenFieldType.getDefaultOpenFieldType(listTag);
                         }
-
-                        caster.resetAndAllocate(outList, argTypes[i], listsEval[i]);
-                        caster.cast(tempList, listsArgs[i]);
+                        caster.allocateAndCast(tempList, argTypes[i], listsArgs[i], outList);
                     }
                 }
             }
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayFlattenDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayFlattenDescriptor.java
index 72d6c3d..67c0da9 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayFlattenDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayFlattenDescriptor.java
@@ -127,7 +127,7 @@
         private final TaggedValuePointable depthArg;
         private final IObjectPool<IMutableValueStorage, ATypeTag> storageAllocator;
         private final IObjectPool<ListAccessor, ATypeTag> listAccessorAllocator;
-        private final CastTypeEvaluator caster;
+        private final TypeCaster caster;
         private final ArrayBackedValueStorage finalStorage;
         private ArrayBackedValueStorage storage;
         private IAsterixListBuilder orderedListBuilder;
@@ -141,7 +141,7 @@
             depthEval = args[1].createScalarEvaluator(ctx);
             list = new VoidPointable();
             pointable = new VoidPointable();
-            caster = new CastTypeEvaluator(null);
+            caster = new TypeCaster(sourceLoc);
             depthArg = new TaggedValuePointable();
             orderedListBuilder = null;
             unorderedListBuilder = null;
@@ -172,9 +172,8 @@
             }
 
             try {
-                caster.resetAndAllocate(DefaultOpenFieldType.getDefaultOpenFieldType(listType), inputListType,
-                        listEval);
-                caster.cast(pointable, list);
+                caster.allocateAndCast(pointable, inputListType, list,
+                        DefaultOpenFieldType.getDefaultOpenFieldType(listType));
 
                 int depthInt = (int) depth;
                 // create list
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayIntersectDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayIntersectDescriptor.java
index c33222d..25a01ca 100755
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayIntersectDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayIntersectDescriptor.java
@@ -179,7 +179,7 @@
         private final IObjectPool<List<ValueListIndex>, ATypeTag> arrayListAllocator;
         private final IObjectPool<ValueListIndex, ATypeTag> valueListIndexAllocator;
         private final ArrayBackedValueStorage finalResult;
-        private final CastTypeEvaluator caster;
+        private final TypeCaster caster;
         private final IBinaryComparator comp;
         private IAsterixListBuilder orderedListBuilder;
         private IAsterixListBuilder unorderedListBuilder;
@@ -194,7 +194,7 @@
             hashes = new Int2ObjectOpenHashMap<>();
             finalResult = new ArrayBackedValueStorage();
             listAccessor = new ListAccessor();
-            caster = new CastTypeEvaluator(null);
+            caster = new TypeCaster(sourceLoc);
             // for functions that accept multiple lists arguments, they will be casted to open, hence item is ANY
             comp = BinaryComparatorFactoryProvider.INSTANCE
                     .getBinaryComparatorFactory(BuiltinType.ANY, BuiltinType.ANY, true).createBinaryComparator();
@@ -247,8 +247,7 @@
                                         (AbstractCollectionType) DefaultOpenFieldType.getDefaultOpenFieldType(listTag);
                             }
 
-                            caster.resetAndAllocate(outList, argTypes[i], listsEval[i]);
-                            caster.cast(pointable, listsArgs[i]);
+                            caster.allocateAndCast(pointable, argTypes[i], listsArgs[i], outList);
                             nextSize = getNumItems(outList, listsArgs[i].getByteArray(), listsArgs[i].getStartOffset());
                             if (nextSize < minSize || minSize == -1) {
                                 minSize = nextSize;
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayReplaceEvaluator.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayReplaceEvaluator.java
index aeda168..74eb3e1 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayReplaceEvaluator.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayReplaceEvaluator.java
@@ -86,7 +86,7 @@
     private final ListAccessor listAccessor;
     private final IBinaryComparator comp;
     private final ArrayBackedValueStorage storage;
-    private final CastTypeEvaluator caster;
+    private final TypeCaster caster;
     private IAsterixListBuilder orderedListBuilder;
     private IAsterixListBuilder unorderedListBuilder;
 
@@ -108,7 +108,7 @@
         tempVal = new VoidPointable();
         item = new VoidPointable();
         listAccessor = new ListAccessor();
-        caster = new CastTypeEvaluator(null);
+        caster = new TypeCaster(sourceLocation);
         orderedListBuilder = null;
         unorderedListBuilder = null;
 
@@ -157,12 +157,10 @@
         }
         try {
             IAType defaultOpenType = DefaultOpenFieldType.getDefaultOpenFieldType(listType);
-            caster.resetAndAllocate(defaultOpenType, inputListType, listEval);
-            caster.cast(tempList, list);
+            caster.allocateAndCast(tempList, inputListType, list, defaultOpenType);
             defaultOpenType = DefaultOpenFieldType.getDefaultOpenFieldType(newValTag);
             if (defaultOpenType != null) {
-                caster.resetAndAllocate(defaultOpenType, newValueType, newValEval);
-                caster.cast(tempVal, newVal);
+                caster.allocateAndCast(tempVal, newValueType, newVal, defaultOpenType);
             } else {
                 newVal.set(tempVal);
             }
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayStarDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayStarDescriptor.java
index 78d8d36..ae11178 100755
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayStarDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/ArrayStarDescriptor.java
@@ -182,7 +182,7 @@
         private final IPointable list;
         private final IPointable tempList;
         private final IPointable object;
-        private final CastTypeEvaluator caster;
+        private final TypeCaster caster;
         private final ListAccessor listAccessor;
         private final RecordBuilder recordBuilder;
         private final IAsterixListBuilder listBuilder;
@@ -198,7 +198,7 @@
             list = new VoidPointable();
             tempList = new VoidPointable();
             listEval = args[0].createScalarEvaluator(ctx);
-            caster = new CastTypeEvaluator(null);
+            caster = new TypeCaster(sourceLoc);
             listAccessor = new ListAccessor();
             recordBuilder = new RecordBuilder();
             listBuilder = new OrderedListBuilder();
@@ -225,8 +225,8 @@
             }
 
             try {
-                caster.resetAndAllocate(DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE, inputListType, listEval);
-                caster.cast(tempList, list);
+                caster.allocateAndCast(tempList, inputListType, list,
+                        DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE);
 
                 tempMinHeap.clear();
                 fieldNameToValuesList.clear();
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 50f6417..6be4483 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
@@ -30,8 +30,6 @@
 import org.apache.asterix.om.types.EnumDeserializer;
 import org.apache.asterix.om.types.IAType;
 import org.apache.asterix.om.types.TypeTagUtil;
-import org.apache.asterix.om.util.container.IObjectPool;
-import org.apache.asterix.om.util.container.ListObjectPool;
 import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.api.exceptions.SourceLocation;
@@ -42,34 +40,27 @@
 public class CastTypeEvaluator implements IScalarEvaluator {
 
     private final IPointable argPointable = new VoidPointable();
-    private final IObjectPool<AFlatValueCastingPointable, IAType> flatValuePool =
-            new ListObjectPool<>(AFlatValueCastingPointable.FACTORY);
-    private final IObjectPool<ARecordCastingPointable, IAType> recordValuePool =
-            new ListObjectPool<>(ARecordCastingPointable.FACTORY);
-    private final IObjectPool<AListCastingPointable, IAType> listValuePool =
-            new ListObjectPool<>(AListCastingPointable.FACTORY);
-    private IScalarEvaluator argEvaluator;
+    private final IScalarEvaluator argEvaluator;
     protected final SourceLocation sourceLoc;
     private ICastingPointable inputPointable;
+    private ICastingPointable record;
+    private ICastingPointable list;
+    private ICastingPointable flat;
     private final ACastingPointableVisitor castVisitor = createCastVisitor();
     private final CastResult castResult = new CastResult(new VoidPointable(), null);
-    private boolean inputTypeIsAny;
-
-    public CastTypeEvaluator(SourceLocation sourceLoc) {
-        this.sourceLoc = sourceLoc;
-        // reset() should be called after using this constructor before calling any method
-    }
+    private final boolean inputTypeIsAny;
 
     public CastTypeEvaluator(IAType reqType, IAType inputType, IScalarEvaluator argEvaluator,
             SourceLocation sourceLoc) {
         this.sourceLoc = sourceLoc;
-        resetAndAllocate(reqType, inputType, argEvaluator);
-    }
-
-    public void resetAndAllocate(IAType reqType, IAType inputType, IScalarEvaluator argEvaluator) {
         this.argEvaluator = argEvaluator;
-        this.inputPointable = allocatePointable(inputType);
         this.castResult.setOutType(reqType);
+        if (!inputType.equals(BuiltinType.ANY)) {
+            this.inputPointable = createPointable(inputType);
+            this.inputTypeIsAny = false;
+        } else {
+            this.inputTypeIsAny = true;
+        }
     }
 
     protected ACastingPointableVisitor createCastVisitor() {
@@ -79,20 +70,11 @@
     @Override
     public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
         argEvaluator.evaluate(tuple, argPointable);
-
         if (PointableHelper.checkAndSetMissingOrNull(result, argPointable)) {
             return;
         }
-
-        cast(argPointable, result);
-    }
-
-    // TODO(ali): refactor in a better way
-    protected void cast(IPointable argPointable, IPointable result) throws HyracksDataException {
         if (inputTypeIsAny) {
-            ATypeTag inTag = EnumDeserializer.ATYPETAGDESERIALIZER
-                    .deserialize(argPointable.getByteArray()[argPointable.getStartOffset()]);
-            inputPointable = allocateForInput(TypeTagUtil.getBuiltinTypeByTag(inTag));
+            inputPointable = getPointable(argPointable);
         }
         inputPointable.set(argPointable);
         castInto(result);
@@ -103,35 +85,37 @@
         result.set(castResult.getOutPointable());
     }
 
-    private ICastingPointable allocatePointable(IAType inputType) {
-        if (!inputType.equals(BuiltinType.ANY)) {
-            inputTypeIsAny = false;
-            return allocateForInput(inputType);
-        } else {
-            inputTypeIsAny = true;
-            return null;
-        }
-    }
-
-    private ICastingPointable allocateForInput(IAType inputType) {
-        ICastingPointable pointable;
-        switch (inputType.getTypeTag()) {
+    private static ICastingPointable createPointable(IAType type) {
+        switch (type.getTypeTag()) {
             case OBJECT:
-                pointable = recordValuePool.allocate(inputType);
-                break;
+                return ARecordCastingPointable.FACTORY.create(type);
             case ARRAY:
             case MULTISET:
-                pointable = listValuePool.allocate(inputType);
-                break;
+                return AListCastingPointable.FACTORY.create(type);
             default:
-                pointable = flatValuePool.allocate(null);
+                return AFlatValueCastingPointable.FACTORY.create(type);
         }
-        return pointable;
     }
 
-    public void deallocatePointables() {
-        flatValuePool.reset();
-        listValuePool.reset();
-        recordValuePool.reset();
+    private ICastingPointable getPointable(IPointable arg) throws HyracksDataException {
+        ATypeTag tag = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(arg.getByteArray()[arg.getStartOffset()]);
+        switch (tag) {
+            case OBJECT:
+                if (record == null) {
+                    record = ARecordCastingPointable.FACTORY.create(TypeTagUtil.getBuiltinTypeByTag(tag));
+                }
+                return record;
+            case ARRAY:
+            case MULTISET:
+                if (list == null) {
+                    list = AListCastingPointable.FACTORY.create(TypeTagUtil.getBuiltinTypeByTag(tag));
+                }
+                return list;
+            default:
+                if (flat == null) {
+                    flat = AFlatValueCastingPointable.FACTORY.create(null);
+                }
+                return flat;
+        }
     }
 }
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/TypeCaster.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/TypeCaster.java
new file mode 100644
index 0000000..670b44d
--- /dev/null
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/TypeCaster.java
@@ -0,0 +1,96 @@
+/*
+ * 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 org.apache.asterix.om.pointables.AFlatValueCastingPointable;
+import org.apache.asterix.om.pointables.AListCastingPointable;
+import org.apache.asterix.om.pointables.ARecordCastingPointable;
+import org.apache.asterix.om.pointables.base.ICastingPointable;
+import org.apache.asterix.om.pointables.cast.ACastingPointableVisitor;
+import org.apache.asterix.om.pointables.cast.CastResult;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.EnumDeserializer;
+import org.apache.asterix.om.types.IAType;
+import org.apache.asterix.om.types.TypeTagUtil;
+import org.apache.asterix.om.util.container.IObjectPool;
+import org.apache.asterix.om.util.container.ListObjectPool;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.api.exceptions.SourceLocation;
+import org.apache.hyracks.data.std.api.IPointable;
+import org.apache.hyracks.data.std.primitive.VoidPointable;
+
+public class TypeCaster {
+
+    private final IObjectPool<AFlatValueCastingPointable, IAType> flatValuePool =
+            new ListObjectPool<>(AFlatValueCastingPointable.FACTORY);
+    private final IObjectPool<ARecordCastingPointable, IAType> recordValuePool =
+            new ListObjectPool<>(ARecordCastingPointable.FACTORY);
+    private final IObjectPool<AListCastingPointable, IAType> listValuePool =
+            new ListObjectPool<>(AListCastingPointable.FACTORY);
+    private final CastResult castResult = new CastResult(new VoidPointable(), null);
+    private final ACastingPointableVisitor castVisitor;
+
+    public TypeCaster(SourceLocation sourceLoc) {
+        this.castVisitor = new ACastingPointableVisitor(true, sourceLoc);
+    }
+
+    protected void allocateAndCast(IPointable argPointable, IAType argType, IPointable result, IAType reqType)
+            throws HyracksDataException {
+        castResult.setOutType(reqType);
+        ICastingPointable inputPointable = allocate(argPointable, argType);
+        inputPointable.accept(castVisitor, castResult);
+        result.set(castResult.getOutPointable());
+    }
+
+    private ICastingPointable allocate(IPointable arg, IAType argType) throws HyracksDataException {
+        ICastingPointable p;
+        if (!argType.equals(BuiltinType.ANY)) {
+            p = allocate(argType);
+        } else {
+            ATypeTag tag = EnumDeserializer.ATYPETAGDESERIALIZER.deserialize(arg.getByteArray()[arg.getStartOffset()]);
+            p = allocate(TypeTagUtil.getBuiltinTypeByTag(tag));
+        }
+        p.set(arg);
+        return p;
+    }
+
+    private ICastingPointable allocate(IAType inputType) {
+        ICastingPointable pointable;
+        switch (inputType.getTypeTag()) {
+            case OBJECT:
+                pointable = recordValuePool.allocate(inputType);
+                break;
+            case ARRAY:
+            case MULTISET:
+                pointable = listValuePool.allocate(inputType);
+                break;
+            default:
+                pointable = flatValuePool.allocate(null);
+        }
+        return pointable;
+    }
+
+    public void deallocatePointables() {
+        flatValuePool.reset();
+        listValuePool.reset();
+        recordValuePool.reset();
+    }
+}