diff --git conf/ivysettings.xml conf/ivysettings.xml index bda842a..aa10f43 100644 --- conf/ivysettings.xml +++ conf/ivysettings.xml @@ -1,4 +1,3 @@ - + + + + + + - + + diff --git itests/custom-udfs/pom.xml itests/custom-udfs/pom.xml new file mode 100644 index 0000000..69e1f70 --- /dev/null +++ itests/custom-udfs/pom.xml @@ -0,0 +1,62 @@ + + + + 4.0.0 + + org.apache.hive + hive-it + 2.1.0-SNAPSHOT + ../pom.xml + + + hive-it-custom-udfs + pom + Hive Integration - Custom udfs + Custom udfs used in hive itest can be defined under this module + + + ../.. + + + + + udf-classloader-util + udf-classloader-udf1 + udf-classloader-udf2 + + + + + + org.apache.hive + hive-exec + ${project.version} + true + + + org.apache.hadoop + hadoop-common + ${hadoop.version} + true + + + diff --git itests/custom-udfs/udf-classloader-udf1/pom.xml itests/custom-udfs/udf-classloader-udf1/pom.xml new file mode 100644 index 0000000..5f35c63 --- /dev/null +++ itests/custom-udfs/udf-classloader-udf1/pom.xml @@ -0,0 +1,43 @@ + + + + 4.0.0 + + org.apache.hive + hive-it-custom-udfs + 2.1.0-SNAPSHOT + ../pom.xml + + + org.apache.hive.hive-it-custom-udfs + udf-classloader-udf1 + jar + Hive Integration - Custom UDFs - udf-classloader-udf1 + + + + org.apache.hive.hive-it-custom-udfs + udf-classloader-util + ${project.version} + + + + + ../../.. + + + diff --git itests/custom-udfs/udf-classloader-udf1/src/main/java/hive/it/custom/udfs/UDF1.java itests/custom-udfs/udf-classloader-udf1/src/main/java/hive/it/custom/udfs/UDF1.java new file mode 100644 index 0000000..6816190 --- /dev/null +++ itests/custom-udfs/udf-classloader-udf1/src/main/java/hive/it/custom/udfs/UDF1.java @@ -0,0 +1,58 @@ +/** + * 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 hive.it.custom.udfs; + +import org.apache.hadoop.hive.ql.exec.UDFArgumentException; +import org.apache.hadoop.hive.ql.metadata.HiveException; +import org.apache.hadoop.hive.ql.udf.generic.GenericUDF; +import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; +import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory; + + +public class UDF1 extends GenericUDF { + public UDF1() { + Util util = new Util(); + System.out.println( + "constructor: " + getClass().getSimpleName() + " classloader: " + getClass().getClassLoader() + ", " + util + " classloader: " + + util.getClass().getClassLoader()); + } + + @Override + public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException { + Util util = new Util(); + System.out.println( + "initialize: " + getClass().getSimpleName() + " classloader: " + getClass().getClassLoader() + ", " + util + " classloader: " + + util.getClass().getClassLoader()); + return PrimitiveObjectInspectorFactory.javaStringObjectInspector; + } + + @Override + public Object evaluate(DeferredObject[] arguments) throws HiveException { + Util util = new Util(); + System.out.println( + "evaluate: " + getClass().getSimpleName() + " classloader: " + getClass().getClassLoader() + ", " + util + " classloader: " + + util.getClass().getClassLoader()); + return getClass().getSimpleName(); + } + + @Override + public String getDisplayString(String[] children) { + return getClass().getName(); + } +} diff --git itests/custom-udfs/udf-classloader-udf2/pom.xml itests/custom-udfs/udf-classloader-udf2/pom.xml new file mode 100644 index 0000000..8edca63 --- /dev/null +++ itests/custom-udfs/udf-classloader-udf2/pom.xml @@ -0,0 +1,43 @@ + + + + 4.0.0 + + org.apache.hive + hive-it-custom-udfs + 2.1.0-SNAPSHOT + ../pom.xml + + + org.apache.hive.hive-it-custom-udfs + udf-classloader-udf2 + jar + Hive Integration - Custom UDFs - udf-classloader-udf2 + + + + org.apache.hive.hive-it-custom-udfs + udf-classloader-util + ${project.version} + + + + + ../../.. + + + diff --git itests/custom-udfs/udf-classloader-udf2/src/main/java/hive/it/custom/udfs/UDF2.java itests/custom-udfs/udf-classloader-udf2/src/main/java/hive/it/custom/udfs/UDF2.java new file mode 100644 index 0000000..4bb8772 --- /dev/null +++ itests/custom-udfs/udf-classloader-udf2/src/main/java/hive/it/custom/udfs/UDF2.java @@ -0,0 +1,60 @@ +/** + * 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 hive.it.custom.udfs; + +import org.apache.hadoop.hive.ql.exec.UDFArgumentException; +import org.apache.hadoop.hive.ql.metadata.HiveException; +import org.apache.hadoop.hive.ql.udf.generic.GenericUDF; +import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; +import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory; + + +public class UDF2 extends GenericUDF { + public UDF2() { + Util util = new Util(); + System.out.println( + "constructor: " + getClass().getSimpleName() + " classloader: " + getClass().getClassLoader() + ", " + util + + " classloader: " + + util.getClass().getClassLoader()); + } + + @Override + public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException { + Util util = new Util(); + System.out.println( + "initialize: " + getClass().getSimpleName() + " classloader: " + getClass().getClassLoader() + ", " + util + + " classloader: " + + util.getClass().getClassLoader()); + return PrimitiveObjectInspectorFactory.javaStringObjectInspector; + } + + @Override + public Object evaluate(DeferredObject[] arguments) throws HiveException { + Util util = new Util(); + System.out.println( + "evaluate: " + getClass().getSimpleName() + " classloader: " + getClass().getClassLoader() + ", " + util + + " classloader: " + + util.getClass().getClassLoader()); + return getClass().getSimpleName(); + } + + @Override + public String getDisplayString(String[] children) { + return getClass().getName(); + } +} diff --git itests/custom-udfs/udf-classloader-util/pom.xml itests/custom-udfs/udf-classloader-util/pom.xml new file mode 100644 index 0000000..b6475f5 --- /dev/null +++ itests/custom-udfs/udf-classloader-util/pom.xml @@ -0,0 +1,35 @@ + + + + 4.0.0 + + org.apache.hive + hive-it-custom-udfs + 2.1.0-SNAPSHOT + ../pom.xml + + + org.apache.hive.hive-it-custom-udfs + udf-classloader-util + jar + Hive Integration - Custom UDFs - udf-classloader-util + + + ../../.. + + + diff --git itests/custom-udfs/udf-classloader-util/src/main/java/hive/it/custom/udfs/Util.java itests/custom-udfs/udf-classloader-util/src/main/java/hive/it/custom/udfs/Util.java new file mode 100644 index 0000000..8881ec7 --- /dev/null +++ itests/custom-udfs/udf-classloader-util/src/main/java/hive/it/custom/udfs/Util.java @@ -0,0 +1,25 @@ +/** + * 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 hive.it.custom.udfs; + +public class Util { + @Override + public String toString() { + return getClass().getSimpleName(); + } +} diff --git itests/hive-unit/src/test/java/org/apache/hadoop/hive/ql/security/authorization/plugin/TestHiveAuthorizerShowFilters.java itests/hive-unit/src/test/java/org/apache/hadoop/hive/ql/security/authorization/plugin/TestHiveAuthorizerShowFilters.java index 0c03a00..5922a8c 100644 --- itests/hive-unit/src/test/java/org/apache/hadoop/hive/ql/security/authorization/plugin/TestHiveAuthorizerShowFilters.java +++ itests/hive-unit/src/test/java/org/apache/hadoop/hive/ql/security/authorization/plugin/TestHiveAuthorizerShowFilters.java @@ -58,7 +58,7 @@ private static final String dbName2 = (TestHiveAuthorizerShowFilters.class.getSimpleName() + "db2") .toLowerCase(); - static HiveAuthorizer mockedAuthorizer; + protected static HiveAuthorizer mockedAuthorizer; static final List AllTables = getSortedList(tableName1, tableName2); static final List AllDbs = getSortedList("default", dbName1, dbName2); @@ -73,28 +73,28 @@ * HiveAuthorizer.filterListCmdObjects, and stores the list argument in * filterArguments */ - static class MockedHiveAuthorizerFactory implements HiveAuthorizerFactory { + protected static class MockedHiveAuthorizerFactory implements HiveAuthorizerFactory { + protected abstract class AuthorizerWithFilterCmdImpl implements HiveAuthorizer { + @Override + public List filterListCmdObjects(List listObjs, + HiveAuthzContext context) throws HiveAuthzPluginException, HiveAccessControlException { + // capture arguments in static + filterArguments = listObjs; + // return static variable with results, if it is set to some set of + // values + // otherwise return the arguments + if (filteredResults.size() == 0) { + return filterArguments; + } + return filteredResults; + } + } + @Override public HiveAuthorizer createHiveAuthorizer(HiveMetastoreClientFactory metastoreClientFactory, HiveConf conf, HiveAuthenticationProvider authenticator, HiveAuthzSessionContext ctx) { Mockito.validateMockitoUsage(); - abstract class AuthorizerWithFilterCmdImpl implements HiveAuthorizer { - @Override - public List filterListCmdObjects(List listObjs, - HiveAuthzContext context) throws HiveAuthzPluginException, HiveAccessControlException { - // capture arguments in static - filterArguments = listObjs; - // return static variable with results, if it is set to some set of - // values - // otherwise return the arguments - if (filteredResults.size() == 0) { - return filterArguments; - } - return filteredResults; - } - } - mockedAuthorizer = Mockito.mock(AuthorizerWithFilterCmdImpl.class, Mockito.withSettings() .verboseLogging()); diff --git itests/pom.xml itests/pom.xml index 5d8249f..fb0a613 100644 --- itests/pom.xml +++ itests/pom.xml @@ -33,6 +33,7 @@ custom-serde + custom-udfs hcatalog-unit hive-unit util diff --git itests/qtest/pom.xml itests/qtest/pom.xml index 8f6807a..ec2fc85 100644 --- itests/qtest/pom.xml +++ itests/qtest/pom.xml @@ -656,7 +656,6 @@ initScript="${initScript}" cleanupScript="q_test_cleanup.sql"/> - diff --git ql/src/java/org/apache/hadoop/hive/ql/exec/UDFClassLoader.java ql/src/java/org/apache/hadoop/hive/ql/exec/UDFClassLoader.java new file mode 100644 index 0000000..c363803 --- /dev/null +++ ql/src/java/org/apache/hadoop/hive/ql/exec/UDFClassLoader.java @@ -0,0 +1,70 @@ +/** + * 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.hadoop.hive.ql.exec; + +import com.google.common.base.Preconditions; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import org.apache.hadoop.hive.ql.session.SessionState; + + +/** + * {@link UDFClassLoader} is used to dynamically register + * udf (and related) jars + * + * This was introducted to fix HIVE-11878 + * + * Each session will have its own instance of {@link UDFClassLoader} + * This is to support HiveServer2 where there can be multiple + * active sessions. Addition/removal of jars/resources in one + * session should not affect other sessions. + */ +public class UDFClassLoader extends URLClassLoader { + private boolean isClosed; + + public UDFClassLoader(URL[] urls) { + super(urls); + isClosed = false; + } + + public UDFClassLoader(URL[] urls, ClassLoader parent) { + super(urls, parent); + isClosed = false; + } + + @Override + public void addURL(URL url) { + Preconditions.checkState(!isClosed, getClass().getSimpleName() + " is already closed"); + super.addURL(url); + } + + /** + * See {@link URLClassLoader#close} + */ + public boolean isClosed() { + return isClosed; + } + + @Override + public void close() throws IOException { + isClosed = true; + super.close(); + } +} diff --git ql/src/java/org/apache/hadoop/hive/ql/exec/Utilities.java ql/src/java/org/apache/hadoop/hive/ql/exec/Utilities.java index c01994f..54abdef 100644 --- ql/src/java/org/apache/hadoop/hive/ql/exec/Utilities.java +++ ql/src/java/org/apache/hadoop/hive/ql/exec/Utilities.java @@ -18,6 +18,9 @@ package org.apache.hadoop.hive.ql.exec; +import java.util.ArrayList; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import java.beans.DefaultPersistenceDelegate; import java.beans.Encoder; import java.beans.Expression; @@ -1748,6 +1751,19 @@ private static URL urlFromPathString(String onestr) { return result; } + private static boolean useExistingClassLoader(ClassLoader cl) { + if (!(cl instanceof UDFClassLoader)) { + // Cannot use the same classloader if it is not an instance of {@code UDFClassLoader} + return false; + } + final UDFClassLoader udfClassLoader = (UDFClassLoader) cl; + if (udfClassLoader.isClosed()) { + // The classloader may have been closed, Cannot add to the same instance + return false; + } + return true; + } + /** * Add new elements to the classpath. * @@ -1755,24 +1771,28 @@ private static URL urlFromPathString(String onestr) { * Array of classpath elements */ public static ClassLoader addToClassPath(ClassLoader cloader, String[] newPaths) throws Exception { - URLClassLoader loader = (URLClassLoader) cloader; - List curPath = Arrays.asList(loader.getURLs()); - ArrayList newPath = new ArrayList(); - - // get a list with the current classpath components - for (URL onePath : curPath) { - newPath.add(onePath); + final URLClassLoader loader = (URLClassLoader) cloader; + if (useExistingClassLoader(cloader)) { + final UDFClassLoader udfClassLoader = (UDFClassLoader) loader; + for (String path : newPaths) { + udfClassLoader.addURL(urlFromPathString(path)); + } + return udfClassLoader; + } else { + return createUDFClassLoader(loader, newPaths); } - curPath = newPath; + } + public static ClassLoader createUDFClassLoader(URLClassLoader loader, String[] newPaths) { + final Set curPathsSet = Sets.newHashSet(loader.getURLs()); + final List curPaths = Lists.newArrayList(curPathsSet); for (String onestr : newPaths) { - URL oneurl = urlFromPathString(onestr); - if (oneurl != null && !curPath.contains(oneurl)) { - curPath.add(oneurl); + final URL oneurl = urlFromPathString(onestr); + if (oneurl != null && !curPathsSet.contains(oneurl)) { + curPaths.add(oneurl); } } - - return new URLClassLoader(curPath.toArray(new URL[0]), loader); + return new UDFClassLoader(curPaths.toArray(new URL[0]), loader); } /** @@ -1793,13 +1813,13 @@ public static void removeFromClassPath(String[] pathsToRemove) throws Exception } } JavaUtils.closeClassLoader(loader); -//this loader is closed, remove it from cached registry loaders to avoid remove it again. + // This loader is closed, remove it from cached registry loaders to avoid removing it again. Registry reg = SessionState.getRegistry(); if(reg != null) { reg.removeFromUDFLoaders(loader); } - loader = new URLClassLoader(newPath.toArray(new URL[0])); + loader = new UDFClassLoader(newPath.toArray(new URL[0])); curThread.setContextClassLoader(loader); SessionState.get().getConf().setClassLoader(loader); } diff --git ql/src/java/org/apache/hadoop/hive/ql/session/SessionState.java ql/src/java/org/apache/hadoop/hive/ql/session/SessionState.java index 5c69fb6..c066c7a 100644 --- ql/src/java/org/apache/hadoop/hive/ql/session/SessionState.java +++ ql/src/java/org/apache/hadoop/hive/ql/session/SessionState.java @@ -362,7 +362,12 @@ public SessionState(HiveConf conf, String userName) { if (StringUtils.isEmpty(conf.getVar(HiveConf.ConfVars.HIVESESSIONID))) { conf.setVar(HiveConf.ConfVars.HIVESESSIONID, makeSessionId()); } - parentLoader = JavaUtils.getClassLoader(); + // Using system classloader as the parent. Using thread context + // classloader as parent can pollute the session. See HIVE-11878 + parentLoader = SessionState.class.getClassLoader(); + // Make sure that each session has its own UDFClassloader. For details see {@link UDFClassLoader} + final ClassLoader currentLoader = Utilities.createUDFClassLoader((URLClassLoader) parentLoader, new String[]{}); + this.conf.setClassLoader(currentLoader); } public void setCmd(String cmdString) { @@ -1273,7 +1278,7 @@ private static String getURLType(String value) throws URISyntaxException { return scheme; } - List resolveAndDownload(ResourceType t, String value, boolean convertToUnix) throws URISyntaxException, + protected List resolveAndDownload(ResourceType t, String value, boolean convertToUnix) throws URISyntaxException, IOException { URI uri = createURI(value); if (getURLType(value).equals("file")) { diff --git ql/src/test/queries/clientpositive/udf_classloader.q ql/src/test/queries/clientpositive/udf_classloader.q new file mode 100644 index 0000000..82678c2 --- /dev/null +++ ql/src/test/queries/clientpositive/udf_classloader.q @@ -0,0 +1,16 @@ +ADD JAR ${system:maven.local.repository}/org/apache/hive/hive-it-custom-udfs/udf-classloader-udf1/${system:hive.version}/udf-classloader-udf1-${system:hive.version}.jar; +ADD JAR ${system:maven.local.repository}/org/apache/hive/hive-it-custom-udfs/udf-classloader-util/${system:hive.version}/udf-classloader-util-${system:hive.version}.jar; +ADD JAR ${system:maven.local.repository}/org/apache/hive/hive-it-custom-udfs/udf-classloader-udf2/${system:hive.version}/udf-classloader-udf2-${system:hive.version}.jar; + +CREATE TEMPORARY FUNCTION f1 AS 'hive.it.custom.udfs.UDF1'; +CREATE TEMPORARY FUNCTION f2 AS 'hive.it.custom.udfs.UDF2'; + +-- udf-classloader-udf1.jar contains f1 which relies on udf-classloader-util.jar, +-- similiary udf-classloader-udf2.jar contains f2 which also relies on udf-classloader-util.jar. +SELECT f1(*), f2(*) FROM SRC limit 1; + +DELETE JAR ${system:maven.local.repository}/org/apache/hive/hive-it-custom-udfs/udf-classloader-udf2/${system:hive.version}/udf-classloader-udf2-${system:hive.version}.jar; +SELECT f1(*) FROM SRC limit 1; + +ADD JAR ${system:maven.local.repository}/org/apache/hive/hive-it-custom-udfs/udf-classloader-udf2/${system:hive.version}/udf-classloader-udf2-${system:hive.version}.jar; +SELECT f2(*) FROM SRC limit 1; diff --git ql/src/test/queries/clientpositive/udf_classloader_dynamic_dependency_resolution.q ql/src/test/queries/clientpositive/udf_classloader_dynamic_dependency_resolution.q new file mode 100644 index 0000000..2ceeaa3 --- /dev/null +++ ql/src/test/queries/clientpositive/udf_classloader_dynamic_dependency_resolution.q @@ -0,0 +1,16 @@ +ADD JAR ivy://org.apache.hive.hive-it-custom-udfs:udf-classloader-udf1:+; +ADD JAR ivy://org.apache.hive.hive-it-custom-udfs:udf-classloader-util:+; +ADD JAR ivy://org.apache.hive.hive-it-custom-udfs:udf-classloader-udf2:+; + +CREATE TEMPORARY FUNCTION f1 AS 'hive.it.custom.udfs.UDF1'; +CREATE TEMPORARY FUNCTION f2 AS 'hive.it.custom.udfs.UDF2'; + +-- udf-classloader-udf1.jar contains f1 which relies on udf-classloader-util.jar, +-- similiary udf-classloader-udf2.jar contains f2 which also relies on udf-classloader-util.jar. +SELECT f1(*), f2(*) FROM SRC limit 1; + +DELETE JAR ivy://org.apache.hive.hive-it-custom-udfs:udf-classloader-udf2:+; +SELECT f1(*) FROM SRC limit 1; + +ADD JAR ivy://org.apache.hive.hive-it-custom-udfs:udf-classloader-udf2:+; +SELECT f2(*) FROM SRC limit 1; diff --git ql/src/test/results/clientpositive/udf_classloader.q.out ql/src/test/results/clientpositive/udf_classloader.q.out new file mode 100644 index 0000000..031d88a --- /dev/null +++ ql/src/test/results/clientpositive/udf_classloader.q.out @@ -0,0 +1,43 @@ +PREHOOK: query: CREATE TEMPORARY FUNCTION f1 AS 'hive.it.custom.udfs.UDF1' +PREHOOK: type: CREATEFUNCTION +PREHOOK: Output: f1 +POSTHOOK: query: CREATE TEMPORARY FUNCTION f1 AS 'hive.it.custom.udfs.UDF1' +POSTHOOK: type: CREATEFUNCTION +POSTHOOK: Output: f1 +PREHOOK: query: CREATE TEMPORARY FUNCTION f2 AS 'hive.it.custom.udfs.UDF2' +PREHOOK: type: CREATEFUNCTION +PREHOOK: Output: f2 +POSTHOOK: query: CREATE TEMPORARY FUNCTION f2 AS 'hive.it.custom.udfs.UDF2' +POSTHOOK: type: CREATEFUNCTION +POSTHOOK: Output: f2 +PREHOOK: query: -- udf-classloader-udf1.jar contains f1 which relies on udf-classloader-util.jar, +-- similiary udf-classloader-udf2.jar contains f2 which also relies on udf-classloader-util.jar. +SELECT f1(*), f2(*) FROM SRC limit 1 +PREHOOK: type: QUERY +PREHOOK: Input: default@src +#### A masked pattern was here #### +POSTHOOK: query: -- udf-classloader-udf1.jar contains f1 which relies on udf-classloader-util.jar, +-- similiary udf-classloader-udf2.jar contains f2 which also relies on udf-classloader-util.jar. +SELECT f1(*), f2(*) FROM SRC limit 1 +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +#### A masked pattern was here #### +UDF1 UDF2 +PREHOOK: query: SELECT f1(*) FROM SRC limit 1 +PREHOOK: type: QUERY +PREHOOK: Input: default@src +#### A masked pattern was here #### +POSTHOOK: query: SELECT f1(*) FROM SRC limit 1 +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +#### A masked pattern was here #### +UDF1 +PREHOOK: query: SELECT f2(*) FROM SRC limit 1 +PREHOOK: type: QUERY +PREHOOK: Input: default@src +#### A masked pattern was here #### +POSTHOOK: query: SELECT f2(*) FROM SRC limit 1 +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +#### A masked pattern was here #### +UDF2 diff --git ql/src/test/results/clientpositive/udf_classloader_dynamic_dependency_resolution.q.out ql/src/test/results/clientpositive/udf_classloader_dynamic_dependency_resolution.q.out new file mode 100644 index 0000000..031d88a --- /dev/null +++ ql/src/test/results/clientpositive/udf_classloader_dynamic_dependency_resolution.q.out @@ -0,0 +1,43 @@ +PREHOOK: query: CREATE TEMPORARY FUNCTION f1 AS 'hive.it.custom.udfs.UDF1' +PREHOOK: type: CREATEFUNCTION +PREHOOK: Output: f1 +POSTHOOK: query: CREATE TEMPORARY FUNCTION f1 AS 'hive.it.custom.udfs.UDF1' +POSTHOOK: type: CREATEFUNCTION +POSTHOOK: Output: f1 +PREHOOK: query: CREATE TEMPORARY FUNCTION f2 AS 'hive.it.custom.udfs.UDF2' +PREHOOK: type: CREATEFUNCTION +PREHOOK: Output: f2 +POSTHOOK: query: CREATE TEMPORARY FUNCTION f2 AS 'hive.it.custom.udfs.UDF2' +POSTHOOK: type: CREATEFUNCTION +POSTHOOK: Output: f2 +PREHOOK: query: -- udf-classloader-udf1.jar contains f1 which relies on udf-classloader-util.jar, +-- similiary udf-classloader-udf2.jar contains f2 which also relies on udf-classloader-util.jar. +SELECT f1(*), f2(*) FROM SRC limit 1 +PREHOOK: type: QUERY +PREHOOK: Input: default@src +#### A masked pattern was here #### +POSTHOOK: query: -- udf-classloader-udf1.jar contains f1 which relies on udf-classloader-util.jar, +-- similiary udf-classloader-udf2.jar contains f2 which also relies on udf-classloader-util.jar. +SELECT f1(*), f2(*) FROM SRC limit 1 +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +#### A masked pattern was here #### +UDF1 UDF2 +PREHOOK: query: SELECT f1(*) FROM SRC limit 1 +PREHOOK: type: QUERY +PREHOOK: Input: default@src +#### A masked pattern was here #### +POSTHOOK: query: SELECT f1(*) FROM SRC limit 1 +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +#### A masked pattern was here #### +UDF1 +PREHOOK: query: SELECT f2(*) FROM SRC limit 1 +PREHOOK: type: QUERY +PREHOOK: Input: default@src +#### A masked pattern was here #### +POSTHOOK: query: SELECT f2(*) FROM SRC limit 1 +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +#### A masked pattern was here #### +UDF2