You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by dl...@apache.org on 2020/06/02 05:33:27 UTC

[asterixdb] branch master updated: [NO ISSUE] Improve handling of udf parameter/return types

This is an automated email from the ASF dual-hosted git repository.

dlych pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git


The following commit(s) were added to refs/heads/master by this push:
     new f7bc6c1  [NO ISSUE] Improve handling of udf parameter/return types
f7bc6c1 is described below

commit f7bc6c1cda0176d9f88651b71b57dc88afada78c
Author: Dmitry Lychagin <dm...@couchbase.com>
AuthorDate: Mon Jun 1 18:19:44 2020 -0700

    [NO ISSUE] Improve handling of udf parameter/return types
    
    - user model changes: yes
    - storage format changes: no
    - interface changes: no
    
    Details:
    - Prohibit parameter/return type specification for inline udfs
    - Prohibit parameter/return type quantifier (?) for external udfs
    - Allow external udfs to refer to types from other dataverses
    - Do not store type quantifiers in udf metadata
    - Align names of anonymous types automatically created by
      QueryTranslator for datasets and udfs
    - Reserve user-defined type names starting from '$' for system use
    - Add testcases
    - Prohibit UdfServlet operations if cluster is not active
    - Return correct path from IOManager.getWorkspacePath()
    - Test framework: support multiple commands in .lib.sqlpp files
    - Remove CC files when deleting old instance data in
      AsterixHyracksIntegrationUtil
    
    Change-Id: I09bdfd8c7b26750d12339034d2143a16102d1212
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/6545
    Integration-Tests: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Tested-by: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Reviewed-by: Dmitry Lychagin <dm...@couchbase.com>
---
 .../translator/LangExpressionToPlanTranslator.java |   8 +-
 .../asterix/api/http/server/UdfApiServlet.java     |  17 ++-
 .../asterix/app/translator/QueryTranslator.java    | 156 ++++++++++++---------
 .../api/common/AsterixHyracksIntegrationUtil.java  |   8 ++
 .../apache/asterix/test/common/TestExecutor.java   |  53 +++----
 .../bad-type-ddl/bad-type-ddl.1.ddl.sqlpp}         |  19 ++-
 .../udf_metadata/udf_metadata.0.ddl.sqlpp          |  13 +-
 .../udf_metadata/udf_metadata.1.lib.sqlpp          |   1 +
 .../udf_metadata/udf_metadata.2.ddl.sqlpp          |  14 +-
 .../udf_metadata/udf_metadata.3.query.sqlpp        |   4 +-
 .../udf_metadata/udf_metadata.4.ddl.sqlpp          |   1 +
 .../bad-function-ddl-11.1.ddl.sqlpp}               |  19 ++-
 .../bad-function-ddl-11.2.ddl.sqlpp}               |  19 ++-
 .../udf32_metadata/udf32_metadata.1.ddl.sqlpp      |  35 +----
 .../udf_metadata/udf_metadata.3.adm                |  39 +++---
 .../udf32_metadata/udf32_metadata.2.adm            |  22 +--
 .../test/resources/runtimets/testsuite_sqlpp.xml   |  13 ++
 .../external/library/ExternalLibraryManager.java   |   6 +-
 asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj  |   6 +-
 .../asterix/lang/common/parser/FunctionParser.java |   2 +-
 .../common/statement/CreateFunctionStatement.java  |  39 ++++--
 .../asterix/lang/common/util/FunctionUtil.java     |  60 ++++----
 .../lang/common/visitor/FormatPrintVisitor.java    |   5 +-
 .../asterix-lang-sqlpp/src/main/javacc/SQLPP.jj    | 123 +++++++++-------
 .../apache/asterix/metadata/MetadataManager.java   |  10 +-
 .../metadata/bootstrap/MetadataRecordTypes.java    |   2 +-
 .../asterix/metadata/entities/BuiltinTypeMap.java  |   5 +-
 .../apache/asterix/metadata/entities/Function.java |  39 +++---
 .../FunctionTupleTranslator.java                   | 145 +++++++++----------
 .../functions/ExternalFunctionCompilerUtil.java    |  50 +++++--
 .../metadata/functions/ExternalTypeComputer.java   |  19 +--
 .../apache/asterix/metadata/utils/DatasetUtil.java |  10 --
 .../apache/asterix/metadata/utils/TypeUtil.java    |  37 +++++
 .../ExternalFunctionCompilerUtilTest.java          |  52 -------
 .../org/apache/asterix/om/types/TypeSignature.java |  15 +-
 .../apache/hyracks/control/nc/io/IOManager.java    |  13 +-
 36 files changed, 567 insertions(+), 512 deletions(-)

diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
index 3bd8f42..0f8a790 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
@@ -896,11 +896,9 @@ abstract class LangExpressionToPlanTranslator
             if (function == null) {
                 return null;
             }
-            IFunctionInfo finfo =
-                    function.isExternal()
-                            ? ExternalFunctionCompilerUtil
-                                    .getExternalFunctionInfo(metadataProvider.getMetadataTxnContext(), function)
-                            : FunctionUtil.getFunctionInfo(signature);
+            IFunctionInfo finfo = function.isExternal()
+                    ? ExternalFunctionCompilerUtil.getExternalFunctionInfo(metadataProvider, function)
+                    : FunctionUtil.getFunctionInfo(signature);
             AbstractFunctionCallExpression f = new ScalarFunctionCallExpression(finfo, args);
             f.setSourceLocation(sourceLoc);
             return f;
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/UdfApiServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/UdfApiServlet.java
index 71be106..b0da8e0 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/UdfApiServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/UdfApiServlet.java
@@ -35,6 +35,7 @@ import java.util.concurrent.ConcurrentMap;
 
 import org.apache.asterix.app.external.ExternalLibraryUtils;
 import org.apache.asterix.app.message.LoadUdfMessage;
+import org.apache.asterix.common.api.IClusterManagementWork;
 import org.apache.asterix.common.dataflow.ICcApplicationContext;
 import org.apache.asterix.common.exceptions.AsterixException;
 import org.apache.asterix.common.exceptions.ErrorCode;
@@ -103,6 +104,12 @@ public class UdfApiServlet extends BasicAuthServlet {
 
     @Override
     protected void post(IServletRequest request, IServletResponse response) {
+        IClusterManagementWork.ClusterState clusterState = appCtx.getClusterStateManager().getState();
+        if (clusterState != IClusterManagementWork.ClusterState.ACTIVE) {
+            response.setStatus(HttpResponseStatus.SERVICE_UNAVAILABLE);
+            return;
+        }
+
         PrintWriter responseWriter = response.writer();
         FullHttpRequest req = request.getHttpRequest();
         Pair<String, DataverseName> resourceNames;
@@ -238,11 +245,11 @@ public class UdfApiServlet extends BasicAuthServlet {
             throws RemoteException, AlgebricksException {
         Dataverse dv = MetadataManager.INSTANCE.getDataverse(mdTxnCtx, dataverse);
         if (dv == null) {
-            throw new AsterixException(ErrorCode.UNKNOWN_DATAVERSE);
+            throw new AsterixException(ErrorCode.UNKNOWN_DATAVERSE, dataverse);
         }
         Library library = MetadataManager.INSTANCE.getLibrary(mdTxnCtx, dataverse, libraryName);
         if (library == null) {
-            throw new AsterixException(ErrorCode.UNKNOWN_LIBRARY);
+            throw new AsterixException(ErrorCode.UNKNOWN_LIBRARY, libraryName);
         }
         List<Function> functions = MetadataManager.INSTANCE.getDataverseFunctions(mdTxnCtx, dataverse);
         for (Function function : functions) {
@@ -261,6 +268,12 @@ public class UdfApiServlet extends BasicAuthServlet {
 
     @Override
     protected void delete(IServletRequest request, IServletResponse response) {
+        IClusterManagementWork.ClusterState clusterState = appCtx.getClusterStateManager().getState();
+        if (clusterState != IClusterManagementWork.ClusterState.ACTIVE) {
+            response.setStatus(HttpResponseStatus.SERVICE_UNAVAILABLE);
+            return;
+        }
+
         Pair<String, DataverseName> resourceNames;
         try {
             resourceNames = getResource(request.getHttpRequest());
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
index 1e4e15b..12fe09b 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
@@ -172,10 +172,10 @@ import org.apache.asterix.metadata.utils.IndexUtil;
 import org.apache.asterix.metadata.utils.KeyFieldTypeUtil;
 import org.apache.asterix.metadata.utils.MetadataConstants;
 import org.apache.asterix.metadata.utils.MetadataUtil;
+import org.apache.asterix.metadata.utils.TypeUtil;
 import org.apache.asterix.om.base.IAObject;
 import org.apache.asterix.om.types.ARecordType;
 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.asterix.om.types.TypeSignature;
@@ -600,7 +600,7 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
                 break;
             case RECORD:
                 itemTypeDataverseName = dataverseName;
-                itemTypeName = DatasetUtil.createInlineTypeName(datasetName, false);
+                itemTypeName = TypeUtil.createDatasetInlineTypeName(datasetName, false);
                 itemTypeAnonymous = true;
                 break;
             default:
@@ -624,7 +624,7 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
                     break;
                 case RECORD:
                     metaItemTypeDataverseName = dataverseName;
-                    metaItemTypeName = DatasetUtil.createInlineTypeName(datasetName, true);
+                    metaItemTypeName = TypeUtil.createDatasetInlineTypeName(datasetName, true);
                     metaItemTypeAnonymous = true;
                     break;
                 default:
@@ -1378,6 +1378,9 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
                 if (BuiltinTypeMap.getBuiltinType(typeName) != null) {
                     throw new CompilationException(ErrorCode.COMPILATION_ERROR, sourceLoc,
                             "Cannot redefine builtin type " + typeName + ".");
+                } else if (TypeUtil.isReservedInlineTypeName(typeName)) {
+                    throw new CompilationException(ErrorCode.COMPILATION_ERROR, sourceLoc,
+                            "Reserved type name " + typeName + ".");
                 } else {
                     IAType type = translateType(dataverseName, typeName, stmtCreateType.getTypeDef(), mdTxnCtx);
                     MetadataManager.INSTANCE.addDatatype(mdTxnCtx, new Datatype(dataverseName, typeName, type, false));
@@ -1634,14 +1637,14 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
             // prepare to drop item and meta types if they were created as inline types
             DataverseName itemTypeDataverseName = ds.getItemTypeDataverseName();
             String itemTypeName = ds.getItemTypeName();
-            boolean isInlineItemType = DatasetUtil.isInlineTypeName(ds, itemTypeDataverseName, itemTypeName);
+            boolean isInlineItemType = TypeUtil.isDatasetInlineTypeName(ds, itemTypeDataverseName, itemTypeName);
             if (isInlineItemType) {
                 lockUtil.dropTypeBegin(lockManager, metadataProvider.getLocks(), itemTypeDataverseName, itemTypeName);
             }
             DataverseName metaTypeDataverseName = ds.getMetaItemTypeDataverseName();
             String metaTypeName = ds.getMetaItemTypeName();
             boolean isInlineMetaType =
-                    metaTypeName != null && DatasetUtil.isInlineTypeName(ds, metaTypeDataverseName, metaTypeName);
+                    metaTypeName != null && TypeUtil.isDatasetInlineTypeName(ds, metaTypeDataverseName, metaTypeName);
             if (isInlineMetaType) {
                 lockUtil.dropTypeBegin(lockManager, metadataProvider.getLocks(), metaTypeDataverseName, metaTypeName);
             }
@@ -1966,56 +1969,37 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
             if (dv == null) {
                 throw new CompilationException(ErrorCode.UNKNOWN_DATAVERSE, sourceLoc, dataverseName);
             }
-            String typeNamePrefix = createFunctionTypeNamePrefix(signature.getName(), signature.getArity());
-            List<Pair<VarIdentifier, IndexedTypeExpression>> cfsArgs = cfs.getArgs();
-            int argCount = cfsArgs.size();
-            List<String> argNames = new ArrayList<>(argCount);
-            List<IAType> argTypes = new ArrayList<>(argCount);
-            List<VarIdentifier> paramVars = new ArrayList<>(argCount);
-            LinkedHashSet<Pair<DataverseName, String>> dependentTypes = new LinkedHashSet<>();
-            for (int i = 0; i < argCount; i++) {
-                Pair<VarIdentifier, IndexedTypeExpression> argPair = cfsArgs.get(i);
-                VarIdentifier argVar = argPair.getFirst();
-                IndexedTypeExpression argTypeExpr = argPair.getSecond();
-                IAType argType;
-                if (argTypeExpr == null) {
-                    argType = BuiltinType.ANY;
-                } else {
-                    Pair<DataverseName, String> depTypeName =
-                            FunctionUtil.getDependencyFromParameterType(argTypeExpr, dataverseName);
-                    if (depTypeName != null) {
-                        dependentTypes.add(depTypeName);
-                    }
-                    TypeSignature argTypeSignature = new TypeSignature(dataverseName, typeNamePrefix + '$' + i);
-                    argType = translateType(argTypeSignature, argTypeExpr, dataverseName, mdTxnCtx);
-                    if (argType == null) {
-                        String errMessage = depTypeName != null ? depTypeName.first + "." + depTypeName.second : "";
-                        throw new CompilationException(ErrorCode.UNKNOWN_TYPE, sourceLoc, errMessage);
-                    }
+            boolean isExternal = cfs.isExternal();
+
+            List<Pair<VarIdentifier, TypeExpression>> paramList = cfs.getParameters();
+            int paramCount = paramList.size();
+            List<VarIdentifier> paramVars = new ArrayList<>(paramCount);
+            List<String> paramNames = new ArrayList<>(paramCount);
+            List<TypeSignature> paramTypes = new ArrayList<>(paramCount);
+            LinkedHashSet<TypeSignature> dependentTypes = new LinkedHashSet<>();
+
+            for (int i = 0; i < paramCount; i++) {
+                Pair<VarIdentifier, TypeExpression> paramPair = paramList.get(i);
+                VarIdentifier paramName = paramPair.getFirst();
+                TypeExpression paramTypeExpr = paramPair.getSecond();
+                Pair<TypeSignature, TypeSignature> paramType = translateFunctionParameterType(signature, i,
+                        paramTypeExpr, isExternal, sourceLoc, metadataProvider, mdTxnCtx);
+                paramVars.add(paramName);
+                paramNames.add(stmtRewriter.toFunctionParameterName(paramName));
+                paramTypes.add(paramType.first);
+                if (paramType.second != null) {
+                    dependentTypes.add(paramType.second);
                 }
-                paramVars.add(argVar);
-                argNames.add(stmtRewriter.toFunctionParameterName(argVar));
-                argTypes.add(argType);
             }
 
-            IndexedTypeExpression returnTypeExpr = cfs.getReturnType();
-            IAType returnType;
-            if (returnTypeExpr == null) {
-                returnType = BuiltinType.ANY;
-            } else {
-                Pair<DataverseName, String> depTypeName =
-                        FunctionUtil.getDependencyFromParameterType(returnTypeExpr, dataverseName);
-                if (depTypeName != null) {
-                    dependentTypes.add(depTypeName);
-                }
-                TypeSignature returnTypeSignature = new TypeSignature(dataverseName, typeNamePrefix);
-                returnType = translateType(returnTypeSignature, returnTypeExpr, dataverseName, mdTxnCtx);
-                if (returnType == null) {
-                    String errMessage = depTypeName != null ? depTypeName.first + "." + depTypeName.second : "";
-                    throw new CompilationException(ErrorCode.UNKNOWN_TYPE, sourceLoc, errMessage);
-                }
+            TypeExpression returnTypeExpr = cfs.getReturnType();
+            Pair<TypeSignature, TypeSignature> returnType = translateFunctionParameterType(signature, -1,
+                    returnTypeExpr, isExternal, sourceLoc, metadataProvider, mdTxnCtx);
+            if (returnType.second != null) {
+                dependentTypes.add(returnType.second);
             }
-            if (cfs.isExternal()) {
+
+            if (isExternal) {
                 String lang = cfs.getLang();
                 if (lang == null) {
                     throw new CompilationException(ErrorCode.COMPILATION_INCOMPATIBLE_FUNCTION_LANGUAGE, sourceLoc, "");
@@ -2036,7 +2020,7 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
                         cfs.getExternalIdentifier());
                 List<List<Triple<DataverseName, String, String>>> dependencies =
                         FunctionUtil.getExternalFunctionDependencies(dependentTypes);
-                Function f = new Function(signature, argNames, argTypes, returnType, body,
+                Function f = new Function(signature, paramNames, paramTypes, returnType.first, body,
                         FunctionKind.SCALAR.toString(), functionLang.name(), libraryName, cfs.getNullCall(),
                         cfs.getDeterministic(), cfs.getResources(), dependencies);
                 MetadataManager.INSTANCE.addFunction(mdTxnCtx, f);
@@ -2056,9 +2040,9 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
                 List<List<Triple<DataverseName, String, String>>> dependencies =
                         FunctionUtil.getFunctionDependencies(rewriterFactory.createQueryRewriter(),
                                 cfs.getFunctionBodyExpression(), metadataProvider, dependentTypes);
-                Function function = new Function(signature, argNames, argTypes, returnType, cfs.getFunctionBody(),
-                        FunctionKind.SCALAR.toString(), compilationProvider.getParserFactory().getLanguage(), null,
-                        null, null, null, dependencies);
+                Function function = new Function(signature, paramNames, paramTypes, returnType.first,
+                        cfs.getFunctionBody(), FunctionKind.SCALAR.toString(),
+                        compilationProvider.getParserFactory().getLanguage(), null, null, null, null, dependencies);
                 MetadataManager.INSTANCE.addFunction(mdTxnCtx, function);
                 if (LOGGER.isInfoEnabled()) {
                     LOGGER.info("Installed function: " + signature);
@@ -2071,19 +2055,59 @@ public class QueryTranslator extends AbstractLangTranslator implements IStatemen
         }
     }
 
-    private static IAType translateType(TypeSignature typeSignature, IndexedTypeExpression typeExpr,
-            DataverseName defaultDataverse, MetadataTransactionContext mdTxnCtx) throws AlgebricksException {
-        Map<TypeSignature, IAType> typeMap = TypeTranslator.computeTypes(typeSignature.getDataverseName(),
-                typeSignature.getName(), typeExpr.getType(), defaultDataverse, mdTxnCtx);
-        IAType type = typeMap.get(typeSignature);
-        if (type != null && typeExpr.isUnknownable()) {
-            type = AUnionType.createUnknownableType(type);
+    private Pair<TypeSignature, TypeSignature> translateFunctionParameterType(FunctionSignature functionSignature,
+            int paramIdx, TypeExpression paramTypeExpr, boolean isExternalFunction, SourceLocation sourceLoc,
+            MetadataProvider metadataProvider, MetadataTransactionContext mdTxnCtx) throws AlgebricksException {
+        if (paramTypeExpr == null) {
+            return new Pair<>(TypeUtil.ANY_TYPE_SIGNATURE, null);
+        }
+
+        if (!isExternalFunction) {
+            // grammar doesn't allow parameter types for inline functions
+            throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, sourceLoc);
+        }
+
+        TypeSignature resultType, dependentType;
+
+        switch (paramTypeExpr.getTypeKind()) {
+            case TYPEREFERENCE:
+                TypeReferenceExpression paramTypeRefExpr = (TypeReferenceExpression) paramTypeExpr;
+                String paramTypeName = paramTypeRefExpr.getIdent().second.getValue();
+                BuiltinType builtinType = BuiltinTypeMap.getBuiltinType(paramTypeName);
+                if (builtinType != null) {
+                    // built-in type
+                    resultType = new TypeSignature(builtinType);
+                    dependentType = null;
+                } else {
+                    // user-defined type
+                    DataverseName paramTypeDataverseName = paramTypeRefExpr.getIdent().first;
+                    if (paramTypeDataverseName == null) {
+                        paramTypeDataverseName = functionSignature.getDataverseName();
+                    }
+                    IAType paramType = metadataProvider.findType(paramTypeDataverseName, paramTypeName);
+                    if (paramType == null) {
+                        throw new CompilationException(ErrorCode.UNKNOWN_TYPE, sourceLoc, paramTypeName);
+                    }
+                    resultType = dependentType = new TypeSignature(paramTypeDataverseName, paramTypeName);
+                }
+                break;
+            case ORDEREDLIST:
+            case UNORDEREDLIST:
+                DataverseName paramTypeDataverseName = functionSignature.getDataverseName();
+                paramTypeName = TypeUtil.createFunctionParameterTypeName(functionSignature.getName(),
+                        functionSignature.getArity(), paramIdx);
+                IAType paramType = translateType(paramTypeDataverseName, paramTypeName, paramTypeExpr, mdTxnCtx);
+                MetadataManager.INSTANCE.addDatatype(mdTxnCtx,
+                        new Datatype(paramTypeDataverseName, paramTypeName, paramType, true));
+                resultType = new TypeSignature(paramTypeDataverseName, paramTypeName);
+                dependentType = FunctionUtil.getTypeDependencyFromFunctionParameter(paramTypeExpr,
+                        functionSignature.getDataverseName());
+                break;
+            default:
+                throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, sourceLoc);
         }
-        return type;
-    }
 
-    private static String createFunctionTypeNamePrefix(String name, int arity) {
-        return "fn$" + name + "$" + arity;
+        return new Pair<>(resultType, dependentType);
     }
 
     protected void handleCreateAdapterStatement(MetadataProvider metadataProvider, Statement stmt) throws Exception {
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/api/common/AsterixHyracksIntegrationUtil.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/api/common/AsterixHyracksIntegrationUtil.java
index 1079fb8..117fb63 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/api/common/AsterixHyracksIntegrationUtil.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/api/common/AsterixHyracksIntegrationUtil.java
@@ -135,6 +135,7 @@ public class AsterixHyracksIntegrationUtil {
         if (deleteOldInstanceData) {
             deleteTransactionLogs();
             removeTestStorageFiles();
+            deleteCCFiles();
         }
         final List<NodeControllerService> nodeControllers = new ArrayList<>();
         for (String nodeId : nodeNames) {
@@ -306,6 +307,7 @@ public class AsterixHyracksIntegrationUtil {
         if (deleteOldInstanceData) {
             deleteTransactionLogs();
             removeTestStorageFiles();
+            deleteCCFiles();
         }
     }
 
@@ -342,6 +344,12 @@ public class AsterixHyracksIntegrationUtil {
         }
     }
 
+    private void deleteCCFiles() {
+        if (cc != null) {
+            FileUtils.deleteQuietly(new File(cc.getCCConfig().getRootDir()));
+        }
+    }
+
     protected void run(boolean cleanupOnStart, boolean cleanupOnShutdown, String loadExternalLibs, String confFile)
             throws Exception {
         Runtime.getRuntime().addShutdownHook(new Thread() {
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
index 4275aa6..2acb391 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
@@ -1196,36 +1196,37 @@ public class TestExecutor {
                             // <library-directory>
                         // TODO: make this case work well with entity names containing spaces by
                         // looking for \"
-                lines = statement.split("\n");
-                String lastLine = lines[lines.length - 1];
-                String[] command = lastLine.trim().split(" ");
-                if (command.length < 2) {
-                    throw new Exception("invalid library format");
-                }
-                String dataverse = command[1];
-                String library = command[2];
-                String username = command[3];
-                String pw = command[4];
-                switch (command[0]) {
-                    case "install":
-                        if (command.length != 6) {
-                            throw new Exception("invalid library format");
-                        }
-                        String libPath = command[5];
-                        librarian.install(dataverse, library, libPath, new Pair(username, pw));
-                        break;
-                    case "uninstall":
-                        if (command.length != 5) {
+                lines = stripAllComments(statement).trim().split("\n");
+                for (String line : lines) {
+                    String[] command = line.trim().split(" ");
+                    if (command.length < 2) {
+                        throw new Exception("invalid library command: " + line);
+                    }
+                    String dataverse = command[1];
+                    String library = command[2];
+                    String username = command[3];
+                    String pw = command[4];
+                    switch (command[0]) {
+                        case "install":
+                            if (command.length != 6) {
+                                throw new Exception("invalid library format");
+                            }
+                            String libPath = command[5];
+                            librarian.install(dataverse, library, libPath, new Pair<>(username, pw));
+                            break;
+                        case "uninstall":
+                            if (command.length != 5) {
+                                throw new Exception("invalid library format");
+                            }
+                            librarian.uninstall(dataverse, library, new Pair<>(username, pw));
+                            break;
+                        default:
                             throw new Exception("invalid library format");
-                        }
-                        librarian.uninstall(dataverse, library, new Pair(username, pw));
-                        break;
-                    default:
-                        throw new Exception("invalid library format");
+                    }
                 }
                 break;
             case "node":
-                command = stripJavaComments(statement).trim().split(" ");
+                String[] command = stripJavaComments(statement).trim().split(" ");
                 String commandType = command[0];
                 String nodeId = command[1];
                 switch (commandType) {
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.0.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/bad-type-ddl/bad-type-ddl.1.ddl.sqlpp
similarity index 80%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.0.ddl.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/bad-type-ddl/bad-type-ddl.1.ddl.sqlpp
index 5a5bbec..42927bd 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.0.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/ddl/bad-type-ddl/bad-type-ddl.1.ddl.sqlpp
@@ -16,11 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-DROP DATAVERSE externallibtest if exists;
-CREATE DATAVERSE  externallibtest;
-USE externallibtest;
 
-create type CountryCapitalType if not exists as closed {
-country: string,
-capital: string
-};
+/*
+ * Description  : Reserved type name
+ * Expected Res : Error
+ */
+
+drop dataverse experiments if exists;
+create dataverse experiments;
+use experiments;
+
+create type `$x` as {
+  c : string
+};
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.0.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.0.ddl.sqlpp
index 5a5bbec..7237fff 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.0.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.0.ddl.sqlpp
@@ -21,6 +21,15 @@ CREATE DATAVERSE  externallibtest;
 USE externallibtest;
 
 create type CountryCapitalType if not exists as closed {
-country: string,
-capital: string
+  country: string,
+  capital: string
+};
+
+DROP DATAVERSE externallibtest2 if exists;
+CREATE DATAVERSE  externallibtest2;
+USE externallibtest2;
+
+create type CountryCapitalType2 if not exists as open {
+  country: string,
+  capital: string
 };
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.1.lib.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.1.lib.sqlpp
index 3dc6eb6..b4197f1 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.1.lib.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.1.lib.sqlpp
@@ -17,3 +17,4 @@
  * under the License.
  */
 install externallibtest testlib admin admin target/data/externallib/asterix-external-data-testlib.zip
+install externallibtest2 testlib2 admin admin target/data/externallib/asterix-external-data-testlib.zip
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.2.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.2.ddl.sqlpp
index 2826b9e..bcb86ac 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.2.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.2.ddl.sqlpp
@@ -33,22 +33,22 @@ create function myfn004(a:CountryCapitalType, b:[CountryCapitalType])
   returns CountryCapitalType
   language java as "testlib","org.apache.asterix.external.library.CapitalFinderFactory";
 
-create function myfn005(a:string?, b:[bigint]?, c:CountryCapitalType?, d:[CountryCapitalType]?)
-  returns string?
+create function myfn005(a:smallint, b:[bigint], c:CountryCapitalType, d:[CountryCapitalType])
+  returns string
   language java as "testlib","org.apache.asterix.external.library.CapitalFinderFactory";
 
 create function myfn006(a [string])
   returns [string]
   language java as "testlib","org.apache.asterix.external.library.CapitalFinderFactory";
 
-create function myfn007(a {{string}}?)
-  returns {{string}}?
+create function myfn007(a {{string}})
+  returns {{string}}
   language java as "testlib","org.apache.asterix.external.library.CapitalFinderFactory";
 
 create function myfn008(a [CountryCapitalType])
   returns [CountryCapitalType]
   language java as "testlib","org.apache.asterix.external.library.CapitalFinderFactory";
 
-create function myfn009(a {{CountryCapitalType}}?)
-  returns {{CountryCapitalType}}?
-  language java as "testlib","org.apache.asterix.external.library.CapitalFinderFactory";
+create function externallibtest2.myfn009(a externallibtest.CountryCapitalType)
+  returns externallibtest.CountryCapitalType
+  language java as "testlib2","org.apache.asterix.external.library.CapitalFinderFactory";
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.3.query.sqlpp
index b099f5f..fbdfd9f 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.3.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.3.query.sqlpp
@@ -19,9 +19,9 @@
 
 SELECT object_remove(fn, "Timestamp") as fn
 FROM Metadata.`Function` fn
-WHERE fn.DataverseName = "externallibtest"
+WHERE fn.DataverseName like "externallibtest%"
 UNION ALL
 SELECT object_remove(dt, "Timestamp") as dt
 FROM Metadata.`Datatype` dt
-WHERE dt.DataverseName = "externallibtest"
+WHERE dt.DataverseName like "externallibtest%"
 ORDER BY dt.DatatypeName, fn.Name;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.4.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.4.ddl.sqlpp
index cb57494..2fc3b7e 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.4.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.4.ddl.sqlpp
@@ -16,4 +16,5 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+DROP DATAVERSE externallibtest2;
 DROP DATAVERSE externallibtest;
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.0.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/bad-function-ddl-11/bad-function-ddl-11.1.ddl.sqlpp
similarity index 77%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.0.ddl.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/bad-function-ddl-11/bad-function-ddl-11.1.ddl.sqlpp
index 5a5bbec..eaddc21 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.0.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/bad-function-ddl-11/bad-function-ddl-11.1.ddl.sqlpp
@@ -16,11 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-DROP DATAVERSE externallibtest if exists;
-CREATE DATAVERSE  externallibtest;
-USE externallibtest;
 
-create type CountryCapitalType if not exists as closed {
-country: string,
-capital: string
-};
+/*
+ * Description  : Parameter type definition is prohibited for inline functions
+ * Expected Res : Error
+ */
+
+drop dataverse experiments if exists;
+create dataverse experiments;
+use experiments;
+
+create function myfn001(a:string) {
+  a
+};
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.0.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/bad-function-ddl-11/bad-function-ddl-11.2.ddl.sqlpp
similarity index 76%
copy from asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.0.ddl.sqlpp
copy to asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/bad-function-ddl-11/bad-function-ddl-11.2.ddl.sqlpp
index 5a5bbec..9b2c6f0 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/external-library/udf_metadata/udf_metadata.0.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/bad-function-ddl-11/bad-function-ddl-11.2.ddl.sqlpp
@@ -16,11 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-DROP DATAVERSE externallibtest if exists;
-CREATE DATAVERSE  externallibtest;
-USE externallibtest;
 
-create type CountryCapitalType if not exists as closed {
-country: string,
-capital: string
-};
+/*
+ * Description  : Return type definition is prohibited for inline functions
+ * Expected Res : Error
+ */
+
+drop dataverse experiments if exists;
+create dataverse experiments;
+use experiments;
+
+create function myfn002(a) returns string {
+  a
+};
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf32_metadata/udf32_metadata.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf32_metadata/udf32_metadata.1.ddl.sqlpp
index 9f268d1..8392e6c 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf32_metadata/udf32_metadata.1.ddl.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/user-defined-functions/udf32_metadata/udf32_metadata.1.ddl.sqlpp
@@ -21,11 +21,6 @@ create dataverse test;
 
 use test;
 
-create type MyType1 as {
-  `id`: int,
-  `value`: string
-};
-
 create function myfn001() {
   42
 };
@@ -34,30 +29,6 @@ create function myfn002(a) {
   a
 };
 
-create function myfn003(a:string, b:[bigint], c:{{boolean}}) returns string {
-  a
-};
-
-create function myfn004(a:MyType1, b:[MyType1]) returns MyType1 {
-  a
-};
-
-create function myfn005(a:string?, b:[bigint]?, c:MyType1?, d:[MyType1]?) returns string? {
-  a
-};
-
-create function myfn006(a [string]) returns [string] {
-  a
-};
-
-create function myfn007(a {{string}}?) returns {{string}}? {
-  a
-};
-
-create function myfn008(a [MyType1]) returns [MyType1] {
-  a
-};
-
-create function myfn009(a {{MyType1}}?) returns {{MyType1}}? {
-  a
-};
+create function myfn003(a, b) {
+  a + b
+};
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/external-library/udf_metadata/udf_metadata.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/external-library/udf_metadata/udf_metadata.3.adm
index 67f81b2..913eab7 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/external-library/udf_metadata/udf_metadata.3.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/external-library/udf_metadata/udf_metadata.3.adm
@@ -1,23 +1,22 @@
 { "fn": { "DataverseName": "externallibtest", "Name": "myfn001", "Arity": "0", "Params": [  ], "ReturnType": "any", "Definition": "org.apache.asterix.external.library.CapitalFinderFactory", "Language": "JAVA", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [  ] ], "ParamTypes": [  ], "Library": "testlib", "NullCall": false, "Deterministic": false } }
 { "fn": { "DataverseName": "externallibtest", "Name": "myfn002", "Arity": "1", "Params": [ "a" ], "ReturnType": "any", "Definition": "org.apache.asterix.external.library.CapitalFinderFactory", "Language": "JAVA", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [  ] ], "ParamTypes": [ { "Type": "any" } ], "Library": "testlib", "NullCall": false, "Deterministic": false } }
-{ "fn": { "DataverseName": "externallibtest", "Name": "myfn003", "Arity": "3", "Params": [ "a", "b", "c" ], "ReturnType": "string", "Definition": "org.apache.asterix.external.library.CapitalFinderFactory", "Language": "JAVA", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [  ] ], "ReturnTypeIsNullable": false, "ParamTypes": [ { "Type": "string", "IsNullable": false }, { "Type": "fn$myfn003$3$1", "IsNullable": false }, { "Type": "fn$myfn003$3$2", "IsNullable": false } ], "Library": "test [...]
-{ "fn": { "DataverseName": "externallibtest", "Name": "myfn004", "Arity": "2", "Params": [ "a", "b" ], "ReturnType": "CountryCapitalType", "Definition": "org.apache.asterix.external.library.CapitalFinderFactory", "Language": "JAVA", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [ [ "externallibtest", "CountryCapitalType" ] ] ], "ReturnTypeIsNullable": false, "ParamTypes": [ { "Type": "CountryCapitalType", "IsNullable": false }, { "Type": "fn$myfn004$2$1", "IsNullable": false } ], "Libr [...]
-{ "fn": { "DataverseName": "externallibtest", "Name": "myfn005", "Arity": "4", "Params": [ "a", "b", "c", "d" ], "ReturnType": "string", "Definition": "org.apache.asterix.external.library.CapitalFinderFactory", "Language": "JAVA", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [ [ "externallibtest", "CountryCapitalType" ] ] ], "ReturnTypeIsNullable": true, "ParamTypes": [ { "Type": "string", "IsNullable": true }, { "Type": "fn$myfn005$4$1", "IsNullable": true }, { "Type": "CountryCapita [...]
-{ "fn": { "DataverseName": "externallibtest", "Name": "myfn006", "Arity": "1", "Params": [ "a" ], "ReturnType": "fn$myfn006$1", "Definition": "org.apache.asterix.external.library.CapitalFinderFactory", "Language": "JAVA", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [  ] ], "ReturnTypeIsNullable": false, "ParamTypes": [ { "Type": "fn$myfn006$1$0", "IsNullable": false } ], "Library": "testlib", "NullCall": false, "Deterministic": false } }
-{ "fn": { "DataverseName": "externallibtest", "Name": "myfn007", "Arity": "1", "Params": [ "a" ], "ReturnType": "fn$myfn007$1", "Definition": "org.apache.asterix.external.library.CapitalFinderFactory", "Language": "JAVA", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [  ] ], "ReturnTypeIsNullable": true, "ParamTypes": [ { "Type": "fn$myfn007$1$0", "IsNullable": true } ], "Library": "testlib", "NullCall": false, "Deterministic": false } }
-{ "fn": { "DataverseName": "externallibtest", "Name": "myfn008", "Arity": "1", "Params": [ "a" ], "ReturnType": "fn$myfn008$1", "Definition": "org.apache.asterix.external.library.CapitalFinderFactory", "Language": "JAVA", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [ [ "externallibtest", "CountryCapitalType" ] ] ], "ReturnTypeIsNullable": false, "ParamTypes": [ { "Type": "fn$myfn008$1$0", "IsNullable": false } ], "Library": "testlib", "NullCall": false, "Deterministic": false } }
-{ "fn": { "DataverseName": "externallibtest", "Name": "myfn009", "Arity": "1", "Params": [ "a" ], "ReturnType": "fn$myfn009$1", "Definition": "org.apache.asterix.external.library.CapitalFinderFactory", "Language": "JAVA", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [ [ "externallibtest", "CountryCapitalType" ] ] ], "ReturnTypeIsNullable": true, "ParamTypes": [ { "Type": "fn$myfn009$1$0", "IsNullable": true } ], "Library": "testlib", "NullCall": false, "Deterministic": false } }
+{ "fn": { "DataverseName": "externallibtest", "Name": "myfn003", "Arity": "3", "Params": [ "a", "b", "c" ], "ReturnType": "string", "Definition": "org.apache.asterix.external.library.CapitalFinderFactory", "Language": "JAVA", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [  ] ], "ParamTypes": [ { "Type": "string" }, { "Type": "$f$t$myfn003$3$1" }, { "Type": "$f$t$myfn003$3$2" } ], "Library": "testlib", "NullCall": false, "Deterministic": false } }
+{ "fn": { "DataverseName": "externallibtest", "Name": "myfn004", "Arity": "2", "Params": [ "a", "b" ], "ReturnType": "CountryCapitalType", "Definition": "org.apache.asterix.external.library.CapitalFinderFactory", "Language": "JAVA", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [ [ "externallibtest", "CountryCapitalType" ] ] ], "ParamTypes": [ { "Type": "CountryCapitalType" }, { "Type": "$f$t$myfn004$2$1" } ], "Library": "testlib", "NullCall": false, "Deterministic": false } }
+{ "fn": { "DataverseName": "externallibtest", "Name": "myfn005", "Arity": "4", "Params": [ "a", "b", "c", "d" ], "ReturnType": "string", "Definition": "org.apache.asterix.external.library.CapitalFinderFactory", "Language": "JAVA", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [ [ "externallibtest", "CountryCapitalType" ] ] ], "ParamTypes": [ { "Type": "int16" }, { "Type": "$f$t$myfn005$4$1" }, { "Type": "CountryCapitalType" }, { "Type": "$f$t$myfn005$4$3" } ], "Library": "testlib", "Nu [...]
+{ "fn": { "DataverseName": "externallibtest", "Name": "myfn006", "Arity": "1", "Params": [ "a" ], "ReturnType": "$f$t$myfn006$1", "Definition": "org.apache.asterix.external.library.CapitalFinderFactory", "Language": "JAVA", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [  ] ], "ParamTypes": [ { "Type": "$f$t$myfn006$1$0" } ], "Library": "testlib", "NullCall": false, "Deterministic": false } }
+{ "fn": { "DataverseName": "externallibtest", "Name": "myfn007", "Arity": "1", "Params": [ "a" ], "ReturnType": "$f$t$myfn007$1", "Definition": "org.apache.asterix.external.library.CapitalFinderFactory", "Language": "JAVA", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [  ] ], "ParamTypes": [ { "Type": "$f$t$myfn007$1$0" } ], "Library": "testlib", "NullCall": false, "Deterministic": false } }
+{ "fn": { "DataverseName": "externallibtest", "Name": "myfn008", "Arity": "1", "Params": [ "a" ], "ReturnType": "$f$t$myfn008$1", "Definition": "org.apache.asterix.external.library.CapitalFinderFactory", "Language": "JAVA", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [ [ "externallibtest", "CountryCapitalType" ] ] ], "ParamTypes": [ { "Type": "$f$t$myfn008$1$0" } ], "Library": "testlib", "NullCall": false, "Deterministic": false } }
+{ "fn": { "DataverseName": "externallibtest2", "Name": "myfn009", "Arity": "1", "Params": [ "a" ], "ReturnType": "CountryCapitalType", "Definition": "org.apache.asterix.external.library.CapitalFinderFactory", "Language": "JAVA", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [ [ "externallibtest", "CountryCapitalType" ] ] ], "ReturnTypeDataverseName": "externallibtest", "ParamTypes": [ { "Type": "CountryCapitalType", "DataverseName": "externallibtest" } ], "Library": "testlib2", "NullCa [...]
+{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "$f$t$myfn003$3$1", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "int64" } } }
+{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "$f$t$myfn003$3$2", "Derived": { "Tag": "UNORDEREDLIST", "IsAnonymous": true, "UnorderedList": "boolean" } } }
+{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "$f$t$myfn004$2$1", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "CountryCapitalType" } } }
+{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "$f$t$myfn005$4$1", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "int64" } } }
+{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "$f$t$myfn005$4$3", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "CountryCapitalType" } } }
+{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "$f$t$myfn006$1", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "string" } } }
+{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "$f$t$myfn006$1$0", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "string" } } }
+{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "$f$t$myfn007$1", "Derived": { "Tag": "UNORDEREDLIST", "IsAnonymous": true, "UnorderedList": "string" } } }
+{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "$f$t$myfn007$1$0", "Derived": { "Tag": "UNORDEREDLIST", "IsAnonymous": true, "UnorderedList": "string" } } }
+{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "$f$t$myfn008$1", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "CountryCapitalType" } } }
+{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "$f$t$myfn008$1$0", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "CountryCapitalType" } } }
 { "dt": { "DataverseName": "externallibtest", "DatatypeName": "CountryCapitalType", "Derived": { "Tag": "RECORD", "IsAnonymous": false, "Record": { "IsOpen": false, "Fields": [ { "FieldName": "country", "FieldType": "string", "IsNullable": false, "IsMissable": false }, { "FieldName": "capital", "FieldType": "string", "IsNullable": false, "IsMissable": false } ] } } } }
-{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "fn$myfn003$3$1", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "int64" } } }
-{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "fn$myfn003$3$2", "Derived": { "Tag": "UNORDEREDLIST", "IsAnonymous": true, "UnorderedList": "boolean" } } }
-{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "fn$myfn004$2$1", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "CountryCapitalType" } } }
-{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "fn$myfn005$4$1", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "int64" } } }
-{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "fn$myfn005$4$3", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "CountryCapitalType" } } }
-{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "fn$myfn006$1", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "string" } } }
-{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "fn$myfn006$1$0", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "string" } } }
-{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "fn$myfn007$1", "Derived": { "Tag": "UNORDEREDLIST", "IsAnonymous": true, "UnorderedList": "string" } } }
-{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "fn$myfn007$1$0", "Derived": { "Tag": "UNORDEREDLIST", "IsAnonymous": true, "UnorderedList": "string" } } }
-{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "fn$myfn008$1", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "CountryCapitalType" } } }
-{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "fn$myfn008$1$0", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "CountryCapitalType" } } }
-{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "fn$myfn009$1", "Derived": { "Tag": "UNORDEREDLIST", "IsAnonymous": true, "UnorderedList": "CountryCapitalType" } } }
-{ "dt": { "DataverseName": "externallibtest", "DatatypeName": "fn$myfn009$1$0", "Derived": { "Tag": "UNORDEREDLIST", "IsAnonymous": true, "UnorderedList": "CountryCapitalType" } } }
+{ "dt": { "DataverseName": "externallibtest2", "DatatypeName": "CountryCapitalType2", "Derived": { "Tag": "RECORD", "IsAnonymous": false, "Record": { "IsOpen": true, "Fields": [ { "FieldName": "country", "FieldType": "string", "IsNullable": false, "IsMissable": false }, { "FieldName": "capital", "FieldType": "string", "IsNullable": false, "IsMissable": false } ] } } } }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/user-defined-functions/udf32_metadata/udf32_metadata.2.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/user-defined-functions/udf32_metadata/udf32_metadata.2.adm
index c78c3d4..07f3289 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/user-defined-functions/udf32_metadata/udf32_metadata.2.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/user-defined-functions/udf32_metadata/udf32_metadata.2.adm
@@ -1,23 +1,3 @@
 { "fn": { "DataverseName": "test", "Name": "myfn001", "Arity": "0", "Params": [  ], "ReturnType": "any", "Definition": "42", "Language": "SQLPP", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [  ] ], "ParamTypes": [  ] } }
 { "fn": { "DataverseName": "test", "Name": "myfn002", "Arity": "1", "Params": [ "a" ], "ReturnType": "any", "Definition": "a", "Language": "SQLPP", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [  ] ], "ParamTypes": [ { "Type": "any" } ] } }
-{ "fn": { "DataverseName": "test", "Name": "myfn003", "Arity": "3", "Params": [ "a", "b", "c" ], "ReturnType": "string", "Definition": "a", "Language": "SQLPP", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [  ] ], "ReturnTypeIsNullable": false, "ParamTypes": [ { "Type": "string", "IsNullable": false }, { "Type": "fn$myfn003$3$1", "IsNullable": false }, { "Type": "fn$myfn003$3$2", "IsNullable": false } ] } }
-{ "fn": { "DataverseName": "test", "Name": "myfn004", "Arity": "2", "Params": [ "a", "b" ], "ReturnType": "MyType1", "Definition": "a", "Language": "SQLPP", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [ [ "test", "MyType1" ] ] ], "ReturnTypeIsNullable": false, "ParamTypes": [ { "Type": "MyType1", "IsNullable": false }, { "Type": "fn$myfn004$2$1", "IsNullable": false } ] } }
-{ "fn": { "DataverseName": "test", "Name": "myfn005", "Arity": "4", "Params": [ "a", "b", "c", "d" ], "ReturnType": "string", "Definition": "a", "Language": "SQLPP", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [ [ "test", "MyType1" ] ] ], "ReturnTypeIsNullable": true, "ParamTypes": [ { "Type": "string", "IsNullable": true }, { "Type": "fn$myfn005$4$1", "IsNullable": true }, { "Type": "MyType1", "IsNullable": true }, { "Type": "fn$myfn005$4$3", "IsNullable": true } ] } }
-{ "fn": { "DataverseName": "test", "Name": "myfn006", "Arity": "1", "Params": [ "a" ], "ReturnType": "fn$myfn006$1", "Definition": "a", "Language": "SQLPP", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [  ] ], "ReturnTypeIsNullable": false, "ParamTypes": [ { "Type": "fn$myfn006$1$0", "IsNullable": false } ] } }
-{ "fn": { "DataverseName": "test", "Name": "myfn007", "Arity": "1", "Params": [ "a" ], "ReturnType": "fn$myfn007$1", "Definition": "a", "Language": "SQLPP", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [  ] ], "ReturnTypeIsNullable": true, "ParamTypes": [ { "Type": "fn$myfn007$1$0", "IsNullable": true } ] } }
-{ "fn": { "DataverseName": "test", "Name": "myfn008", "Arity": "1", "Params": [ "a" ], "ReturnType": "fn$myfn008$1", "Definition": "a", "Language": "SQLPP", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [ [ "test", "MyType1" ] ] ], "ReturnTypeIsNullable": false, "ParamTypes": [ { "Type": "fn$myfn008$1$0", "IsNullable": false } ] } }
-{ "fn": { "DataverseName": "test", "Name": "myfn009", "Arity": "1", "Params": [ "a" ], "ReturnType": "fn$myfn009$1", "Definition": "a", "Language": "SQLPP", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [ [ "test", "MyType1" ] ] ], "ReturnTypeIsNullable": true, "ParamTypes": [ { "Type": "fn$myfn009$1$0", "IsNullable": true } ] } }
-{ "dt": { "DataverseName": "test", "DatatypeName": "MyType1", "Derived": { "Tag": "RECORD", "IsAnonymous": false, "Record": { "IsOpen": true, "Fields": [ { "FieldName": "id", "FieldType": "int64", "IsNullable": false, "IsMissable": false }, { "FieldName": "value", "FieldType": "string", "IsNullable": false, "IsMissable": false } ] } } } }
-{ "dt": { "DataverseName": "test", "DatatypeName": "fn$myfn003$3$1", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "int64" } } }
-{ "dt": { "DataverseName": "test", "DatatypeName": "fn$myfn003$3$2", "Derived": { "Tag": "UNORDEREDLIST", "IsAnonymous": true, "UnorderedList": "boolean" } } }
-{ "dt": { "DataverseName": "test", "DatatypeName": "fn$myfn004$2$1", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "MyType1" } } }
-{ "dt": { "DataverseName": "test", "DatatypeName": "fn$myfn005$4$1", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "int64" } } }
-{ "dt": { "DataverseName": "test", "DatatypeName": "fn$myfn005$4$3", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "MyType1" } } }
-{ "dt": { "DataverseName": "test", "DatatypeName": "fn$myfn006$1", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "string" } } }
-{ "dt": { "DataverseName": "test", "DatatypeName": "fn$myfn006$1$0", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "string" } } }
-{ "dt": { "DataverseName": "test", "DatatypeName": "fn$myfn007$1", "Derived": { "Tag": "UNORDEREDLIST", "IsAnonymous": true, "UnorderedList": "string" } } }
-{ "dt": { "DataverseName": "test", "DatatypeName": "fn$myfn007$1$0", "Derived": { "Tag": "UNORDEREDLIST", "IsAnonymous": true, "UnorderedList": "string" } } }
-{ "dt": { "DataverseName": "test", "DatatypeName": "fn$myfn008$1", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "MyType1" } } }
-{ "dt": { "DataverseName": "test", "DatatypeName": "fn$myfn008$1$0", "Derived": { "Tag": "ORDEREDLIST", "IsAnonymous": true, "OrderedList": "MyType1" } } }
-{ "dt": { "DataverseName": "test", "DatatypeName": "fn$myfn009$1", "Derived": { "Tag": "UNORDEREDLIST", "IsAnonymous": true, "UnorderedList": "MyType1" } } }
-{ "dt": { "DataverseName": "test", "DatatypeName": "fn$myfn009$1$0", "Derived": { "Tag": "UNORDEREDLIST", "IsAnonymous": true, "UnorderedList": "MyType1" } } }
+{ "fn": { "DataverseName": "test", "Name": "myfn003", "Arity": "2", "Params": [ "a", "b" ], "ReturnType": "any", "Definition": "a + b", "Language": "SQLPP", "Kind": "SCALAR", "Dependencies": [ [  ], [  ], [  ] ], "ParamTypes": [ { "Type": "any" }, { "Type": "any" } ] } }
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 abee116..deb8503 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -3968,6 +3968,12 @@
       </compilation-unit>
     </test-case>
     <test-case FilePath="ddl">
+      <compilation-unit name="bad-type-ddl">
+        <output-dir compare="Text">none</output-dir>
+        <expected-error>ASX1079: Compilation error: Reserved type name $x</expected-error>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="ddl">
       <compilation-unit name="create-dataset-inline-type-1">
         <output-dir compare="Text">create-dataset-inline-type-1</output-dir>
       </compilation-unit>
@@ -11714,6 +11720,13 @@
       </compilation-unit>
     </test-case>
     <test-case FilePath="user-defined-functions">
+      <compilation-unit name="bad-function-ddl-11">
+        <output-dir compare="Text">bad-function-ddl-11</output-dir>
+        <expected-error>ASX1001: Syntax error: Unexpected type declaration for parameter a in function myfn001</expected-error>
+        <expected-error>ASX1001: Syntax error: Unexpected return type declaration for function myfn002</expected-error>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="user-defined-functions">
       <compilation-unit name="check-dependencies-1">
         <output-dir compare="Text">check-dependencies-1</output-dir>
       </compilation-unit>
diff --git a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/library/ExternalLibraryManager.java b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/library/ExternalLibraryManager.java
index 9e1461e..b09752e 100755
--- a/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/library/ExternalLibraryManager.java
+++ b/asterixdb/asterix-external-data/src/main/java/org/apache/asterix/external/library/ExternalLibraryManager.java
@@ -55,7 +55,7 @@ public class ExternalLibraryManager implements ILibraryManager {
     }
 
     private static final Logger LOGGER = LogManager.getLogger();
-    private final Map<Pair<DataverseName, String>, ILibrary> libraries = Collections.synchronizedMap(new HashMap());
+    private final Map<Pair<DataverseName, String>, ILibrary> libraries = Collections.synchronizedMap(new HashMap<>());
     private final IPersistedResourceRegistry reg;
 
     public ExternalLibraryManager(File appDir, IPersistedResourceRegistry reg) {
@@ -86,13 +86,13 @@ public class ExternalLibraryManager implements ILibraryManager {
     @Override
     public void deregister(DataverseName dataverseName, String libraryName) {
         Pair<DataverseName, String> key = getKey(dataverseName, libraryName);
-        ILibrary cl = libraries.get(key);
+        ILibrary cl = libraries.remove(key);
         if (cl != null) {
             cl.close();
-            libraries.remove(key);
         }
     }
 
+    @Override
     public void setUpDeployedLibrary(String libraryPath) throws IOException, AsterixException {
         // get the installed library dirs
         String[] parts = libraryPath.split(File.separator);
diff --git a/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj b/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
index 0a1d485..b9a489d 100644
--- a/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
+++ b/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
@@ -742,7 +742,7 @@ CreateFunctionStatement FunctionSpecification() throws ParseException:
   Token beginPos;
   Token endPos;
   FunctionName fctName = null;
-  List<Pair<VarIdentifier,IndexedTypeExpression>> bodge = new ArrayList<Pair<VarIdentifier,IndexedTypeExpression>>();
+  List<Pair<VarIdentifier,TypeExpression>> bodge = new ArrayList<Pair<VarIdentifier,TypeExpression>>();
   createNewScope();
 }
 {
@@ -762,9 +762,9 @@ CreateFunctionStatement FunctionSpecification() throws ParseException:
       getCurrentScope().addFunctionDescriptor(signature, false);
       removeCurrentScope();
       for(VarIdentifier v: paramList){
-          bodge.add(new Pair<VarIdentifier,IndexedTypeExpression>(v,null));
+          bodge.add(new Pair<VarIdentifier,TypeExpression>(v,null));
       }
-      return new CreateFunctionStatement(signature, bodge, null, functionBody, functionBodyExpr, ifNotExists);
+      return new CreateFunctionStatement(signature, bodge, functionBody, functionBodyExpr, ifNotExists);
     }
 }
 
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/FunctionParser.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/FunctionParser.java
index e37868c..fec4f50 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/FunctionParser.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/FunctionParser.java
@@ -46,6 +46,6 @@ public class FunctionParser {
                     function.getLanguage());
         }
         IParser parser = parserFactory.createParser(new StringReader(function.getFunctionBody()));
-        return parser.parseFunctionBody(function.getSignature(), function.getArgNames());
+        return parser.parseFunctionBody(function.getSignature(), function.getParameterNames());
     }
 }
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CreateFunctionStatement.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CreateFunctionStatement.java
index 72962fa..082665f 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CreateFunctionStatement.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/statement/CreateFunctionStatement.java
@@ -27,8 +27,8 @@ import org.apache.asterix.common.functions.FunctionSignature;
 import org.apache.asterix.lang.common.base.AbstractStatement;
 import org.apache.asterix.lang.common.base.Expression;
 import org.apache.asterix.lang.common.base.Statement;
-import org.apache.asterix.lang.common.expression.IndexedTypeExpression;
 import org.apache.asterix.lang.common.expression.RecordConstructor;
+import org.apache.asterix.lang.common.expression.TypeExpression;
 import org.apache.asterix.lang.common.struct.VarIdentifier;
 import org.apache.asterix.lang.common.util.ConfigurationUtil;
 import org.apache.asterix.lang.common.util.ExpressionUtils;
@@ -42,8 +42,8 @@ public class CreateFunctionStatement extends AbstractStatement {
     private final String functionBody;
     private final Expression functionBodyExpression;
     private final boolean ifNotExists;
-    private final List<Pair<VarIdentifier, IndexedTypeExpression>> args;
-    private final IndexedTypeExpression returnType;
+    private final List<Pair<VarIdentifier, TypeExpression>> paramList;
+    private final TypeExpression returnType;
 
     private final String lang;
     private final String libName;
@@ -52,15 +52,14 @@ public class CreateFunctionStatement extends AbstractStatement {
     private final Boolean nullCall;
     private final AdmObjectNode resources;
 
-    public CreateFunctionStatement(FunctionSignature signature,
-            List<Pair<VarIdentifier, IndexedTypeExpression>> parameterList, IndexedTypeExpression returnType,
+    public CreateFunctionStatement(FunctionSignature signature, List<Pair<VarIdentifier, TypeExpression>> paramList,
             String functionBody, Expression functionBodyExpression, boolean ifNotExists) {
         this.signature = signature;
         this.functionBody = functionBody;
         this.functionBodyExpression = functionBodyExpression;
         this.ifNotExists = ifNotExists;
-        this.args = parameterList;
-        this.returnType = returnType;
+        this.paramList = requireNullTypes(paramList);
+        this.returnType = null; // return type specification is not allowed for inline functions
         this.lang = null;
         this.libName = null;
         this.externalIdentifier = null;
@@ -69,13 +68,13 @@ public class CreateFunctionStatement extends AbstractStatement {
         this.resources = null;
     }
 
-    public CreateFunctionStatement(FunctionSignature signature,
-            List<Pair<VarIdentifier, IndexedTypeExpression>> parameterList, IndexedTypeExpression returnType,
-            boolean deterministic, boolean nullCall, String lang, String libName, List<String> externalIdentifier,
-            RecordConstructor resources, boolean ifNotExists) throws CompilationException {
+    public CreateFunctionStatement(FunctionSignature signature, List<Pair<VarIdentifier, TypeExpression>> paramList,
+            TypeExpression returnType, boolean deterministic, boolean nullCall, String lang, String libName,
+            List<String> externalIdentifier, RecordConstructor resources, boolean ifNotExists)
+            throws CompilationException {
         this.signature = signature;
         this.ifNotExists = ifNotExists;
-        this.args = parameterList;
+        this.paramList = paramList;
         this.returnType = returnType;
         this.deterministic = deterministic;
         this.nullCall = nullCall;
@@ -108,11 +107,11 @@ public class CreateFunctionStatement extends AbstractStatement {
         return functionBodyExpression;
     }
 
-    public List<Pair<VarIdentifier, IndexedTypeExpression>> getArgs() {
-        return args;
+    public List<Pair<VarIdentifier, TypeExpression>> getParameters() {
+        return paramList;
     }
 
-    public IndexedTypeExpression getReturnType() {
+    public TypeExpression getReturnType() {
         return returnType;
     }
 
@@ -153,4 +152,14 @@ public class CreateFunctionStatement extends AbstractStatement {
     public byte getCategory() {
         return Category.DDL;
     }
+
+    private static List<Pair<VarIdentifier, TypeExpression>> requireNullTypes(
+            List<Pair<VarIdentifier, TypeExpression>> paramList) {
+        for (Pair<VarIdentifier, TypeExpression> p : paramList) {
+            if (p.second != null) {
+                throw new IllegalArgumentException(String.valueOf(p.second));
+            }
+        }
+        return paramList;
+    }
 }
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/FunctionUtil.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/FunctionUtil.java
index 0c16f47..643d2a5 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/FunctionUtil.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/util/FunctionUtil.java
@@ -19,10 +19,9 @@
 
 package org.apache.asterix.lang.common.util;
 
-import static org.apache.asterix.common.functions.FunctionConstants.ASTERIX_DV;
-
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -35,7 +34,6 @@ import org.apache.asterix.common.metadata.DataverseName;
 import org.apache.asterix.lang.common.base.Expression;
 import org.apache.asterix.lang.common.base.IQueryRewriter;
 import org.apache.asterix.lang.common.expression.CallExpr;
-import org.apache.asterix.lang.common.expression.IndexedTypeExpression;
 import org.apache.asterix.lang.common.expression.OrderedListTypeDefinition;
 import org.apache.asterix.lang.common.expression.TypeExpression;
 import org.apache.asterix.lang.common.expression.TypeReferenceExpression;
@@ -48,6 +46,8 @@ import org.apache.asterix.metadata.declared.MetadataProvider;
 import org.apache.asterix.metadata.entities.BuiltinTypeMap;
 import org.apache.asterix.metadata.entities.Function;
 import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.TypeSignature;
 import org.apache.asterix.om.utils.ConstantExpressionUtil;
 import org.apache.commons.lang3.mutable.Mutable;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
@@ -85,32 +85,30 @@ public class FunctionUtil {
         return fi;
     }
 
-    public static Pair<DataverseName, String> getDependencyFromParameterType(IndexedTypeExpression parameterType,
-            DataverseName defaultDataverse) {
-        Pair<DataverseName, String> typeName =
-                FunctionUtil.extractNestedTypeName(parameterType.getType(), defaultDataverse);
-        return typeName == null || ASTERIX_DV.equals(typeName.getFirst()) ? null : typeName;
-    }
-
-    private static Pair<DataverseName, String> extractNestedTypeName(TypeExpression typeExpr,
+    public static TypeSignature getTypeDependencyFromFunctionParameter(TypeExpression typeExpr,
             DataverseName defaultDataverse) {
         switch (typeExpr.getTypeKind()) {
             case ORDEREDLIST:
-                return extractNestedTypeName(((OrderedListTypeDefinition) typeExpr).getItemTypeExpression(),
-                        defaultDataverse);
+                return getTypeDependencyFromFunctionParameter(
+                        ((OrderedListTypeDefinition) typeExpr).getItemTypeExpression(), defaultDataverse);
             case UNORDEREDLIST:
-                return extractNestedTypeName(((UnorderedListTypeDefinition) typeExpr).getItemTypeExpression(),
-                        defaultDataverse);
-            case RECORD:
-                break;
+                return getTypeDependencyFromFunctionParameter(
+                        ((UnorderedListTypeDefinition) typeExpr).getItemTypeExpression(), defaultDataverse);
             case TYPEREFERENCE:
                 TypeReferenceExpression typeRef = ((TypeReferenceExpression) typeExpr);
                 String typeName = typeRef.getIdent().getSecond().toString();
-                DataverseName typeDv = BuiltinTypeMap.getBuiltinType(typeName) != null ? ASTERIX_DV
-                        : typeRef.getIdent().getFirst() != null ? typeRef.getIdent().getFirst() : defaultDataverse;
-                return new Pair<>(typeDv, typeName);
+                BuiltinType builtinType = BuiltinTypeMap.getBuiltinType(typeName);
+                if (builtinType != null) {
+                    return null;
+                }
+                DataverseName typeDataverseName =
+                        typeRef.getIdent().getFirst() != null ? typeRef.getIdent().getFirst() : defaultDataverse;
+                return new TypeSignature(typeDataverseName, typeName);
+            case RECORD:
+                throw new IllegalArgumentException();
+            default:
+                throw new IllegalStateException();
         }
-        return null;
     }
 
     @FunctionalInterface
@@ -218,13 +216,13 @@ public class FunctionUtil {
     }
 
     public static List<List<Triple<DataverseName, String, String>>> getFunctionDependencies(IQueryRewriter rewriter,
-            Expression expression, MetadataProvider metadataProvider, Collection<Pair<DataverseName, String>> argTypes)
+            Expression expression, MetadataProvider metadataProvider, Collection<TypeSignature> dependentTypes)
             throws CompilationException {
         Set<CallExpr> functionCalls = rewriter.getFunctionCalls(expression);
         //Get the List of used functions and used datasets
         List<Triple<DataverseName, String, String>> datasourceDependencies = new ArrayList<>();
         List<Triple<DataverseName, String, String>> functionDependencies = new ArrayList<>();
-        List<Triple<DataverseName, String, String>> typeDependencies = new ArrayList<>();
+        List<Triple<DataverseName, String, String>> typeDependencies = new ArrayList<>(dependentTypes.size());
         for (CallExpr functionCall : functionCalls) {
             FunctionSignature signature = functionCall.getFunctionSignature();
             if (isBuiltinDatasetFunction(signature)) {
@@ -237,8 +235,8 @@ public class FunctionUtil {
                         Integer.toString(signature.getArity())));
             }
         }
-        for (Pair<DataverseName, String> t : argTypes) {
-            typeDependencies.add(new Triple<>(t.getFirst(), t.getSecond(), null));
+        for (TypeSignature t : dependentTypes) {
+            typeDependencies.add(new Triple<>(t.getDataverseName(), t.getName(), null));
         }
         List<List<Triple<DataverseName, String, String>>> dependencies = new ArrayList<>(3);
         dependencies.add(datasourceDependencies);
@@ -248,12 +246,12 @@ public class FunctionUtil {
     }
 
     public static List<List<Triple<DataverseName, String, String>>> getExternalFunctionDependencies(
-            Collection<Pair<DataverseName, String>> argTypes) {
-        List<Triple<DataverseName, String, String>> datasourceDependencies = new ArrayList<>();
-        List<Triple<DataverseName, String, String>> functionDependencies = new ArrayList<>();
-        List<Triple<DataverseName, String, String>> typeDependencies = new ArrayList<>();
-        for (Pair<DataverseName, String> t : argTypes) {
-            typeDependencies.add(new Triple<>(t.getFirst(), t.getSecond(), null));
+            Collection<TypeSignature> dependentTypes) {
+        List<Triple<DataverseName, String, String>> datasourceDependencies = Collections.emptyList();
+        List<Triple<DataverseName, String, String>> functionDependencies = Collections.emptyList();
+        List<Triple<DataverseName, String, String>> typeDependencies = new ArrayList<>(dependentTypes.size());
+        for (TypeSignature t : dependentTypes) {
+            typeDependencies.add(new Triple<>(t.getDataverseName(), t.getName(), null));
         }
         List<List<Triple<DataverseName, String, String>>> dependencies = new ArrayList<>(3);
         dependencies.add(datasourceDependencies);
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
index 1de5dcf..47e934e 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
@@ -25,7 +25,6 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -796,8 +795,8 @@ public abstract class FormatPrintVisitor implements ILangVisitor<Void, Integer>
         out.print(this.generateFullName(cfs.getFunctionSignature().getDataverseName(),
                 cfs.getFunctionSignature().getName()));
         out.print("(");
-        printDelimitedStrings(cfs.getArgs().stream().map(v -> v.getFirst().getValue()).collect(Collectors.toList()),
-                COMMA);
+        printDelimitedStrings(
+                cfs.getParameters().stream().map(v -> v.getFirst().getValue()).collect(Collectors.toList()), COMMA);
         out.println(") {");
         out.println(cfs.getFunctionBody());
         out.println("}" + SEMICOLON);
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
index 7105a42..6f756c7 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
+++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
@@ -546,6 +546,21 @@ class SQLPPParser extends ScopeChecker implements IParser {
             warningCollector.warn(WarningUtil.forAsterix(sourceLoc, ErrorCode.UNEXPECTED_HINT, actualHint, expectedHints));
         }
     }
+
+    private void ensureNoTypeDeclsInFunction(String fnName, List<Pair<VarIdentifier, TypeExpression>> paramList,
+      TypeExpression returnType, Token startToken) throws SqlppParseException {
+      for (Pair<VarIdentifier, TypeExpression> p : paramList) {
+        if (p.second != null) {
+          String paramName = SqlppVariableUtil.toUserDefinedName(p.first.getValue());
+          throw new SqlppParseException(getSourceLocation(startToken),
+            "Unexpected type declaration for parameter " + paramName + " in function " + fnName);
+        }
+      }
+      if (returnType != null) {
+        throw new SqlppParseException(getSourceLocation(startToken),
+          "Unexpected return type declaration for function " + fnName);
+      }
+    }
 }
 
 PARSER_END(SQLPPParser)
@@ -1144,14 +1159,14 @@ CreateFunctionStatement FunctionSpecification(Token startStmtToken) throws Parse
   Token endPos;
   FunctionName fctName = null;
   DataverseName currentDataverse = defaultDataverse;
-  IndexedTypeExpression returnType = null;
+  TypeExpression returnType = null;
   boolean deterministic = false;
   boolean nullCall = false;
   String lang = null;
   String libName ="";
   String externalIdent = "";
   List<String> externalIdentList = null;
-  List<Pair<VarIdentifier,IndexedTypeExpression>> args = null;
+  List<Pair<VarIdentifier,TypeExpression>> params = null;
   RecordConstructor resources = null;
 }
 {
@@ -1160,7 +1175,7 @@ CreateFunctionStatement FunctionSpecification(Token startStmtToken) throws Parse
      defaultDataverse = fctName.dataverse;
   }
   ifNotExists = IfNotExists()
-  args = FunctionParameters()
+  params = FunctionParameters()
   returnType = FunctionReturnType()
   (
     (
@@ -1173,11 +1188,12 @@ CreateFunctionStatement FunctionSpecification(Token startStmtToken) throws Parse
       <RIGHTBRACE>{
           endPos = token;
           functionBody = extractFragment(beginPos.beginLine, beginPos.beginColumn, endPos.beginLine, endPos.beginColumn);
-          signature = new FunctionSignature(fctName.dataverse, fctName.function, args.size());
+          signature = new FunctionSignature(fctName.dataverse, fctName.function, params.size());
           getCurrentScope().addFunctionDescriptor(signature, false);
           removeCurrentScope();
           defaultDataverse = currentDataverse;
-          CreateFunctionStatement stmt = new CreateFunctionStatement(signature, args, returnType, functionBody, functionBodyExpr, ifNotExists);
+          ensureNoTypeDeclsInFunction(fctName.function, params, returnType, startStmtToken);
+          CreateFunctionStatement stmt = new CreateFunctionStatement(signature, params, functionBody, functionBodyExpr, ifNotExists);
           return addSourceLocation(stmt, startStmtToken);
         }
     )
@@ -1195,11 +1211,12 @@ CreateFunctionStatement FunctionSpecification(Token startStmtToken) throws Parse
               {
                   endPos = token;
                   functionBody = extractFragment(beginPos.endLine, beginPos.beginColumn+1, endPos.endLine, endPos.endColumn+1);
-                  signature = new FunctionSignature(fctName.dataverse, fctName.function, args.size());
+                  signature = new FunctionSignature(fctName.dataverse, fctName.function, params.size());
                   getCurrentScope().addFunctionDescriptor(signature, false);
                   removeCurrentScope();
                   defaultDataverse = currentDataverse;
-                  CreateFunctionStatement stmt = new CreateFunctionStatement(signature, args, returnType, functionBody, functionBodyExpr, ifNotExists);
+                  ensureNoTypeDeclsInFunction(fctName.function, params, returnType, startStmtToken);
+                  CreateFunctionStatement stmt = new CreateFunctionStatement(signature, params, functionBody, functionBodyExpr, ifNotExists);
                   return addSourceLocation(stmt, startStmtToken);
               }
         )
@@ -1213,12 +1230,12 @@ CreateFunctionStatement FunctionSpecification(Token startStmtToken) throws Parse
               ( <COMMA>  externalIdent = ConstantString() { externalIdentList.add(externalIdent); } )+
               (<WITH> resources = RecordConstructor())?
               {
-                  signature = new FunctionSignature(fctName.dataverse, fctName.function, args.size());
+                  signature = new FunctionSignature(fctName.dataverse, fctName.function, params.size());
                   defaultDataverse = currentDataverse;
                   CreateFunctionStatement stmt = null;
                   try{
                       stmt =
-                      new CreateFunctionStatement(signature, args, returnType, deterministic, nullCall,
+                      new CreateFunctionStatement(signature, params, returnType, deterministic, nullCall,
                                                    lang, libName, externalIdentList, resources,  ifNotExists);
                   } catch (AlgebricksException e) {
                       throw new SqlppParseException(getSourceLocation(startStmtToken), e.getMessage());
@@ -1230,9 +1247,9 @@ CreateFunctionStatement FunctionSpecification(Token startStmtToken) throws Parse
   )
 }
 
-List<Pair<VarIdentifier,IndexedTypeExpression>> FunctionParameters() :
+List<Pair<VarIdentifier,TypeExpression>> FunctionParameters() :
 {
-  List<Pair<VarIdentifier,IndexedTypeExpression>> paramList = Collections.<Pair<VarIdentifier,IndexedTypeExpression>>emptyList();
+  List<Pair<VarIdentifier,TypeExpression>> paramList = Collections.<Pair<VarIdentifier,TypeExpression>>emptyList();
 }
 {
   <LEFTPAREN> (paramList = FunctionParameterList())? <RIGHTPAREN>
@@ -1241,33 +1258,38 @@ List<Pair<VarIdentifier,IndexedTypeExpression>> FunctionParameters() :
   }
 }
 
-List<Pair<VarIdentifier,IndexedTypeExpression>> FunctionParameterList() :
+List<Pair<VarIdentifier,TypeExpression>> FunctionParameterList() :
 {
-    List<Pair<VarIdentifier,IndexedTypeExpression>> paramList = new ArrayList<Pair<VarIdentifier,IndexedTypeExpression>>();
-    Pair<VarIdentifier,IndexedTypeExpression> varPair = new Pair<VarIdentifier,IndexedTypeExpression>(null,null);
-    String var = null;
-    IndexedTypeExpression type = null;
+  List<Pair<VarIdentifier,TypeExpression>> paramList = new ArrayList<Pair<VarIdentifier,TypeExpression>>();
+  Pair<VarIdentifier,TypeExpression> param = null;
 }
 {
-    var = VariableIdentifier() {
-        varPair.setFirst(new VarIdentifier(var));
-        paramList.add(varPair);
-    } (LOOKAHEAD(3)(<COLON>)? type = IndexedTypeExpr() {varPair.setSecond(type);} )? (<COMMA> var = VariableIdentifier() {
-        varPair = new Pair<VarIdentifier,IndexedTypeExpression>(null,null);
-        varPair.setFirst(new VarIdentifier(var));
-        paramList.add(varPair);
-    } (LOOKAHEAD(3)(<COLON>)? type = IndexedTypeExpr() {varPair.setSecond(type);})?)*
-    {
-        return paramList;
-    }
+  param = FunctionParameter() { paramList.add(param); }
+  ( <COMMA> param = FunctionParameter() { paramList.add(param); } )*
+  {
+    return paramList;
+  }
 }
 
-IndexedTypeExpression FunctionReturnType() throws ParseException:
+Pair<VarIdentifier,TypeExpression> FunctionParameter() throws ParseException:
 {
-  IndexedTypeExpression returnType = null;
+  String name = null;
+  TypeExpression type = null;
 }
 {
-  ( LOOKAHEAD({laIdentifier(RETURNS)}) <IDENTIFIER> returnType = IndexedTypeExpr() )?
+  name = VariableIdentifier()
+  ( LOOKAHEAD(3) (<COLON>)? type = TypeExpr(false) )?
+  {
+    return new Pair<VarIdentifier,TypeExpression>(new VarIdentifier(name), type);
+  }
+}
+
+TypeExpression FunctionReturnType() throws ParseException:
+{
+  TypeExpression returnType = null;
+}
+{
+  ( LOOKAHEAD({laIdentifier(RETURNS)}) <IDENTIFIER> returnType = TypeExpr(false) )?
   {
     return returnType;
   }
@@ -2124,27 +2146,27 @@ IndexedTypeExpression IndexedTypeExpr() throws ParseException:
   boolean isUnknownable = false;
 }
 {
-  (
-      typeExpr = TypeReference()
-    | typeExpr = OrderedListTypeDef()
-    | typeExpr = UnorderedListTypeDef()
-  )
+  typeExpr = TypeExpr(false)
   ( <QUES> { isUnknownable = true; } )?
   {
     return new IndexedTypeExpression(typeExpr, isUnknownable);
   }
 }
 
-TypeExpression TypeExpr() throws ParseException:
+TypeExpression TypeExpr(boolean allowRecordTypeDef) throws ParseException:
 {
   TypeExpression typeExpr = null;
 }
 {
   (
-      typeExpr = RecordTypeDef()
-    | typeExpr = TypeReference()
-    | typeExpr = OrderedListTypeDef()
-    | typeExpr = UnorderedListTypeDef()
+    typeExpr = TypeReference()
+    | typeExpr = OrderedListTypeDef(allowRecordTypeDef)
+    | typeExpr = UnorderedListTypeDef(allowRecordTypeDef)
+    | typeExpr = RecordTypeDef() {
+      if (!allowRecordTypeDef) {
+        throw new SqlppParseException(typeExpr.getSourceLocation(), "Unexpected record type declaration");
+      }
+    }
   )
   {
     return typeExpr;
@@ -2218,7 +2240,7 @@ void RecordField(RecordTypeDefinition recType) throws ParseException:
         SqlppHint.DATE_BETWEEN_YEARS_HINT, SqlppHint.DATETIME_ADD_RAND_HOURS_HINT, SqlppHint.AUTO_HINT);
       IRecordFieldDataGen rfdg = hintToken != null ? parseFieldDataGen(hintToken) : null;
     }
-  <COLON> type = TypeExpr() ( <QUES> { nullable = true; missable = true; } )?
+  <COLON> type = TypeExpr(true) ( <QUES> { nullable = true; missable = true; } )?
     {
       recType.addField(fieldName, type, nullable, missable, rfdg);
     }
@@ -2240,14 +2262,14 @@ TypeReferenceExpression TypeReference() throws ParseException:
   }
 }
 
-OrderedListTypeDefinition OrderedListTypeDef() throws ParseException:
+OrderedListTypeDefinition OrderedListTypeDef(boolean allowRecordTypeDef) throws ParseException:
 {
   Token startToken = null;
   TypeExpression type = null;
 }
 {
   <LEFTBRACKET> { startToken = token; }
-    ( type = TypeExpr() )
+    ( type = TypeExpr(allowRecordTypeDef) )
   <RIGHTBRACKET>
   {
     OrderedListTypeDefinition typeDef = new OrderedListTypeDefinition(type);
@@ -2255,14 +2277,14 @@ OrderedListTypeDefinition OrderedListTypeDef() throws ParseException:
   }
 }
 
-UnorderedListTypeDefinition UnorderedListTypeDef() throws ParseException:
+UnorderedListTypeDefinition UnorderedListTypeDef(boolean allowRecordTypeDef) throws ParseException:
 {
   Token startToken = null;
   TypeExpression type = null;
 }
 {
   <LEFTDBLBRACE> { startToken = token; }
-    ( type =  TypeExpr() )
+    ( type = TypeExpr(allowRecordTypeDef) )
   <RIGHTDBLBRACE>
   {
     UnorderedListTypeDefinition typeDef = new UnorderedListTypeDefinition(type);
@@ -2498,8 +2520,7 @@ FunctionDecl FunctionDeclaration() throws ParseException:
 {
   Token startToken = null;
   String functionName;
-  List<Pair<VarIdentifier,IndexedTypeExpression>> paramList = Collections.<Pair<VarIdentifier,IndexedTypeExpression>>emptyList();;
-  List<VarIdentifier> paramVarOnly = new ArrayList<VarIdentifier>();
+  List<Pair<VarIdentifier,TypeExpression>> paramList;
   Expression funcBody;
   createNewScope();
 }
@@ -2513,10 +2534,12 @@ FunctionDecl FunctionDeclaration() throws ParseException:
   {
     FunctionSignature signature = new FunctionSignature(defaultDataverse, functionName, paramList.size());
     getCurrentScope().addFunctionDescriptor(signature, false);
-    for(Pair<VarIdentifier,IndexedTypeExpression> p: paramList){
-        paramVarOnly.add(p.getFirst());
+    ensureNoTypeDeclsInFunction(functionName, paramList, null, startToken);
+    List<VarIdentifier> params = new ArrayList<VarIdentifier>(paramList.size());
+    for (Pair<VarIdentifier,TypeExpression> p: paramList) {
+        params.add(p.getFirst());
     }
-    FunctionDecl stmt = new FunctionDecl(signature, paramVarOnly, funcBody);
+    FunctionDecl stmt = new FunctionDecl(signature, params, funcBody);
     removeCurrentScope();
     return addSourceLocation(stmt, startToken);
   }
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataManager.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataManager.java
index f134ee5..e06e22f 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataManager.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataManager.java
@@ -55,7 +55,6 @@ import org.apache.asterix.metadata.entities.Library;
 import org.apache.asterix.metadata.entities.Node;
 import org.apache.asterix.metadata.entities.NodeGroup;
 import org.apache.asterix.metadata.entities.Synonym;
-import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.transaction.management.opcallbacks.AbstractIndexModificationOperationCallback.Operation;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
@@ -383,14 +382,7 @@ public abstract class MetadataManager implements IMetadataManager {
         datatype = cache.getDatatype(dataverseName, datatypeName);
         if (datatype != null) {
             // Datatype is already in the cache, don't add it again.
-            // create a new Datatype object with a new ARecordType object in order to avoid
-            // concurrent access to UTF8StringPointable comparator in ARecordType object.
-            // see issue 510
-            ARecordType aRecType = (ARecordType) datatype.getDatatype();
-            return new Datatype(
-                    datatype.getDataverseName(), datatype.getDatatypeName(), new ARecordType(aRecType.getTypeName(),
-                            aRecType.getFieldNames(), aRecType.getFieldTypes(), aRecType.isOpen()),
-                    datatype.getIsAnonymous());
+            return datatype;
         }
         try {
             datatype = metadataNode.getDatatype(ctx.getTxnId(), dataverseName, datatypeName);
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java
index 3e8f3ba..1962559 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/bootstrap/MetadataRecordTypes.java
@@ -95,6 +95,7 @@ public final class MetadataRecordTypes {
     public static final String FIELD_NAME_PROPERTIES = "Properties";
     public static final String FIELD_NAME_RECORD = "Record";
     public static final String FIELD_NAME_RETURN_TYPE = "ReturnType";
+    public static final String FIELD_NAME_RETURN_TYPE_DATAVERSE_NAME = "ReturnTypeDataverseName";
     public static final String FIELD_NAME_SEARCH_KEY = "SearchKey";
     public static final String FIELD_NAME_STATUS = "Status";
     public static final String FIELD_NAME_SYNONYM_NAME = "SynonymName";
@@ -341,7 +342,6 @@ public final class MetadataRecordTypes {
     //open types
     public static final String FUNCTION_ARECORD_FUNCTION_WITHPARAM_LIST_NAME = "WithParams";
     public static final String FUNCTION_ARECORD_FUNCTION_LIBRARY_FIELD_NAME = "Library";
-    public static final String FUNCTION_ARECORD_FUNCTION_RETURN_TYPE_IS_NULLABLE = "ReturnTypeIsNullable";
     public static final String FUNCTION_ARECORD_FUNCTION_NULLCALL_FIELD_NAME = "NullCall";
     public static final String FUNCTION_ARECORD_FUNCTION_DETERMINISTIC_FIELD_NAME = "Deterministic";
     public static final String FUNCTION_ARECORD_FUNCTION_PARAMTYPES_FIELD_NAME = "ParamTypes";
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/BuiltinTypeMap.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/BuiltinTypeMap.java
index e26dec7..2dcea99 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/BuiltinTypeMap.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/BuiltinTypeMap.java
@@ -81,14 +81,13 @@ public class BuiltinTypeMap {
     }
 
     private BuiltinTypeMap() {
-
     }
 
-    public static IAType getBuiltinType(String typeName) {
+    public static BuiltinType getBuiltinType(String typeName) {
         return _builtinTypeMap.get(typeName.toLowerCase());
     }
 
-    public static Set<IAType> getAllBuiltinTypes() {
+    public static Set<BuiltinType> getAllBuiltinTypes() {
         return new HashSet<>(_builtinTypeMap.values());
     }
 
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Function.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Function.java
index 6884970..542bbaf 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Function.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entities/Function.java
@@ -20,7 +20,6 @@ package org.apache.asterix.metadata.entities;
 
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -28,32 +27,32 @@ import org.apache.asterix.common.functions.FunctionSignature;
 import org.apache.asterix.common.metadata.DataverseName;
 import org.apache.asterix.metadata.MetadataCache;
 import org.apache.asterix.metadata.api.IMetadataEntity;
-import org.apache.asterix.om.types.IAType;
+import org.apache.asterix.om.types.TypeSignature;
 import org.apache.hyracks.algebricks.common.utils.Triple;
 
 public class Function implements IMetadataEntity<Function> {
-    private static final long serialVersionUID = 3L;
+    private static final long serialVersionUID = 4L;
 
     private final FunctionSignature signature;
-    private final List<String> argNames;
-    private final List<IAType> argTypes;
-    private final IAType returnType;
+    private final List<String> paramNames;
+    private final List<TypeSignature> paramTypes;
+    private final TypeSignature returnType;
     private final String body;
     private final String language;
     private final String kind;
     private final String library;
     private final Boolean deterministic; // null for SQL++ and AQL functions
     private final Boolean nullCall; // null for SQL++ and AQL functions
-    private final Map<String, String> params;
+    private final Map<String, String> resources;
     private final List<List<Triple<DataverseName, String, String>>> dependencies;
 
-    public Function(FunctionSignature signature, List<String> argNames, List<IAType> argTypes, IAType returnType,
-            String functionBody, String functionKind, String language, String library, Boolean nullCall,
-            Boolean deterministic, Map<String, String> params,
+    public Function(FunctionSignature signature, List<String> paramNames, List<TypeSignature> paramTypes,
+            TypeSignature returnType, String functionBody, String functionKind, String language, String library,
+            Boolean nullCall, Boolean deterministic, Map<String, String> resources,
             List<List<Triple<DataverseName, String, String>>> dependencies) {
         this.signature = signature;
-        this.argNames = argNames;
-        this.argTypes = argTypes;
+        this.paramNames = paramNames;
+        this.paramTypes = paramTypes;
         this.body = functionBody;
         this.returnType = returnType;
         this.language = language;
@@ -61,7 +60,7 @@ public class Function implements IMetadataEntity<Function> {
         this.library = library;
         this.nullCall = nullCall;
         this.deterministic = deterministic;
-        this.params = params == null ? new HashMap<>() : params;
+        this.resources = resources == null ? Collections.emptyMap() : resources;
         this.dependencies = dependencies == null
                 ? Arrays.asList(Collections.emptyList(), Collections.emptyList(), Collections.emptyList())
                 : dependencies;
@@ -83,19 +82,19 @@ public class Function implements IMetadataEntity<Function> {
         return signature.getArity();
     }
 
-    public List<String> getArgNames() {
-        return argNames;
+    public List<String> getParameterNames() {
+        return paramNames;
     }
 
-    public List<IAType> getArgTypes() {
-        return argTypes;
+    public List<TypeSignature> getParameterTypes() {
+        return paramTypes;
     }
 
     public String getFunctionBody() {
         return body;
     }
 
-    public IAType getReturnType() {
+    public TypeSignature getReturnType() {
         return returnType;
     }
 
@@ -123,8 +122,8 @@ public class Function implements IMetadataEntity<Function> {
         return deterministic;
     }
 
-    public Map<String, String> getParams() {
-        return params;
+    public Map<String, String> getResources() {
+        return resources;
     }
 
     public List<List<Triple<DataverseName, String, String>>> getDependencies() {
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FunctionTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FunctionTupleTranslator.java
index f4f6070..7135305 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FunctionTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/FunctionTupleTranslator.java
@@ -19,15 +19,15 @@
 
 package org.apache.asterix.metadata.entitytupletranslators;
 
-import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_IS_NULLABLE;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_DATAVERSE_NAME;
 import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_NAME;
+import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_RETURN_TYPE_DATAVERSE_NAME;
 import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_TYPE;
 import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FIELD_NAME_VALUE;
 import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_DETERMINISTIC_FIELD_NAME;
 import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_LIBRARY_FIELD_NAME;
 import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_NULLCALL_FIELD_NAME;
 import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_PARAMTYPES_FIELD_NAME;
-import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_RETURN_TYPE_IS_NULLABLE;
 import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_WITHPARAM_LIST_NAME;
 import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.PROPERTIES_NAME_FIELD_NAME;
 import static org.apache.asterix.metadata.bootstrap.MetadataRecordTypes.PROPERTIES_VALUE_FIELD_NAME;
@@ -58,13 +58,8 @@ import org.apache.asterix.om.base.IACursor;
 import org.apache.asterix.om.pointables.base.DefaultOpenFieldType;
 import org.apache.asterix.om.types.AOrderedListType;
 import org.apache.asterix.om.types.ARecordType;
-import org.apache.asterix.om.types.ATypeTag;
-import org.apache.asterix.om.types.AUnionType;
-import org.apache.asterix.om.types.AbstractComplexType;
 import org.apache.asterix.om.types.BuiltinType;
-import org.apache.asterix.om.types.IAType;
-import org.apache.asterix.om.utils.NonTaggedFormatUtil;
-import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.asterix.om.types.TypeSignature;
 import org.apache.hyracks.algebricks.common.utils.Triple;
 import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
@@ -98,7 +93,7 @@ public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Fun
         }
     }
 
-    protected Function createMetadataEntityFromARecord(ARecord functionRecord) throws AlgebricksException {
+    protected Function createMetadataEntityFromARecord(ARecord functionRecord) {
         String dataverseCanonicalName =
                 ((AString) functionRecord.getValueByPos(MetadataRecordTypes.FUNCTION_ARECORD_DATAVERSENAME_FIELD_INDEX))
                         .getStringValue();
@@ -109,19 +104,19 @@ public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Fun
         int arity = Integer.parseInt(((AString) functionRecord
                 .getValueByPos(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_ARITY_FIELD_INDEX)).getStringValue());
 
-        IACursor argCursor = ((AOrderedList) functionRecord
+        IACursor paramNameCursor = ((AOrderedList) functionRecord
                 .getValueByPos(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_PARAM_LIST_FIELD_INDEX)).getCursor();
-        List<String> argNames = new ArrayList<>();
-        while (argCursor.next()) {
-            argNames.add(((AString) argCursor.get()).getStringValue());
+        List<String> paramNames = new ArrayList<>();
+        while (paramNameCursor.next()) {
+            paramNames.add(((AString) paramNameCursor.get()).getStringValue());
         }
 
-        List<IAType> argTypes = getArgTypes(functionRecord, dataverseName, arity);
+        List<TypeSignature> paramTypes = getParamTypes(functionRecord, arity, dataverseName);
 
         String returnTypeName = ((AString) functionRecord
                 .getValueByPos(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_RETURN_TYPE_FIELD_INDEX)).getStringValue();
-        Boolean returnTypeIsNullable = getBoolean(functionRecord, FUNCTION_ARECORD_FUNCTION_RETURN_TYPE_IS_NULLABLE);
-        IAType returnType = resolveType(dataverseName, returnTypeName, returnTypeIsNullable);
+        String returnTypeDataverseNameCanonical = getString(functionRecord, FIELD_NAME_RETURN_TYPE_DATAVERSE_NAME);
+        TypeSignature returnType = getTypeSignature(returnTypeName, returnTypeDataverseNameCanonical, dataverseName);
 
         String definition = ((AString) functionRecord
                 .getValueByPos(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_DEFINITION_FIELD_INDEX)).getStringValue();
@@ -134,7 +129,7 @@ public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Fun
         Boolean nullCall = getBoolean(functionRecord, FUNCTION_ARECORD_FUNCTION_NULLCALL_FIELD_NAME);
         Boolean deterministic = getBoolean(functionRecord, FUNCTION_ARECORD_FUNCTION_DETERMINISTIC_FIELD_NAME);
 
-        Map<String, String> params = getWithParameters(functionRecord);
+        Map<String, String> resources = getResources(functionRecord);
 
         IACursor dependenciesCursor = ((AOrderedList) functionRecord
                 .getValueByPos(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_DEPENDENCIES_FIELD_INDEX)).getCursor();
@@ -152,23 +147,12 @@ public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Fun
 
         FunctionSignature signature = new FunctionSignature(dataverseName, functionName, arity);
 
-        return new Function(signature, argNames, argTypes, returnType, definition, functionKind, language,
-                functionLibrary, nullCall, deterministic, params, dependencies);
+        return new Function(signature, paramNames, paramTypes, returnType, definition, functionKind, language,
+                functionLibrary, nullCall, deterministic, resources, dependencies);
     }
 
-    private IAType resolveType(DataverseName dataverseName, String typeName, Boolean isUnknownable)
-            throws AlgebricksException {
-        //TODO(dmitry): revisit "isNullable"/"isMissable" for function paramters
-        return BuiltinType.ANY.getTypeName().equalsIgnoreCase(typeName) ? BuiltinType.ANY
-                : TypeUtil.createQuantifiedType(
-                        BuiltinTypeMap.getTypeFromTypeName(metadataNode, txnId, dataverseName, typeName), isUnknownable,
-                        isUnknownable);
-    }
-
-    private List<IAType> getArgTypes(ARecord functionRecord, DataverseName dataverseName, int arity)
-            throws AlgebricksException {
-        List<IAType> argTypes = new ArrayList<>(arity);
-
+    private List<TypeSignature> getParamTypes(ARecord functionRecord, int arity, DataverseName functionDataverseName) {
+        List<TypeSignature> paramTypes = new ArrayList<>(arity);
         ARecordType functionRecordType = functionRecord.getType();
         int paramTypesFieldIdx = functionRecordType.getFieldIndex(FUNCTION_ARECORD_FUNCTION_PARAMTYPES_FIELD_NAME);
         if (paramTypesFieldIdx >= 0) {
@@ -176,17 +160,31 @@ public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Fun
             while (cursor.next()) {
                 ARecord paramTypeRecord = (ARecord) cursor.get();
                 String paramTypeName = getString(paramTypeRecord, FIELD_NAME_TYPE);
-                Boolean paramTypeIsNullable = getBoolean(paramTypeRecord, FIELD_NAME_IS_NULLABLE);
-                IAType paramType = paramTypeName != null
-                        ? resolveType(dataverseName, paramTypeName, paramTypeIsNullable) : BuiltinType.ANY;
-                argTypes.add(paramType);
+                String paramTypeDataverseNameCanonical = getString(paramTypeRecord, FIELD_NAME_DATAVERSE_NAME);
+                TypeSignature paramType =
+                        getTypeSignature(paramTypeName, paramTypeDataverseNameCanonical, functionDataverseName);
+                paramTypes.add(paramType);
             }
         } else {
             for (int i = 0; i < arity; i++) {
-                argTypes.add(BuiltinType.ANY);
+                paramTypes.add(TypeUtil.ANY_TYPE_SIGNATURE);
             }
         }
-        return argTypes;
+        return paramTypes;
+    }
+
+    private TypeSignature getTypeSignature(String typeName, String typeDataverseNameCanonical,
+            DataverseName functionDataverseName) {
+        if (BuiltinType.ANY.getTypeName().equals(typeName)) {
+            return TypeUtil.ANY_TYPE_SIGNATURE;
+        }
+        BuiltinType builtinType = BuiltinTypeMap.getBuiltinType(typeName);
+        if (builtinType != null) {
+            return new TypeSignature(builtinType);
+        }
+        DataverseName typeDataverseName = typeDataverseNameCanonical == null ? functionDataverseName
+                : DataverseName.createFromCanonicalForm(typeDataverseNameCanonical);
+        return new TypeSignature(typeDataverseName, typeName);
     }
 
     private Triple<DataverseName, String, String> getDependency(AOrderedList dependencySubnames) {
@@ -203,7 +201,7 @@ public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Fun
         return new Triple<>(dataverseName, second, third);
     }
 
-    private Map<String, String> getWithParameters(ARecord functionRecord) {
+    private Map<String, String> getResources(ARecord functionRecord) {
         Map<String, String> adaptorConfiguration = new HashMap<>();
         final ARecordType functionType = functionRecord.getType();
         final int functionLibraryIdx = functionType.getFieldIndex(FUNCTION_ARECORD_FUNCTION_WITHPARAM_LIST_NAME);
@@ -278,7 +276,7 @@ public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Fun
         ArrayBackedValueStorage itemValue = new ArrayBackedValueStorage();
         listBuilder.reset((AOrderedListType) MetadataRecordTypes.FUNCTION_RECORDTYPE
                 .getFieldTypes()[MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_PARAM_LIST_FIELD_INDEX]);
-        for (String p : function.getArgNames()) {
+        for (String p : function.getParameterNames()) {
             itemValue.reset();
             aString.setValue(p);
             stringSerde.serialize(aString, itemValue.getDataOutput());
@@ -288,17 +286,10 @@ public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Fun
         listBuilder.write(fieldValue.getDataOutput(), true);
         recordBuilder.addField(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_PARAM_LIST_FIELD_INDEX, fieldValue);
 
-        IAType returnType = function.getReturnType();
-        boolean returnTypeIsUnknownable = NonTaggedFormatUtil.isOptional(returnType);
-        IAType returnPrimeType = returnTypeIsUnknownable ? ((AUnionType) returnType).getActualType() : returnType;
-        if (returnPrimeType.getTypeTag().isDerivedType()) {
-            handleNestedDerivedType(dataverseName, returnPrimeType.getTypeName(),
-                    (AbstractComplexType) returnPrimeType);
-        }
-
         // write field 4
+        // Note: return type's dataverse name is written later in the open part
         fieldValue.reset();
-        aString.setValue(returnPrimeType.getTypeName());
+        aString.setValue(function.getReturnType().getName());
         stringSerde.serialize(aString, fieldValue.getDataOutput());
         recordBuilder.addField(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_RETURN_TYPE_FIELD_INDEX, fieldValue);
 
@@ -347,7 +338,7 @@ public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Fun
         dependenciesListBuilder.write(fieldValue.getDataOutput(), true);
         recordBuilder.addField(MetadataRecordTypes.FUNCTION_ARECORD_FUNCTION_DEPENDENCIES_FIELD_INDEX, fieldValue);
 
-        writeOpenFields(function, returnPrimeType, returnTypeIsUnknownable);
+        writeOpenFields(function);
 
         // write record
         recordBuilder.write(tupleBuilder.getDataOutput(), true);
@@ -357,18 +348,17 @@ public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Fun
         return tuple;
     }
 
-    protected void writeOpenFields(Function function, IAType returnPrimeType, boolean returnTypeIsUnknownable)
-            throws HyracksDataException {
-        writeReturnTypeIsNullable(returnPrimeType, returnTypeIsUnknownable);
-        writeArgTypes(function);
-        writeWithParameters(function);
+    protected void writeOpenFields(Function function) throws HyracksDataException {
+        writeReturnTypeDataverseName(function);
+        writeParameterTypes(function);
+        writeResources(function);
         writeLibrary(function);
         writeNullCall(function);
         writeDeterministic(function);
     }
 
-    protected void writeWithParameters(Function function) throws HyracksDataException {
-        Map<String, String> withParams = function.getParams();
+    protected void writeResources(Function function) throws HyracksDataException {
+        Map<String, String> withParams = function.getResources();
         if (withParams == null || withParams.isEmpty()) {
             return;
         }
@@ -391,19 +381,14 @@ public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Fun
         recordBuilder.addField(fieldName, fieldValue);
     }
 
-    protected void writeArgTypes(Function function) throws HyracksDataException {
-        DataverseName dataverseName = function.getDataverseName();
+    protected void writeParameterTypes(Function function) throws HyracksDataException {
         OrderedListBuilder listBuilder = new OrderedListBuilder();
         ArrayBackedValueStorage itemValue = new ArrayBackedValueStorage();
         listBuilder.reset(DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE);
-        for (IAType argType : function.getArgTypes()) {
-            boolean argTypeIsUnknownable = NonTaggedFormatUtil.isOptional(argType);
-            IAType argPrimeType = argTypeIsUnknownable ? ((AUnionType) argType).getActualType() : argType;
-            if (argPrimeType.getTypeTag().isDerivedType()) {
-                handleNestedDerivedType(dataverseName, argPrimeType.getTypeName(), (AbstractComplexType) argPrimeType);
-            }
+        for (TypeSignature paramType : function.getParameterTypes()) {
             itemValue.reset();
-            writeTypeRecord(argPrimeType, argTypeIsUnknownable, itemValue.getDataOutput());
+            writeTypeRecord(paramType.getDataverseName(), paramType.getName(), function.getDataverseName(),
+                    itemValue.getDataOutput());
             listBuilder.addItem(itemValue);
         }
         fieldValue.reset();
@@ -429,14 +414,17 @@ public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Fun
         recordBuilder.addField(fieldName, fieldValue);
     }
 
-    protected void writeReturnTypeIsNullable(IAType returnPrimeType, boolean returnTypeIsUnknownable)
-            throws HyracksDataException {
-        if (returnPrimeType.getTypeTag() != ATypeTag.ANY) {
+    protected void writeReturnTypeDataverseName(Function function) throws HyracksDataException {
+        DataverseName returnTypeDataverseName = function.getReturnType().getDataverseName();
+        boolean skipReturnTypeDataverseName =
+                returnTypeDataverseName == null || returnTypeDataverseName.equals(function.getDataverseName());
+        if (!skipReturnTypeDataverseName) {
             fieldName.reset();
-            aString.setValue(FUNCTION_ARECORD_FUNCTION_RETURN_TYPE_IS_NULLABLE);
+            aString.setValue(FIELD_NAME_RETURN_TYPE_DATAVERSE_NAME);
             stringSerde.serialize(aString, fieldName.getDataOutput());
             fieldValue.reset();
-            booleanSerde.serialize(ABoolean.valueOf(returnTypeIsUnknownable), fieldValue.getDataOutput());
+            aString.setValue(returnTypeDataverseName.getCanonicalForm());
+            stringSerde.serialize(aString, fieldValue.getDataOutput());
             recordBuilder.addField(fieldName, fieldValue);
         }
     }
@@ -492,7 +480,8 @@ public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Fun
         propertyRecordBuilder.write(out, true);
     }
 
-    public void writeTypeRecord(IAType primeType, boolean isUnknownable, DataOutput out) throws HyracksDataException {
+    public void writeTypeRecord(DataverseName typeDataverseName, String typeName, DataverseName functionDataverseName,
+            DataOutput out) throws HyracksDataException {
         IARecordBuilder propertyRecordBuilder = new RecordBuilder();
         propertyRecordBuilder.reset(DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE);
 
@@ -501,17 +490,19 @@ public class FunctionTupleTranslator extends AbstractDatatypeTupleTranslator<Fun
         aString.setValue(FIELD_NAME_TYPE);
         stringSerde.serialize(aString, fieldName.getDataOutput());
         fieldValue.reset();
-        aString.setValue(primeType.getTypeName());
+        aString.setValue(typeName);
         stringSerde.serialize(aString, fieldValue.getDataOutput());
         propertyRecordBuilder.addField(fieldName, fieldValue);
 
-        // write field "IsNullable"
-        if (primeType.getTypeTag() != ATypeTag.ANY) {
+        // write field "DataverseName"
+        boolean skipTypeDataverseName = typeDataverseName == null || typeDataverseName.equals(functionDataverseName);
+        if (!skipTypeDataverseName) {
             fieldName.reset();
-            aString.setValue(FIELD_NAME_IS_NULLABLE);
+            aString.setValue(FIELD_NAME_DATAVERSE_NAME);
             stringSerde.serialize(aString, fieldName.getDataOutput());
             fieldValue.reset();
-            booleanSerde.serialize(ABoolean.valueOf(isUnknownable), fieldValue.getDataOutput());
+            aString.setValue(typeDataverseName.getCanonicalForm());
+            stringSerde.serialize(aString, fieldValue.getDataOutput());
             propertyRecordBuilder.addField(fieldName, fieldValue);
         }
 
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/functions/ExternalFunctionCompilerUtil.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/functions/ExternalFunctionCompilerUtil.java
index ced8dc0..6c88621 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/functions/ExternalFunctionCompilerUtil.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/functions/ExternalFunctionCompilerUtil.java
@@ -18,6 +18,7 @@
  */
 package org.apache.asterix.metadata.functions;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -26,10 +27,13 @@ import org.apache.asterix.common.exceptions.AsterixException;
 import org.apache.asterix.common.exceptions.ErrorCode;
 import org.apache.asterix.common.functions.ExternalFunctionLanguage;
 import org.apache.asterix.common.functions.FunctionSignature;
-import org.apache.asterix.metadata.MetadataTransactionContext;
+import org.apache.asterix.metadata.declared.MetadataProvider;
+import org.apache.asterix.metadata.entities.BuiltinTypeMap;
 import org.apache.asterix.metadata.entities.Function;
 import org.apache.asterix.om.typecomputer.base.IResultTypeComputer;
+import org.apache.asterix.om.types.BuiltinType;
 import org.apache.asterix.om.types.IAType;
+import org.apache.asterix.om.types.TypeSignature;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
 import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression.FunctionKind;
 import org.apache.hyracks.algebricks.core.algebra.functions.IFunctionInfo;
@@ -40,31 +44,38 @@ public class ExternalFunctionCompilerUtil {
         // do nothing
     }
 
-    public static IFunctionInfo getExternalFunctionInfo(MetadataTransactionContext txnCtx, Function function)
+    public static IFunctionInfo getExternalFunctionInfo(MetadataProvider metadataProvider, Function function)
             throws AlgebricksException {
 
         String functionKind = function.getKind();
         IFunctionInfo finfo = null;
         if (FunctionKind.SCALAR.toString().equalsIgnoreCase(functionKind)) {
-            finfo = getScalarFunctionInfo(txnCtx, function);
+            finfo = getScalarFunctionInfo(metadataProvider, function);
         } else if (FunctionKind.AGGREGATE.toString().equalsIgnoreCase(functionKind)) {
-            finfo = getAggregateFunctionInfo(txnCtx, function);
+            finfo = getAggregateFunctionInfo(metadataProvider, function);
         } else if (FunctionKind.STATEFUL.toString().equalsIgnoreCase(functionKind)) {
-            finfo = getStatefulFunctionInfo(txnCtx, function);
+            finfo = getStatefulFunctionInfo(metadataProvider, function);
         } else if (FunctionKind.UNNEST.toString().equalsIgnoreCase(functionKind)) {
-            finfo = getUnnestFunctionInfo(txnCtx, function);
+            finfo = getUnnestFunctionInfo(metadataProvider, function);
         }
         return finfo;
     }
 
-    private static IFunctionInfo getScalarFunctionInfo(MetadataTransactionContext txnCtx, Function function)
+    private static IFunctionInfo getScalarFunctionInfo(MetadataProvider metadataProvider, Function function)
             throws AlgebricksException {
         if (function.getDeterministic() == null) {
             throw new AsterixException(ErrorCode.METADATA_ERROR, "");
         }
 
-        IAType returnType = function.getReturnType();
-        IResultTypeComputer typeComputer = new ExternalTypeComputer(returnType, function.getArgTypes());
+        List<IAType> paramTypes = new ArrayList<>(function.getParameterTypes().size());
+        for (TypeSignature ts : function.getParameterTypes()) {
+            IAType paramType = resolveFunctionType(ts, metadataProvider);
+            paramTypes.add(paramType);
+        }
+
+        IAType returnType = resolveFunctionType(function.getReturnType(), metadataProvider);
+
+        IResultTypeComputer typeComputer = new ExternalTypeComputer(returnType, paramTypes);
 
         ExternalFunctionLanguage lang;
         try {
@@ -75,22 +86,35 @@ public class ExternalFunctionCompilerUtil {
         List<String> externalIdentifier = decodeExternalIdentifier(lang, function.getFunctionBody());
 
         return new ExternalScalarFunctionInfo(function.getSignature().createFunctionIdentifier(), returnType,
-                externalIdentifier, lang, function.getLibrary(), function.getArgTypes(), function.getParams(),
+                externalIdentifier, lang, function.getLibrary(), paramTypes, function.getResources(),
                 function.getDeterministic(), typeComputer);
     }
 
-    private static IFunctionInfo getUnnestFunctionInfo(MetadataTransactionContext txnCtx, Function function) {
+    private static IFunctionInfo getUnnestFunctionInfo(MetadataProvider metadataProvider, Function function) {
         return null;
     }
 
-    private static IFunctionInfo getStatefulFunctionInfo(MetadataTransactionContext txnCtx, Function function) {
+    private static IFunctionInfo getStatefulFunctionInfo(MetadataProvider metadataProvider, Function function) {
         return null;
     }
 
-    private static IFunctionInfo getAggregateFunctionInfo(MetadataTransactionContext txnCtx, Function function) {
+    private static IFunctionInfo getAggregateFunctionInfo(MetadataProvider metadataProvider, Function function) {
         return null;
     }
 
+    private static IAType resolveFunctionType(TypeSignature typeSignature, MetadataProvider metadataProvider)
+            throws AlgebricksException {
+        String typeName = typeSignature.getName();
+        if (BuiltinType.ANY.getTypeName().equals(typeName)) {
+            return BuiltinType.ANY;
+        }
+        IAType type = BuiltinTypeMap.getBuiltinType(typeName);
+        if (type == null) {
+            type = metadataProvider.findType(typeSignature.getDataverseName(), typeName);
+        }
+        return type;
+    }
+
     public static String encodeExternalIdentifier(FunctionSignature functionSignature,
             ExternalFunctionLanguage language, List<String> identList) throws AlgebricksException {
         switch (language) {
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/functions/ExternalTypeComputer.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/functions/ExternalTypeComputer.java
index 2f5742e..4a000a3 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/functions/ExternalTypeComputer.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/functions/ExternalTypeComputer.java
@@ -22,6 +22,8 @@ import java.util.List;
 
 import org.apache.asterix.om.exceptions.TypeMismatchException;
 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.IAType;
 import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
@@ -32,22 +34,23 @@ import org.apache.hyracks.api.exceptions.SourceLocation;
 public class ExternalTypeComputer extends AbstractResultTypeComputer {
 
     private IAType resultType;
-    private List<IAType> argTypes;
+    private List<IAType> paramPrimeTypes;
 
     @Override
     protected void checkArgType(FunctionIdentifier funcId, int argIndex, IAType type, SourceLocation sourceLoc)
             throws AlgebricksException {
-        IAType reqArgType = argTypes.get(argIndex);
-        if (!type.equals(argTypes.get(argIndex))
-                && !ATypeHierarchy.isCompatible(type.getTypeTag(), reqArgType.getTypeTag())) {
+        IAType reqParamType = paramPrimeTypes.get(argIndex);
+        if (!type.equals(paramPrimeTypes.get(argIndex))
+                && !ATypeHierarchy.isCompatible(type.getTypeTag(), reqParamType.getTypeTag())) {
             throw new TypeMismatchException(sourceLoc, funcId, argIndex, type.getTypeTag(),
-                    argTypes.get(argIndex).getTypeTag());
+                    paramPrimeTypes.get(argIndex).getTypeTag());
         }
     }
 
-    public ExternalTypeComputer(IAType resultType, List<IAType> argTypes) {
-        this.resultType = resultType;
-        this.argTypes = argTypes;
+    public ExternalTypeComputer(IAType resultPrimeType, List<IAType> paramPrimeTypes) {
+        this.resultType = resultPrimeType.getTypeTag() == ATypeTag.ANY ? resultPrimeType
+                : AUnionType.createUnknownableType(resultPrimeType);
+        this.paramPrimeTypes = paramPrimeTypes;
     }
 
     @Override
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/DatasetUtil.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/DatasetUtil.java
index 78c026d..3b312bb 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/DatasetUtil.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/DatasetUtil.java
@@ -100,8 +100,6 @@ public class DatasetUtil {
      */
     public static final byte OP_UPSERT = 0x03;
 
-    private static final String DATASET_INLINE_TYPE_PREFIX = "$d$t$";
-
     private DatasetUtil() {
     }
 
@@ -596,12 +594,4 @@ public class DatasetUtil {
         return nodeGroup;
     }
 
-    public static String createInlineTypeName(String datasetName, boolean forMetaItemType) {
-        char typeChar = forMetaItemType ? 'm' : 'i';
-        return DATASET_INLINE_TYPE_PREFIX + typeChar + '$' + datasetName;
-    }
-
-    public static boolean isInlineTypeName(Dataset dataset, DataverseName typeDataverseName, String typeName) {
-        return dataset.getDataverseName().equals(typeDataverseName) && typeName.startsWith(DATASET_INLINE_TYPE_PREFIX);
-    }
 }
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/TypeUtil.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/TypeUtil.java
index 4c3ad73..11dc1ee 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/TypeUtil.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/TypeUtil.java
@@ -26,12 +26,16 @@ import java.util.Map;
 
 import org.apache.asterix.common.exceptions.AsterixException;
 import org.apache.asterix.common.exceptions.ErrorCode;
+import org.apache.asterix.common.metadata.DataverseName;
+import org.apache.asterix.metadata.entities.Dataset;
 import org.apache.asterix.metadata.entities.Index;
 import org.apache.asterix.om.typecomputer.impl.TypeComputeUtils;
 import org.apache.asterix.om.types.ARecordType;
 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.asterix.om.types.TypeSignature;
 import org.apache.asterix.om.types.hierachy.ATypeHierarchy;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
@@ -42,6 +46,14 @@ import org.apache.hyracks.algebricks.common.utils.Pair;
  */
 public class TypeUtil {
 
+    public static final TypeSignature ANY_TYPE_SIGNATURE = new TypeSignature(BuiltinType.ANY);
+
+    private static final char TYPE_NAME_DELIMITER = '$';
+
+    private static final String DATASET_INLINE_TYPE_PREFIX = "$d$t$";
+
+    private static final String FUNCTION_INLINE_TYPE_PREFIX = "$f$t$";
+
     private TypeUtil() {
     }
 
@@ -240,4 +252,29 @@ public class TypeUtil {
         }
         return resType;
     }
+
+    public static boolean isReservedInlineTypeName(String typeName) {
+        return typeName.length() > 0 && typeName.charAt(0) == TYPE_NAME_DELIMITER;
+    }
+
+    public static String createDatasetInlineTypeName(String datasetName, boolean forMetaItemType) {
+        char typeChar = forMetaItemType ? 'm' : 'i';
+        return DATASET_INLINE_TYPE_PREFIX + typeChar + TYPE_NAME_DELIMITER + datasetName;
+    }
+
+    public static boolean isDatasetInlineTypeName(Dataset dataset, DataverseName typeDataverseName, String typeName) {
+        return dataset.getDataverseName().equals(typeDataverseName) && typeName.startsWith(DATASET_INLINE_TYPE_PREFIX);
+    }
+
+    public static String createFunctionParameterTypeName(String functionName, int arity, int parameterIndex) {
+        StringBuilder sb = new StringBuilder(FUNCTION_INLINE_TYPE_PREFIX.length() + functionName.length() + 8);
+        sb.append(FUNCTION_INLINE_TYPE_PREFIX).append(functionName).append(TYPE_NAME_DELIMITER).append(arity);
+        if (parameterIndex >= 0) {
+            sb.append(TYPE_NAME_DELIMITER).append(parameterIndex);
+        } else if (parameterIndex != -1) {
+            throw new IllegalArgumentException(String.valueOf(parameterIndex));
+        } // otherwise it's a return type
+
+        return sb.toString();
+    }
 }
diff --git a/asterixdb/asterix-metadata/src/test/java/org/apache/asterix/metadata/functions/ExternalFunctionCompilerUtilTest.java b/asterixdb/asterix-metadata/src/test/java/org/apache/asterix/metadata/functions/ExternalFunctionCompilerUtilTest.java
deleted file mode 100644
index 17b1213..0000000
--- a/asterixdb/asterix-metadata/src/test/java/org/apache/asterix/metadata/functions/ExternalFunctionCompilerUtilTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.metadata.functions;
-
-import java.util.LinkedList;
-
-import org.apache.asterix.common.functions.ExternalFunctionLanguage;
-import org.apache.asterix.common.functions.FunctionSignature;
-import org.apache.asterix.common.metadata.DataverseName;
-import org.apache.asterix.common.transactions.TxnId;
-import org.apache.asterix.metadata.MetadataTransactionContext;
-import org.apache.asterix.metadata.entities.Function;
-import org.apache.asterix.om.types.BuiltinType;
-import org.apache.asterix.om.types.IAType;
-import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class ExternalFunctionCompilerUtilTest {
-    @Test
-    public void test() throws AlgebricksException {
-        // given
-        MetadataTransactionContext txnCtx = new MetadataTransactionContext(new TxnId(1));
-        FunctionSignature signature = new FunctionSignature(DataverseName.createSinglePartName("test"), "test", 0);
-        Function function = new Function(signature, new LinkedList<>(), new LinkedList<>(), BuiltinType.ASTRING, "",
-                "SCALAR", ExternalFunctionLanguage.JAVA.name(), "", false, false, null, null);
-
-        // when
-        ExternalScalarFunctionInfo info =
-                (ExternalScalarFunctionInfo) ExternalFunctionCompilerUtil.getExternalFunctionInfo(txnCtx, function);
-
-        // then
-        IAType expectedType = BuiltinType.ASTRING;
-        Assert.assertEquals(expectedType, info.getReturnType());
-    }
-}
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/TypeSignature.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/TypeSignature.java
index ac6af0a..682ec6a 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/TypeSignature.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/types/TypeSignature.java
@@ -18,20 +18,25 @@
  */
 package org.apache.asterix.om.types;
 
+import java.io.Serializable;
 import java.util.Objects;
 
 import org.apache.asterix.common.metadata.DataverseName;
 
-public class TypeSignature {
+public class TypeSignature implements Serializable {
+
+    private static final long serialVersionUID = 1L;
 
     private final DataverseName dataverseName;
     private final String name;
-    private final String alias;
 
     public TypeSignature(DataverseName dataverseName, String name) {
         this.dataverseName = dataverseName;
         this.name = name;
-        this.alias = (dataverseName != null ? dataverseName.getCanonicalForm() : null) + "@" + name;
+    }
+
+    public TypeSignature(BuiltinType builtinType) {
+        this(null, builtinType.getTypeName());
     }
 
     @Override
@@ -46,12 +51,12 @@ public class TypeSignature {
 
     @Override
     public String toString() {
-        return alias;
+        return (dataverseName != null ? dataverseName.getCanonicalForm() : null) + "@" + name;
     }
 
     @Override
     public int hashCode() {
-        return alias.hashCode();
+        return Objects.hash(dataverseName, name);
     }
 
     public DataverseName getDataverseName() {
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/io/IOManager.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/io/IOManager.java
index c335312..6c35eff 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/io/IOManager.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-nc/src/main/java/org/apache/hyracks/control/nc/io/IOManager.java
@@ -81,7 +81,7 @@ public class IOManager implements IIOManager {
         for (IODeviceHandle d : ioDevices) {
             if (d.getWorkspace() != null) {
                 try {
-                    FileUtil.forceMkdirs(new File(d.getMount(), d.getWorkspace()));
+                    FileUtil.forceMkdirs(getWorkspaceFolder(d));
                 } catch (IOException e) {
                     throw HyracksDataException.create(e);
                 }
@@ -346,8 +346,13 @@ public class IOManager implements IIOManager {
         return dev.createFileRef(waPath + File.separator + waf.getName());
     }
 
-    public String getWorkspacePath(int index) {
-        return workspaces.get(index) != null ? workspaces.get(index).getWorkspace() : null;
+    public File getWorkspacePath(int index) {
+        IODeviceHandle dev = workspaces.get(index);
+        return dev != null ? getWorkspaceFolder(dev) : null;
+    }
+
+    private File getWorkspaceFolder(IODeviceHandle dev) {
+        return new File(dev.getMount(), dev.getWorkspace());
     }
 
     @Override
@@ -367,7 +372,7 @@ public class IOManager implements IIOManager {
     @Override
     public void deleteWorkspaceFiles() throws HyracksDataException {
         for (IODeviceHandle ioDevice : workspaces) {
-            File workspaceFolder = new File(ioDevice.getMount(), ioDevice.getWorkspace());
+            File workspaceFolder = getWorkspaceFolder(ioDevice);
             if (workspaceFolder.exists() && workspaceFolder.isDirectory()) {
                 File[] workspaceFiles = workspaceFolder.listFiles(WORKSPACE_FILES_FILTER);
                 for (File workspaceFile : workspaceFiles) {