Skip to content

Commit

Permalink
TEIID-4932 adding a UDF metadata factory
Browse files Browse the repository at this point in the history
  • Loading branch information
shawkins committed Oct 1, 2018
1 parent 968ac05 commit 1cdbc14
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 11 deletions.
10 changes: 10 additions & 0 deletions api/src/main/java/org/teiid/metadata/MetadataFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ public class MetadataFactory extends NamespaceContainer {
private Map<String, Grant> grants;

private String nameFormat;

private ClassLoader vdbClassLoader;

public MetadataFactory() {

Expand Down Expand Up @@ -943,4 +945,12 @@ public void setImportPushdownFunctions(boolean importPushdownFunctions) {
this.importPushdownFunctions = importPushdownFunctions;
}

public void setVDBClassLoader(ClassLoader classLoader) {
this.vdbClassLoader = classLoader;
}

public ClassLoader getVDBClassLoader() {
return vdbClassLoader;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags and
* the COPYRIGHT.txt file distributed with this work.
*
* Licensed 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.teiid.query.metadata;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import org.teiid.CommandContext;
import org.teiid.UserDefinedAggregate;
import org.teiid.metadata.MetadataFactory;
import org.teiid.metadata.MetadataRepository;
import org.teiid.query.function.TeiidFunction;
import org.teiid.translator.ExecutionFactory;
import org.teiid.translator.TranslatorException;

/**
* Simple metadata loader for functions
*
* TODO: make the {@link TeiidFunction} annotation public
*/
public class UDFMetadataRepository extends MetadataRepository {

@Override
public void loadMetadata(MetadataFactory factory,
ExecutionFactory executionFactory, Object connectionFactory,
String text) throws TranslatorException {
String className = factory.getModelProperties().getProperty("importer.schemaName"); //$NON-NLS-1$
String methodNames = factory.getModelProperties().getProperty("importer.methodNames"); //$NON-NLS-1$
ClassLoader classLoader = factory.getVDBClassLoader();
Set<String> allowed = null;
if (methodNames != null) {
allowed = new HashSet<>(Arrays.asList(methodNames.split(","))); //$NON-NLS-1$
}
try {
Class<?> clazz = classLoader.loadClass(className);

if (UserDefinedAggregate.class.isAssignableFrom(clazz)) {
factory.addFunction(clazz.getSimpleName(), clazz.getMethod("getResult", new Class<?>[] {CommandContext.class}));
} else {
Method[] methods = clazz.getMethods();
for (Method m : methods) {
if (!Modifier.isStatic(m.getModifiers())) {
continue;
}
if (m.getReturnType() == Void.TYPE) {
continue;
}
if (allowed != null && !allowed.contains(m.getName())) {
continue;
}
factory.addFunction(m.getName(), m);
}
}
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
throw new TranslatorException(e);
}
}

}
22 changes: 11 additions & 11 deletions engine/src/test/java/org/teiid/query/parser/TestDDLParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ public void testOptionalFK() throws Exception {

assertFalse(report.hasItems());

assertEquals(fk.getPrimaryKey().getColumns(), tableMap.get("G1").getColumns());
assertEquals(fk.getReferenceKey().getColumns(), tableMap.get("G1").getColumns());
}

@Test
Expand Down Expand Up @@ -431,7 +431,7 @@ public void testFKAccrossSchemas() throws Exception {
assertEquals(fk.getColumns(), table.getColumns());
assertEquals("G1", fk.getReferenceTableName());

assertEquals(fk.getPrimaryKey().getColumns(), s.getSchema("model").getTable("G1").getColumns());
assertEquals(fk.getReferenceKey().getColumns(), s.getSchema("model").getTable("G1").getColumns());
}

@Test(expected=MetadataException.class)
Expand Down Expand Up @@ -536,7 +536,7 @@ public void testPushdownFunctionNoArgs() throws Exception {

FunctionMethod fm = s.getFunction("hello world");
assertNotNull(fm);
assertEquals("integer", fm.getOutputParameter().getType());
assertEquals("integer", fm.getOutputParameter().getRuntimeType());
assertEquals(FunctionMethod.PushDown.MUST_PUSHDOWN, fm.getPushdown());
}

Expand Down Expand Up @@ -574,13 +574,13 @@ public void testUDF() throws Exception {

FunctionMethod fm = s.getFunction("x");
assertNotNull(fm);
assertEquals("string", fm.getOutputParameter().getType());
assertEquals("string", fm.getOutputParameter().getRuntimeType());
assertEquals(FunctionMethod.PushDown.CAN_PUSHDOWN, fm.getPushdown());
assertEquals(2, fm.getInputParameterCount());
assertEquals("flag", fm.getInputParameters().get(0).getName());
assertEquals("boolean", fm.getInputParameters().get(0).getType());
assertEquals("boolean", fm.getInputParameters().get(0).getRuntimeType());
assertEquals("msg", fm.getInputParameters().get(1).getName());
assertEquals("string", fm.getInputParameters().get(1).getType());
assertEquals("string", fm.getInputParameters().get(1).getRuntimeType());
assertFalse( fm.getInputParameters().get(1).isVarArg());

assertEquals(FunctionMethod.Determinism.DETERMINISTIC, fm.getDeterminism());
Expand All @@ -600,13 +600,13 @@ public void testUDAggregate() throws Exception {

FunctionMethod fm = s.getFunction("y");
assertNotNull(fm);
assertEquals("string", fm.getOutputParameter().getType());
assertEquals("string", fm.getOutputParameter().getRuntimeType());
assertEquals(FunctionMethod.PushDown.CAN_PUSHDOWN, fm.getPushdown());
assertEquals(2, fm.getInputParameterCount());
assertEquals("flag", fm.getInputParameters().get(0).getName());
assertEquals("boolean", fm.getInputParameters().get(0).getType());
assertEquals("boolean", fm.getInputParameters().get(0).getRuntimeType());
assertEquals("msg", fm.getInputParameters().get(1).getName());
assertEquals("string", fm.getInputParameters().get(1).getType());
assertEquals("string", fm.getInputParameters().get(1).getRuntimeType());
assertFalse( fm.getInputParameters().get(1).isVarArg());
assertNotNull(fm.getAggregateAttributes());
assertTrue(fm.getAggregateAttributes().allowsDistinct());
Expand All @@ -631,7 +631,7 @@ public void testVarArgs() throws Exception {
Schema s = helpParse(ddl, "model").getSchema();

FunctionMethod fm = s.getFunction("z");
assertEquals("boolean", fm.getInputParameters().get(0).getType());
assertEquals("boolean", fm.getInputParameters().get(0).getRuntimeType());
}

@Test(expected=MetadataException.class) public void testInvalidFunctionBody() throws Exception {
Expand Down Expand Up @@ -1584,7 +1584,7 @@ public void testFunction() throws Exception {
}
}
assertNotNull(method);
assertEquals("boolean", method.getInputParameters().get(0).getType());
assertEquals("boolean", method.getInputParameters().get(0).getRuntimeType());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ public AbstractVDBDeployer() {
repositories.put("ddl", new DDLMetadataRepository()); //$NON-NLS-1$
repositories.put("native", new NativeMetadataRepository()); //$NON-NLS-1$
repositories.put("ddl-file", new DDLFileMetadataRepository()); //$NON-NLS-1$
repositories.put("udf", new UDFMetadataRepository()); //$NON-NLS-1$
}

public void addMetadataRepository(String name, MetadataRepository<?, ?> metadataRepository) {
Expand Down Expand Up @@ -292,11 +293,13 @@ public void importSchema(String schemaName, String serverType,
if (!excludeTables.isEmpty()) {
modelProperties.put("importer.excludeTables", StringUtil.join(excludeTables, ",")); //$NON-NLS-1$
}
modelProperties.put("importer.schemaName", foreignSchemaName); //$NON-NLS-1$
MetadataFactory factory = DatabaseStore.createMF(this, getSchema(schemaName), true, modelProperties);
factory.setParser(new QueryParser());
if (vdbResources != null) {
factory.setVdbResources(vdbResources.getEntriesPlusVisibilities());
}
factory.setVDBClassLoader(vdb.getAttachment(ClassLoader.class));
MetadataRepository baseRepo = model.getAttachment(MetadataRepository.class);

MetadataRepository metadataRepository;
Expand Down Expand Up @@ -373,6 +376,7 @@ protected MetadataFactory createMetadataFactory(VDBMetaData vdb, MetadataStore s
factory.getSchema().setPhysical(model.isSource());
factory.setParser(new QueryParser()); //for thread safety each factory gets it's own instance.
factory.setVdbResources(vdbResources);
factory.setVDBClassLoader(vdb.getAttachment(ClassLoader.class));
return factory;
}

Expand Down
9 changes: 9 additions & 0 deletions runtime/src/test/java/org/teiid/runtime/Funcs.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.teiid.runtime;

public class Funcs {

public static boolean something(long val) {
return val > System.currentTimeMillis();
}

}
16 changes: 16 additions & 0 deletions runtime/src/test/java/org/teiid/runtime/TestEmbeddedServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -2568,5 +2568,21 @@ public void loadMetadata(MetadataFactory factory,
org.teiid.logging.LogManager.setLogListener(old);
}
}

@Test public void testImportFunctions() throws Exception {
es.start(new EmbeddedConfiguration());

String ddl = "CREATE DATABASE test VERSION '1';"
+ "USE DATABASE test VERSION '1';"
+ "CREATE VIRTUAL SCHEMA test2;"
+ "IMPORT FOREIGN SCHEMA \"org.teiid.runtime.Funcs\" FROM REPOSITORY UDF INTO test2;"
+ "IMPORT FOREIGN SCHEMA \"java.lang.System\" FROM REPOSITORY UDF INTO test2;";

es.deployVDB(new ByteArrayInputStream(ddl.getBytes("UTF-8")), true);
ResultSet rs = es.getDriver().connect("jdbc:teiid:test", null).createStatement().executeQuery("select something(1), nanoTime()");
rs.next();
assertTrue(rs.getObject(1) instanceof Boolean);
assertTrue(rs.getObject(2) instanceof Long);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ <H2><A NAME="Highlights"></A>Highlights</H2>
<li><a href="https://issues.jboss.org/browse/TEIID-5461">TEIID-5461</a> Added parsing and pushdown support for the window frame clause.</li>
<li><a href="https://issues.jboss.org/browse/TEIID-5316">TEIID-5316</a> Engine processing of window functions using the frame clause.</li>
<li><a href="https://issues.jboss.org/browse/TEIID-3931">TEIID-3931</a> Added support for exposing geometry values as OData geometry types.</li>
<li><a href="https://issues.jboss.org/browse/TEIID-4932">TEIID-4932</a> Added a UDF metadata repository for loading UDFs from a class.</li>
</ul>

<h2><a name="Compatibility">Compatibility Issues</a></h2>
Expand Down

0 comments on commit 1cdbc14

Please sign in to comment.