Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id C34FF200BA3 for ; Thu, 6 Oct 2016 02:18:35 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id C1D5A160AF2; Thu, 6 Oct 2016 00:18:35 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 6E2EA160ADE for ; Thu, 6 Oct 2016 02:18:34 +0200 (CEST) Received: (qmail 93351 invoked by uid 500); 6 Oct 2016 00:18:31 -0000 Mailing-List: contact commits-help@hive.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: hive-dev@hive.apache.org Delivered-To: mailing list commits@hive.apache.org Received: (qmail 92688 invoked by uid 99); 6 Oct 2016 00:18:31 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 06 Oct 2016 00:18:31 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 3D056E098A; Thu, 6 Oct 2016 00:18:31 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: khorgath@apache.org To: commits@hive.apache.org Date: Thu, 06 Oct 2016 00:18:45 -0000 Message-Id: <5160ba7f775d4a54a4ecdc8a53b8c478@git.apache.org> In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [16/38] hive git commit: HIVE-14819: FunctionInfo for permanent functions shows TEMPORARY FunctionType (Jason Dere, reviewed by Sergey Shelukhin) archived-at: Thu, 06 Oct 2016 00:18:35 -0000 HIVE-14819: FunctionInfo for permanent functions shows TEMPORARY FunctionType (Jason Dere, reviewed by Sergey Shelukhin) Project: http://git-wip-us.apache.org/repos/asf/hive/repo Commit: http://git-wip-us.apache.org/repos/asf/hive/commit/74a6ff67 Tree: http://git-wip-us.apache.org/repos/asf/hive/tree/74a6ff67 Diff: http://git-wip-us.apache.org/repos/asf/hive/diff/74a6ff67 Branch: refs/heads/repl2 Commit: 74a6ff678f9312d946a7d55d73bf4a60127de763 Parents: 474425a Author: Jason Dere Authored: Thu Sep 29 13:35:17 2016 -0700 Committer: Jason Dere Committed: Thu Sep 29 13:35:17 2016 -0700 ---------------------------------------------------------------------- .../hadoop/hive/ql/exec/FunctionInfo.java | 20 ++-- .../hadoop/hive/ql/exec/FunctionRegistry.java | 3 +- .../apache/hadoop/hive/ql/exec/Registry.java | 96 ++++++++++++++---- .../hadoop/hive/ql/exec/WindowFunctionInfo.java | 4 +- .../translator/SqlFunctionConverter.java | 2 +- .../hive/ql/exec/TestFunctionRegistry.java | 100 +++++++++++++++++++ 6 files changed, 194 insertions(+), 31 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hive/blob/74a6ff67/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionInfo.java ---------------------------------------------------------------------- diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionInfo.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionInfo.java index 30ba996..8014dab 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionInfo.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionInfo.java @@ -73,36 +73,36 @@ public class FunctionInfo { this.discarded = new AtomicBoolean(false); // shared to all session functions } - public FunctionInfo(boolean isNative, String displayName, + public FunctionInfo(FunctionType functionType, String displayName, GenericUDF genericUDF, FunctionResource... resources) { - this.functionType = isNative ? FunctionType.BUILTIN : FunctionType.TEMPORARY; + this.functionType = functionType; this.displayName = displayName; this.genericUDF = genericUDF; this.isInternalTableFunction = false; this.resources = resources; } - public FunctionInfo(boolean isNative, String displayName, + public FunctionInfo(FunctionType functionType, String displayName, GenericUDAFResolver genericUDAFResolver, FunctionResource... resources) { - this.functionType = isNative ? FunctionType.BUILTIN : FunctionType.TEMPORARY; + this.functionType = functionType; this.displayName = displayName; this.genericUDAFResolver = genericUDAFResolver; this.isInternalTableFunction = false; this.resources = resources; } - public FunctionInfo(boolean isNative, String displayName, + public FunctionInfo(FunctionType functionType, String displayName, GenericUDTF genericUDTF, FunctionResource... resources) { - this.functionType = isNative ? FunctionType.BUILTIN : FunctionType.TEMPORARY; + this.functionType = functionType; this.displayName = displayName; this.genericUDTF = genericUDTF; this.isInternalTableFunction = false; this.resources = resources; } - public FunctionInfo(boolean isNative, String displayName, Class tFnCls, + public FunctionInfo(FunctionType functionType, String displayName, Class tFnCls, FunctionResource... resources) { - this.functionType = isNative ? FunctionType.BUILTIN : FunctionType.TEMPORARY; + this.functionType = functionType; this.displayName = displayName; this.tableFunctionResolver = tFnCls; PartitionTableFunctionDescription def = AnnotationUtils.getAnnotation( @@ -263,6 +263,10 @@ public class FunctionInfo { } } + public FunctionType getFunctionType() { + return functionType; + } + public static class FunctionResource { private final SessionState.ResourceType resourceType; private final String resourceURI; http://git-wip-us.apache.org/repos/asf/hive/blob/74a6ff67/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java ---------------------------------------------------------------------- diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java index de74c3e..b277f5e 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java @@ -1535,7 +1535,8 @@ public final class FunctionRegistry { } if (clazz != null) { - return system.isPermanentFunc(clazz); + // Use session registry - see Registry.isPermanentFunc() + return SessionState.getRegistryForWrite().isPermanentFunc(clazz); } return false; } http://git-wip-us.apache.org/repos/asf/hive/blob/74a6ff67/ql/src/java/org/apache/hadoop/hive/ql/exec/Registry.java ---------------------------------------------------------------------- diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/Registry.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/Registry.java index 05926b5..c274933 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/exec/Registry.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/Registry.java @@ -28,6 +28,7 @@ import org.apache.hadoop.hive.conf.HiveConf; import org.apache.hadoop.hive.conf.HiveConf.ConfVars; import org.apache.hadoop.hive.metastore.api.Function; import org.apache.hadoop.hive.ql.exec.FunctionInfo.FunctionResource; +import org.apache.hadoop.hive.ql.exec.FunctionInfo.FunctionType; import org.apache.hadoop.hive.ql.ErrorMsg; import org.apache.hadoop.hive.ql.metadata.Hive; import org.apache.hadoop.hive.ql.metadata.HiveException; @@ -104,31 +105,37 @@ public class Registry { * @return true if udfClass's type was recognized (so registration * succeeded); false otherwise */ - @SuppressWarnings("unchecked") public FunctionInfo registerFunction( String functionName, Class udfClass, FunctionResource... resources) { + FunctionType functionType = isNative ? FunctionType.BUILTIN : FunctionType.TEMPORARY; + return registerFunction(functionName, functionType, udfClass, resources); + } + + @SuppressWarnings("unchecked") + private FunctionInfo registerFunction( + String functionName, FunctionType functionType, Class udfClass, FunctionResource... resources) { FunctionUtils.UDFClassType udfClassType = FunctionUtils.getUDFClassType(udfClass); switch (udfClassType) { case UDF: return registerUDF( - functionName, (Class) udfClass, false, resources); + functionName, functionType, (Class) udfClass, false, functionName.toLowerCase(), resources); case GENERIC_UDF: return registerGenericUDF( - functionName, (Class) udfClass, resources); + functionName, functionType, (Class) udfClass, resources); case GENERIC_UDTF: return registerGenericUDTF( - functionName, (Class) udfClass, resources); + functionName, functionType, (Class) udfClass, resources); case UDAF: return registerUDAF( - functionName, (Class) udfClass, resources); + functionName, functionType, (Class) udfClass, resources); case GENERIC_UDAF_RESOLVER: return registerGenericUDAF( - functionName, (GenericUDAFResolver) - ReflectionUtil.newInstance(udfClass, null), resources); + functionName, functionType, + (GenericUDAFResolver) ReflectionUtil.newInstance(udfClass, null), resources); case TABLE_FUNCTION_RESOLVER: // native or not would be decided by annotation. need to evaluate that first - return registerTableFunction(functionName, + return registerTableFunction(functionName, functionType, (Class) udfClass, resources); } return null; @@ -143,8 +150,15 @@ public class Registry { public FunctionInfo registerUDF(String functionName, Class UDFClass, boolean isOperator, String displayName, FunctionResource... resources) { + FunctionType functionType = isNative ? FunctionType.BUILTIN : FunctionType.TEMPORARY; + return registerUDF(functionName, functionType, UDFClass, isOperator, displayName); + } + + private FunctionInfo registerUDF(String functionName, FunctionType functionType, + Class UDFClass, boolean isOperator, String displayName, + FunctionResource... resources) { validateClass(UDFClass, UDF.class); - FunctionInfo fI = new FunctionInfo(isNative, displayName, + FunctionInfo fI = new FunctionInfo(functionType, displayName, new GenericUDFBridge(displayName, isOperator, UDFClass.getName()), resources); addFunction(functionName, fI); return fI; @@ -152,8 +166,14 @@ public class Registry { public FunctionInfo registerGenericUDF(String functionName, Class genericUDFClass, FunctionResource... resources) { + FunctionType functionType = isNative ? FunctionType.BUILTIN : FunctionType.TEMPORARY; + return registerGenericUDF(functionName, functionType, genericUDFClass, resources); + } + + private FunctionInfo registerGenericUDF(String functionName, FunctionType functionType, + Class genericUDFClass, FunctionResource... resources) { validateClass(genericUDFClass, GenericUDF.class); - FunctionInfo fI = new FunctionInfo(isNative, functionName, + FunctionInfo fI = new FunctionInfo(functionType, functionName, ReflectionUtil.newInstance(genericUDFClass, null), resources); addFunction(functionName, fI); return fI; @@ -177,8 +197,14 @@ public class Registry { public FunctionInfo registerGenericUDTF(String functionName, Class genericUDTFClass, FunctionResource... resources) { + FunctionType functionType = isNative ? FunctionType.BUILTIN : FunctionType.TEMPORARY; + return registerGenericUDTF(functionName, functionType, genericUDTFClass, resources); + } + + private FunctionInfo registerGenericUDTF(String functionName, FunctionType functionType, + Class genericUDTFClass, FunctionResource... resources) { validateClass(genericUDTFClass, GenericUDTF.class); - FunctionInfo fI = new FunctionInfo(isNative, functionName, + FunctionInfo fI = new FunctionInfo(functionType, functionName, ReflectionUtil.newInstance(genericUDTFClass, null), resources); addFunction(functionName, fI); return fI; @@ -186,8 +212,14 @@ public class Registry { public FunctionInfo registerGenericUDAF(String functionName, GenericUDAFResolver genericUDAFResolver, FunctionResource... resources) { + FunctionType functionType = isNative ? FunctionType.BUILTIN : FunctionType.TEMPORARY; + return registerGenericUDAF(functionName, functionType, genericUDAFResolver, resources); + } + + private FunctionInfo registerGenericUDAF(String functionName, FunctionType functionType, + GenericUDAFResolver genericUDAFResolver, FunctionResource... resources) { FunctionInfo function = - new WindowFunctionInfo(isNative, functionName, genericUDAFResolver, resources); + new WindowFunctionInfo(functionType, functionName, genericUDAFResolver, resources); addFunction(functionName, function); addFunction(WINDOW_FUNC_PREFIX + functionName, function); return function; @@ -195,8 +227,14 @@ public class Registry { public FunctionInfo registerUDAF(String functionName, Class udafClass, FunctionResource... resources) { + FunctionType functionType = isNative ? FunctionType.BUILTIN : FunctionType.TEMPORARY; + return registerUDAF(functionName, functionType, udafClass, resources); + } + + private FunctionInfo registerUDAF(String functionName, FunctionType functionType, + Class udafClass, FunctionResource... resources) { validateClass(udafClass, UDAF.class); - FunctionInfo function = new WindowFunctionInfo(isNative, functionName, + FunctionInfo function = new WindowFunctionInfo(functionType, functionName, new GenericUDAFBridge(ReflectionUtil.newInstance(udafClass, null)), resources); addFunction(functionName, function); addFunction(WINDOW_FUNC_PREFIX + functionName, function); @@ -205,8 +243,14 @@ public class Registry { public FunctionInfo registerTableFunction(String functionName, Class tFnCls, FunctionResource... resources) { + FunctionType functionType = isNative ? FunctionType.BUILTIN : FunctionType.TEMPORARY; + return registerTableFunction(functionName, functionType, tFnCls, resources); + } + + private FunctionInfo registerTableFunction(String functionName, FunctionType functionType, + Class tFnCls, FunctionResource... resources) { validateClass(tFnCls, TableFunctionResolver.class); - FunctionInfo function = new FunctionInfo(isNative, functionName, tFnCls, resources); + FunctionInfo function = new FunctionInfo(functionType, functionName, tFnCls, resources); addFunction(functionName, function); return function; } @@ -219,7 +263,7 @@ public class Registry { public FunctionInfo registerMacro(String macroName, ExprNodeDesc body, List colNames, List colTypes, FunctionResource... resources) { GenericUDFMacro macro = new GenericUDFMacro(macroName, body, colNames, colTypes); - FunctionInfo fI = new FunctionInfo(isNative, macroName, macro, resources); + FunctionInfo fI = new FunctionInfo(FunctionType.TEMPORARY, macroName, macro, resources); addFunction(macroName, fI); return fI; } @@ -252,7 +296,8 @@ public class Registry { * @param wFn */ void registerWindowFunction(String name, GenericUDAFResolver wFn) { - addFunction(WINDOW_FUNC_PREFIX + name, new WindowFunctionInfo(isNative, name, wFn, null)); + FunctionType functionType = isNative ? FunctionType.BUILTIN : FunctionType.TEMPORARY; + addFunction(WINDOW_FUNC_PREFIX + name, new WindowFunctionInfo(functionType, name, wFn, null)); } private void validateClass(Class input, Class expected) { @@ -310,6 +355,12 @@ public class Registry { } public boolean isPermanentFunc(Class udfClass) { + // Note that permanent functions can only be properly checked from the session registry. + // If permanent functions are read from the metastore during Hive initialization, + // the JARs are not loaded for the UDFs during that time and so Hive is unable to instantiate + // the UDf classes to add to the persistent functions set. + // Once a permanent UDF has been referenced in a session its FunctionInfo should be registered + // in the session registry (and persistent set updated), so it can be looked up there. return udfClass != null && persistent.containsKey(udfClass); } @@ -448,7 +499,10 @@ public class Registry { private void addFunction(String functionName, FunctionInfo function) { lock.lock(); try { - if (isNative != function.isNative()) { + // Built-in functions shouldn't go in the session registry, + // and temp functions shouldn't go in the system registry. + // Persistent functions can be in either registry. + if ((!isNative && function.isBuiltIn()) || (isNative && !function.isNative())) { throw new RuntimeException("Function " + functionName + " is not for this registry"); } functionName = functionName.toLowerCase(); @@ -463,7 +517,8 @@ public class Registry { mFunctions.put(functionName, function); if (function.isBuiltIn()) { builtIns.add(function.getFunctionClass()); - } else if (function.isPersistent()) { + } else if (function.isPersistent() && !isNative) { + // System registry should not be used to check persistent functions - see isPermanentFunc() Class functionClass = getPermanentUdfClass(function); Integer refCount = persistent.get(functionClass); persistent.put(functionClass, Integer.valueOf(refCount == null ? 1 : refCount + 1)); @@ -597,7 +652,10 @@ public class Registry { ClassLoader loader = Utilities.getSessionSpecifiedClassLoader(); Class udfClass = Class.forName(function.getClassName(), true, loader); - ret = FunctionRegistry.registerTemporaryUDF(qualifiedName, udfClass, resources); + // Make sure the FunctionInfo is listed as PERSISTENT (rather than TEMPORARY) + // when it is registered to the system registry. + ret = SessionState.getRegistryForWrite().registerFunction( + qualifiedName, FunctionType.PERSISTENT, udfClass, resources); if (ret == null) { LOG.error(function.getClassName() + " is not a valid UDF class and was not registered."); } http://git-wip-us.apache.org/repos/asf/hive/blob/74a6ff67/ql/src/java/org/apache/hadoop/hive/ql/exec/WindowFunctionInfo.java ---------------------------------------------------------------------- diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/WindowFunctionInfo.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/WindowFunctionInfo.java index a16d9e5..5e57ccd 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/exec/WindowFunctionInfo.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/WindowFunctionInfo.java @@ -28,9 +28,9 @@ public class WindowFunctionInfo extends FunctionInfo { private final boolean pivotResult; private final boolean impliesOrder; - public WindowFunctionInfo(boolean isNative, String functionName, + public WindowFunctionInfo(FunctionType functionType, String functionName, GenericUDAFResolver resolver, FunctionResource[] resources) { - super(isNative, functionName, resolver, resources); + super(functionType, functionName, resolver, resources); WindowFunctionDescription def = AnnotationUtils.getAnnotation(resolver.getClass(), WindowFunctionDescription.class); supportsWindow = def == null ? true : def.supportsWindow(); http://git-wip-us.apache.org/repos/asf/hive/blob/74a6ff67/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/translator/SqlFunctionConverter.java ---------------------------------------------------------------------- diff --git a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/translator/SqlFunctionConverter.java b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/translator/SqlFunctionConverter.java index 911b86b..53e4a2a 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/translator/SqlFunctionConverter.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/translator/SqlFunctionConverter.java @@ -191,7 +191,7 @@ public class SqlFunctionConverter { throw new RuntimeException(e); } return new FunctionInfo( - fi.isNative(), fi.getDisplayName(), (GenericUDF) udf, fi.getResources()); + fi.getFunctionType(), fi.getDisplayName(), (GenericUDF) udf, fi.getResources()); } // TODO: 1) handle Agg Func Name translation 2) is it correct to add func http://git-wip-us.apache.org/repos/asf/hive/blob/74a6ff67/ql/src/test/org/apache/hadoop/hive/ql/exec/TestFunctionRegistry.java ---------------------------------------------------------------------- diff --git a/ql/src/test/org/apache/hadoop/hive/ql/exec/TestFunctionRegistry.java b/ql/src/test/org/apache/hadoop/hive/ql/exec/TestFunctionRegistry.java index d2d5a1b..2192a89 100644 --- a/ql/src/test/org/apache/hadoop/hive/ql/exec/TestFunctionRegistry.java +++ b/ql/src/test/org/apache/hadoop/hive/ql/exec/TestFunctionRegistry.java @@ -27,7 +27,17 @@ import junit.framework.TestCase; import org.apache.hadoop.hive.common.type.HiveVarchar; import org.apache.hadoop.hive.conf.HiveConf; +import org.apache.hadoop.hive.ql.exec.FunctionInfo.FunctionResource; +import org.apache.hadoop.hive.ql.exec.FunctionInfo.FunctionType; +import org.apache.hadoop.hive.ql.plan.ExprNodeDesc; +import org.apache.hadoop.hive.ql.plan.ExprNodeGenericFuncDesc; import org.apache.hadoop.hive.ql.session.SessionState; +import org.apache.hadoop.hive.ql.udf.UDFLn; +import org.apache.hadoop.hive.ql.udf.generic.GenericUDAFMax; +import org.apache.hadoop.hive.ql.udf.generic.GenericUDF; +import org.apache.hadoop.hive.ql.udf.generic.GenericUDFConcat; +import org.apache.hadoop.hive.ql.udf.generic.GenericUDFCurrentTimestamp; +import org.apache.hadoop.hive.ql.udf.generic.GenericUDTFExplode; import org.apache.hadoop.hive.serde2.io.DateWritable; import org.apache.hadoop.hive.serde2.io.DoubleWritable; import org.apache.hadoop.hive.serde2.io.HiveDecimalWritable; @@ -406,4 +416,94 @@ public class TestFunctionRegistry extends TestCase { Assert.assertTrue(FunctionRegistry.impliesOrder("lag")); Assert.assertFalse(FunctionRegistry.impliesOrder("min")); } + + public void testRegisterTemporaryFunctions() throws Exception { + FunctionResource[] emptyResources = new FunctionResource[] {}; + + // UDF + FunctionRegistry.registerTemporaryUDF("tmp_ln", UDFLn.class, emptyResources); + FunctionInfo functionInfo = FunctionRegistry.getFunctionInfo("tmp_ln"); + assertFalse(functionInfo.isNative()); + + // GenericUDF + FunctionRegistry.registerTemporaryUDF("tmp_concat", GenericUDFConcat.class, emptyResources); + functionInfo = FunctionRegistry.getFunctionInfo("tmp_concat"); + assertFalse(functionInfo.isNative()); + + // GenericUDAF + FunctionRegistry.registerTemporaryUDF("tmp_max",GenericUDAFMax.class, emptyResources); + functionInfo = FunctionRegistry.getFunctionInfo("tmp_max"); + assertFalse(functionInfo.isNative()); + functionInfo = FunctionRegistry.getWindowFunctionInfo("tmp_max"); + assertFalse(functionInfo.isNative()); + + // UDTF + FunctionRegistry.registerTemporaryUDF("tmp_explode", GenericUDTFExplode.class, emptyResources); + functionInfo = FunctionRegistry.getFunctionInfo("tmp_explode"); + assertFalse(functionInfo.isNative()); + } + + public void testRegisterPermanentFunction() throws Exception { + FunctionResource[] emptyResources = new FunctionResource[] {}; + + // UDF + FunctionRegistry.registerPermanentFunction("perm_ln", UDFLn.class.getName(), true, emptyResources); + FunctionInfo functionInfo = FunctionRegistry.getFunctionInfo("perm_ln"); + assertTrue(functionInfo.isPersistent()); + assertTrue(functionInfo.isNative()); + assertFalse(functionInfo.isBuiltIn()); + functionInfo = FunctionRegistry.getFunctionInfo("default.perm_ln"); + assertTrue(functionInfo.isPersistent()); + assertTrue(functionInfo.isNative()); + assertFalse(functionInfo.isBuiltIn()); + + // GenericUDF + FunctionRegistry.registerPermanentFunction("default.perm_concat", + GenericUDFConcat.class.getName(), true, emptyResources); + functionInfo = FunctionRegistry.getFunctionInfo("default.perm_concat"); + assertTrue(functionInfo.isPersistent()); + assertTrue(functionInfo.isNative()); + assertFalse(functionInfo.isBuiltIn()); + + // GenericUDAF + FunctionRegistry.registerPermanentFunction("default.perm_max", + GenericUDAFMax.class.getName(), true, emptyResources); + functionInfo = FunctionRegistry.getFunctionInfo("default.perm_max"); + assertTrue(functionInfo.isPersistent()); + functionInfo = FunctionRegistry.getWindowFunctionInfo("default.perm_max"); + assertTrue(functionInfo.isPersistent()); + assertTrue(functionInfo.isNative()); + assertFalse(functionInfo.isBuiltIn()); + + // UDTF + FunctionRegistry.registerPermanentFunction("default.perm_explode", + GenericUDTFExplode.class.getName(), true, emptyResources); + functionInfo = FunctionRegistry.getFunctionInfo("default.perm_explode"); + assertTrue(functionInfo.isPersistent()); + assertTrue(functionInfo.isNative()); + assertFalse(functionInfo.isBuiltIn()); + } + + public void testBuiltInFunction() throws Exception { + FunctionInfo functionInfo = FunctionRegistry.getFunctionInfo("ln"); + assertTrue(functionInfo.isBuiltIn()); + assertTrue(functionInfo.isNative()); + } + + public void testIsPermanentFunction() throws Exception { + // Setup exprNode + GenericUDF udf = new GenericUDFCurrentTimestamp(); + List children = new ArrayList(); + ExprNodeGenericFuncDesc fnExpr = + new ExprNodeGenericFuncDesc(TypeInfoFactory.timestampTypeInfo, udf, children); + + assertFalse("Function not added as permanent yet", FunctionRegistry.isPermanentFunction(fnExpr)); + + // Now register as permanent function + FunctionResource[] emptyResources = new FunctionResource[] {}; + FunctionRegistry.registerPermanentFunction("default.perm_current_timestamp", + GenericUDFCurrentTimestamp.class.getName(), true, emptyResources); + + assertTrue("Function should now be recognized as permanent function", FunctionRegistry.isPermanentFunction(fnExpr)); + } }