protected FunctionMethod addAggregatePushDownFunction( String qualifier, String name, String returnType, String... paramTypes) { FunctionMethod method = addPushDownFunction(qualifier, name, returnType, paramTypes); AggregateAttributes attr = new AggregateAttributes(); attr.setAnalytic(true); method.setAggregateAttributes(attr); return method; }
/** * Adds a pushdown function. * * @param qualifier will be pre-pended to the name * @param name * @param returnType see {@link RUNTIME_NAMES} for type names * @param paramTypes see {@link RUNTIME_NAMES} for type names * @return the FunctionMethod created. */ protected FunctionMethod addPushDownFunction( String qualifier, String name, String returnType, String... paramTypes) { FunctionMethod method = FunctionMethod.createFunctionMethod( qualifier + '.' + name, name, qualifier, returnType, paramTypes); method.setNameInSource(name); pushdownFunctionMethods.add(method); return method; }
@Test public void testMixedCaseTypes() throws Exception { String ddl = "CREATE FUNCTION SourceFunc(flag Boolean) RETURNS varchaR options (UUID 'z')"; Schema s = helpParse(ddl, "model").getSchema(); FunctionMethod fm = s.getFunction("z"); assertEquals("boolean", fm.getInputParameters().get(0).getType()); }
@Test(expected = MetadataException.class) public void testInvalidProcedureBody() throws Exception { String ddl = "CREATE FOREIGN PROCEDURE SourceFunc(flag boolean) RETURNS varchar AS SELECT 'a';"; Schema s = helpParse(ddl, "model").getSchema(); FunctionMethod fm = s.getFunction("z"); assertTrue(fm.getInputParameters().get(0).isVarArg()); }
@Test public void testVarArgs() throws Exception { String ddl = "CREATE FUNCTION SourceFunc(flag boolean) RETURNS varchar options (varargs 'true', UUID 'z')"; Schema s = helpParse(ddl, "model").getSchema(); FunctionMethod fm = s.getFunction("z"); assertTrue(fm.getInputParameters().get(0).isVarArg()); }
@Test public void testPushdownFunctionNoArgs() throws Exception { String ddl = "CREATE FOREIGN FUNCTION SourceFunc() RETURNS integer OPTIONS (UUID 'hello world')"; Schema s = helpParse(ddl, "model").getSchema(); FunctionMethod fm = s.getFunction("hello world"); assertNotNull(fm); assertEquals("integer", fm.getOutputParameter().getType()); assertEquals(FunctionMethod.PushDown.MUST_PUSHDOWN, fm.getPushdown()); }
public Object newInstance() { try { return invocationMethod.getDeclaringClass().newInstance(); } catch (InstantiationException e) { throw new TeiidRuntimeException( QueryPlugin.Event.TEIID30602, QueryPlugin.Util.gs( QueryPlugin.Event.TEIID30602, method.getName(), method.getInvocationClass())); } catch (IllegalAccessException e) { throw new TeiidRuntimeException( QueryPlugin.Event.TEIID30602, QueryPlugin.Util.gs( QueryPlugin.Event.TEIID30602, method.getName(), method.getInvocationClass())); } }
public ConnectorManager( String translatorName, String connectionName, ExecutionFactory<Object, Object> ef) { this.translatorName = translatorName; this.connectionName = connectionName; if (this.connectionName != null) { if (!this.connectionName.startsWith(JAVA_CONTEXT)) { jndiName = JAVA_CONTEXT + this.connectionName; } else { jndiName = this.connectionName; } } else { jndiName = null; } this.executionFactory = ef; this.id = Arrays.asList(translatorName, connectionName); if (ef != null) { ClassLoader originalCL = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(ef.getClass().getClassLoader()); functions = ef.getPushDownFunctions(); } finally { Thread.currentThread().setContextClassLoader(originalCL); } if (functions != null) { // set the specific name to match against imported versions of // the same function for (FunctionMethod functionMethod : functions) { functionMethod.setProperty(FunctionMethod.SYSTEM_NAME, functionMethod.getName()); } ValidatorReport report = new ValidatorReport("Function Validation"); // $NON-NLS-1$ FunctionMetadataValidator.validateFunctionMethods(functions, report); if (report.hasItems()) { throw new TeiidRuntimeException(report.getFailureMessage()); } } } }
private void visit(FunctionMethod function) { if (this.filter != null && !filter.matcher(function.getName()).matches()) { return; } append(CREATE).append(SPACE); if (function.getPushdown().equals(FunctionMethod.PushDown.MUST_PUSHDOWN)) { append(FOREIGN); } else { append(VIRTUAL); } append(SPACE) .append(FUNCTION) .append(SPACE) .append(SQLStringVisitor.escapeSinglePart(function.getName())); append(LPAREN); boolean first = true; for (FunctionParameter fp : function.getInputParameters()) { if (first) { first = false; } else { append(COMMA).append(SPACE); } visit(fp); } append(RPAREN); append(SPACE).append(RETURNS); appendOptions(function.getOutputParameter()); append(SPACE); append(function.getOutputParameter().getType()); // options String options = buildFunctionOptions(function); if (!options.isEmpty()) { append(NEWLINE).append(OPTIONS).append(SPACE).append(LPAREN).append(options).append(RPAREN); } /*if (function.getDefinition() != null) { append(NEWLINE).append(SQLConstants.Reserved.AS).append(NEWLINE); append(function.getDefinition()); }*/ append(SQLConstants.Tokens.SEMICOLON); }
private String buildFunctionOptions(FunctionMethod function) { StringBuilder options = new StringBuilder(); addCommonOptions(options, function); if (function.getCategory() != null) { addOption(options, CATEGORY, function.getCategory()); } if (!function.getDeterminism().equals(Determinism.DETERMINISTIC)) { addOption(options, DETERMINISM, function.getDeterminism().name()); } if (function.getInvocationClass() != null) { addOption(options, JAVA_CLASS, function.getInvocationClass()); } if (function.getInvocationMethod() != null) { addOption(options, JAVA_METHOD, function.getInvocationMethod()); } if (!function.getProperties().isEmpty()) { for (String key : function.getProperties().keySet()) { addOption(options, key, function.getProperty(key, false)); } } return options.toString(); }
/** * Invoke the function described in the function descriptor, using the values provided. Return the * result of the function. * * @param values Values that should match 1-to-1 with the types described in the function * descriptor * @param context * @param functionTarget TODO * @param fd Function descriptor describing the name and types of the arguments * @return Result of invoking the function */ public Object invokeFunction(Object[] values, CommandContext context, Object functionTarget) throws FunctionExecutionException, BlockedException { if (!isNullDependent()) { for (int i = requiresContext ? 1 : 0; i < values.length; i++) { if (values[i] == null) { return null; } } } // If descriptor is missing invokable method, find this VM's descriptor // give name and types from fd if (invocationMethod == null) { throw new FunctionExecutionException( QueryPlugin.Event.TEIID30382, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30382, getFullName())); } // Invoke the method and return the result try { if (hasWrappedArgs) { for (int i = 0; i < values.length; i++) { Object val = values[i]; if (val != null && types[i] == DataTypeManager.DefaultDataClasses.VARBINARY) { values[i] = ((BinaryType) val).getBytesDirect(); } } } if (method.isVarArgs()) { if (calledWithVarArgArrayParam) { ArrayImpl av = (ArrayImpl) values[values.length - 1]; if (av != null) { Object[] vals = av.getValues(); values[values.length - 1] = vals; if (hasWrappedArgs && types[types.length - 1] == DataTypeManager.DefaultDataClasses.VARBINARY) { vals = Arrays.copyOf(vals, vals.length); for (int i = 0; i < vals.length; i++) { if (vals[i] != null) { vals[i] = ((BinaryType) vals[i]).getBytesDirect(); } } values[values.length - 1] = vals; } Class<?> arrayType = invocationMethod.getParameterTypes()[types.length - 1]; if (arrayType.getComponentType() != Object.class && vals.getClass() != arrayType) { Object varArgs = Array.newInstance(arrayType.getComponentType(), vals.length); for (int i = 0; i < vals.length; i++) { Array.set(varArgs, i, vals[i]); } values[values.length - 1] = varArgs; } } } else { int i = invocationMethod.getParameterTypes().length; Object[] newValues = Arrays.copyOf(values, i); Object varArgs = null; if (invocationMethod.getParameterTypes()[i - 1].getComponentType() != Object.class) { int varArgCount = values.length - i + 1; varArgs = Array.newInstance( invocationMethod.getParameterTypes()[i - 1].getComponentType(), varArgCount); for (int j = 0; j < varArgCount; j++) { Array.set(varArgs, j, values[i - 1 + j]); } } else { varArgs = Arrays.copyOfRange(values, i - 1, values.length); } newValues[i - 1] = varArgs; values = newValues; } } Object result = invocationMethod.invoke(functionTarget, values); if (context != null && getDeterministic().ordinal() <= Determinism.USER_DETERMINISTIC.ordinal()) { context.setDeterminismLevel(getDeterministic()); } return importValue(result, getReturnType()); } catch (ArithmeticException e) { throw new FunctionExecutionException( QueryPlugin.Event.TEIID30384, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30384, getFullName())); } catch (InvocationTargetException e) { if (e.getTargetException() instanceof BlockedException) { throw (BlockedException) e.getTargetException(); } throw new FunctionExecutionException( QueryPlugin.Event.TEIID30384, e.getTargetException(), QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30384, getFullName())); } catch (IllegalAccessException e) { throw new FunctionExecutionException( QueryPlugin.Event.TEIID30385, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30385, method.toString())); } catch (TransformationException e) { throw new FunctionExecutionException(e); } }
@Test public void testUDAggregate() throws Exception { String ddl = "CREATE VIRTUAL FUNCTION SourceFunc(flag boolean, msg varchar) RETURNS varchar " + "OPTIONS(CATEGORY 'misc', AGGREGATE 'true', \"allows-distinct\" 'true', UUID 'y')"; Schema s = helpParse(ddl, "model").getSchema(); FunctionMethod fm = s.getFunction("y"); assertNotNull(fm); assertEquals("string", fm.getOutputParameter().getType()); 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("msg", fm.getInputParameters().get(1).getName()); assertEquals("string", fm.getInputParameters().get(1).getType()); assertFalse(fm.getInputParameters().get(1).isVarArg()); assertNotNull(fm.getAggregateAttributes()); assertTrue(fm.getAggregateAttributes().allowsDistinct()); assertEquals(FunctionMethod.Determinism.DETERMINISTIC, fm.getDeterminism()); assertEquals("misc", fm.getCategory()); assertFalse(fm.isNullOnNull()); }
@Test public void testUDF() throws Exception { String ddl = "CREATE VIRTUAL FUNCTION SourceFunc(flag boolean, msg varchar) RETURNS varchar " + "OPTIONS(CATEGORY 'misc', DETERMINISM 'DETERMINISTIC', " + "\"NULL-ON-NULL\" 'true', JAVA_CLASS 'foo', JAVA_METHOD 'bar', RANDOM 'any', UUID 'x')"; Schema s = helpParse(ddl, "model").getSchema(); FunctionMethod fm = s.getFunction("x"); assertNotNull(fm); assertEquals("string", fm.getOutputParameter().getType()); 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("msg", fm.getInputParameters().get(1).getName()); assertEquals("string", fm.getInputParameters().get(1).getType()); assertFalse(fm.getInputParameters().get(1).isVarArg()); assertEquals(FunctionMethod.Determinism.DETERMINISTIC, fm.getDeterminism()); assertEquals("misc", fm.getCategory()); assertEquals(true, fm.isNullOnNull()); assertEquals("foo", fm.getInvocationClass()); assertEquals("bar", fm.getInvocationMethod()); assertEquals("any", fm.getProperties().get("RANDOM")); }
@Override public void execute( VDBMetaData vdb, MetadataStore store, ValidatorReport report, MetadataValidator metadataValidator) { for (Schema schema : store.getSchemaList()) { if (vdb.getImportedModels().contains(schema.getName())) { continue; } ModelMetaData model = vdb.getModel(schema.getName()); for (Table t : schema.getTables().values()) { if (t.isPhysical() && !model.isSource()) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31075, t.getFullName(), model.getName())); } } Set<String> names = new HashSet<String>(); for (Procedure p : schema.getProcedures().values()) { boolean hasReturn = false; names.clear(); for (int i = 0; i < p.getParameters().size(); i++) { ProcedureParameter param = p.getParameters().get(i); if (param.isVarArg() && param != p.getParameters().get(p.getParameters().size() - 1)) { // check that the rest of the parameters are optional // this accommodates variadic multi-source procedures // effective this and the resolving logic ensure that you can used named parameters // for everything, // or call the vararg procedure as normal if (isTeiidOrGreater(Version.TEIID_8_10)) { for (int j = i + 1; j < p.getParameters().size(); j++) { ProcedureParameter param1 = p.getParameters().get(j); if ((param1.getType() == Type.In || param1.getType() == Type.InOut) && (param1.isVarArg() || (param1.getNullType() != NullType.Nullable && param1.getDefaultValue() == null))) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31112, p.getFullName())); } } } else { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31112, p.getFullName())); } } if (param.getType() == ProcedureParameter.Type.ReturnValue) { if (hasReturn) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31107, p.getFullName())); } hasReturn = true; } else if (p.isFunction() && param.getType() != ProcedureParameter.Type.In && teiidVersion.isGreaterThanOrEqualTo(Version.TEIID_8_11)) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31165, p.getFullName(), param.getFullName())); } if (!names.add(param.getName())) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31106, p.getFullName(), param.getFullName())); } } if (!p.isVirtual() && !model.isSource()) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31077, p.getFullName(), model.getName())); } if (p.isFunction() && teiidVersion.isGreaterThanOrEqualTo(Version.TEIID_8_11)) { if (!hasReturn) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31166, p.getFullName())); } if (p.isVirtual() && p.getQueryPlan() == null) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31167, p.getFullName())); } } } for (FunctionMethod func : schema.getFunctions().values()) { for (FunctionParameter param : func.getInputParameters()) { if (param.isVarArg() && param != func.getInputParameters().get(func.getInputParameterCount() - 1)) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31112, func.getFullName())); } } if (func.getPushdown().equals(FunctionMethod.PushDown.MUST_PUSHDOWN) && !model.isSource()) { metadataValidator.log( report, model, Messages.gs(Messages.TEIID.TEIID31078, func.getFullName(), model.getName())); } } } }