Skip to content

Commit

Permalink
TEIID-5977 adding logic to associate a virtual function with a physic…
Browse files Browse the repository at this point in the history
…al (teiid#1316)
  • Loading branch information
shawkins authored Jul 28, 2020
1 parent 9687fe5 commit 7c1fc08
Show file tree
Hide file tree
Showing 19 changed files with 442 additions and 40 deletions.
1 change: 1 addition & 0 deletions api/src/main/java/org/teiid/metadata/FunctionMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
public class FunctionMethod extends AbstractMetadataRecord {

public static final String SYSTEM_NAME = AbstractMetadataRecord.RELATIONAL_PREFIX + "system-name"; //$NON-NLS-1$
public static final String VIRTUAL_FUNCTION = AbstractMetadataRecord.RELATIONAL_PREFIX + "virtual-function"; //$NON-NLS-1$

private static final long serialVersionUID = -8039086494296455152L;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,18 @@

package org.teiid.dqp.internal.datamgr;

import java.util.*;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.RandomAccess;

import org.teiid.api.exception.query.FunctionExecutionException;
import org.teiid.api.exception.query.QueryMetadataException;
Expand All @@ -31,17 +42,49 @@
import org.teiid.core.TeiidRuntimeException;
import org.teiid.core.types.ArrayImpl;
import org.teiid.core.types.DataTypeManager;
import org.teiid.language.*;
import org.teiid.language.AggregateFunction;
import org.teiid.language.AndOr;
import org.teiid.language.Argument;
import org.teiid.language.Argument.Direction;
import org.teiid.language.BatchedUpdates;
import org.teiid.language.BulkCommand;
import org.teiid.language.Call;
import org.teiid.language.ColumnReference;
import org.teiid.language.Comparison;
import org.teiid.language.Comparison.Operator;
import org.teiid.language.Condition;
import org.teiid.language.DerivedColumn;
import org.teiid.language.DerivedTable;
import org.teiid.language.Exists;
import org.teiid.language.ExpressionValueSource;
import org.teiid.language.In;
import org.teiid.language.InsertValueSource;
import org.teiid.language.IsDistinct;
import org.teiid.language.IsNull;
import org.teiid.language.Join;
import org.teiid.language.Like;
import org.teiid.language.Literal;
import org.teiid.language.NamedProcedureCall;
import org.teiid.language.NamedTable;
import org.teiid.language.Not;
import org.teiid.language.Parameter;
import org.teiid.language.QueryExpression;
import org.teiid.language.SearchedCase;
import org.teiid.language.SearchedWhenClause;
import org.teiid.language.Select;
import org.teiid.language.SortSpecification;
import org.teiid.language.SortSpecification.NullOrdering;
import org.teiid.language.SortSpecification.Ordering;
import org.teiid.language.SubqueryComparison;
import org.teiid.language.SubqueryComparison.Quantifier;
import org.teiid.language.SubqueryIn;
import org.teiid.language.TableReference;
import org.teiid.language.WindowSpecification;
import org.teiid.language.With;
import org.teiid.language.WithItem;
import org.teiid.metadata.BaseColumn;
import org.teiid.metadata.Column;
import org.teiid.metadata.FunctionMethod;
import org.teiid.metadata.Procedure;
import org.teiid.metadata.ProcedureParameter;
import org.teiid.metadata.Table;
Expand All @@ -51,16 +94,40 @@
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.metadata.TempMetadataID;
import org.teiid.query.optimizer.relational.rules.RulePlaceAccess;
import org.teiid.query.sql.lang.*;
import org.teiid.query.sql.lang.BatchedUpdateCommand;
import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.lang.CompareCriteria;
import org.teiid.query.sql.lang.CompoundCriteria;
import org.teiid.query.sql.lang.Criteria;
import org.teiid.query.sql.lang.Delete;
import org.teiid.query.sql.lang.DependentSetCriteria;
import org.teiid.query.sql.lang.ExistsCriteria;
import org.teiid.query.sql.lang.FromClause;
import org.teiid.query.sql.lang.GroupBy;
import org.teiid.query.sql.lang.Insert;
import org.teiid.query.sql.lang.IsDistinctCriteria;
import org.teiid.query.sql.lang.IsNullCriteria;
import org.teiid.query.sql.lang.JoinPredicate;
import org.teiid.query.sql.lang.JoinType;
import org.teiid.query.sql.lang.Limit;
import org.teiid.query.sql.lang.MatchCriteria;
import org.teiid.query.sql.lang.NotCriteria;
import org.teiid.query.sql.lang.OrderBy;
import org.teiid.query.sql.lang.OrderByItem;
import org.teiid.query.sql.lang.Query;
import org.teiid.query.sql.lang.QueryCommand;
import org.teiid.query.sql.lang.SPParameter;
import org.teiid.query.sql.lang.SetClause;
import org.teiid.query.sql.lang.SetClauseList;
import org.teiid.query.sql.lang.SetCriteria;
import org.teiid.query.sql.lang.SetQuery;
import org.teiid.query.sql.lang.StoredProcedure;
import org.teiid.query.sql.lang.SubqueryCompareCriteria;
import org.teiid.query.sql.lang.SubqueryFromClause;
import org.teiid.query.sql.lang.SubquerySetCriteria;
import org.teiid.query.sql.lang.UnaryFromClause;
import org.teiid.query.sql.lang.Update;
import org.teiid.query.sql.lang.WithQueryCommand;
import org.teiid.query.sql.symbol.AggregateSymbol;
import org.teiid.query.sql.symbol.AggregateSymbol.Type;
import org.teiid.query.sql.symbol.AliasSymbol;
Expand Down Expand Up @@ -814,9 +881,12 @@ org.teiid.language.Expression translate(Function function) {
params.add(translate(args[i]));
}
String name = function.getName();
if (function.getFunctionDescriptor() != null) {
name = function.getFunctionDescriptor().getName();
if (!supportsConcat2 && function.getFunctionDescriptor().getMethod().getParent() == null && name.equalsIgnoreCase(SourceSystemFunctions.CONCAT2)) {
FunctionMethod method = null;
FunctionDescriptor functionDescriptor = function.getFunctionDescriptor();
if (functionDescriptor != null) {
method = functionDescriptor.getMethod();
name = functionDescriptor.getName();
if (!supportsConcat2 && method.getParent() == null && name.equalsIgnoreCase(SourceSystemFunctions.CONCAT2)) {
Expression[] newArgs = new Expression[args.length];

boolean useCase = true;
Expand Down Expand Up @@ -853,7 +923,7 @@ org.teiid.language.Expression translate(Function function) {
caseExpr.setType(DataTypeManager.DefaultDataClasses.STRING);
return translate(caseExpr);
}
if (function.getFunctionDescriptor().getMethod().getParent() == null && name.equalsIgnoreCase(SourceSystemFunctions.TIMESTAMPADD)
if (method.getParent() == null && name.equalsIgnoreCase(SourceSystemFunctions.TIMESTAMPADD)
&& function.getArg(1).getType() == DataTypeManager.DefaultDataClasses.LONG) {
//TEIID-5406 only allow integer literal pushdown for backwards compatibility
if (params.get(1) instanceof Literal) {
Expand All @@ -869,11 +939,17 @@ org.teiid.language.Expression translate(Function function) {
Arrays.asList(params.get(1), new Literal(DataTypeManager.DefaultDataTypes.INTEGER, DataTypeManager.DefaultDataClasses.STRING)), DataTypeManager.DefaultDataClasses.INTEGER));
}
}

if (function.getPushdownFunction() != null) {
method = function.getPushdownFunction();
name = method.getName();
}

//check for translator pushdown functions, and use the name in source if possible
if (function.getFunctionDescriptor().getMethod().getNameInSource() != null &&
(CoreConstants.SYSTEM_MODEL.equals(function.getFunctionDescriptor().getSchema())
|| (function.getFunctionDescriptor().getMethod().getParent() != null && function.getFunctionDescriptor().getMethod().getParent().isPhysical()))) {
name = function.getFunctionDescriptor().getMethod().getNameInSource();
if (method.getNameInSource() != null &&
(CoreConstants.SYSTEM_MODEL.equals(functionDescriptor.getSchema())
|| (method.getParent() != null && method.getParent().isPhysical()))) {
name = method.getNameInSource();
}
} else {
name = Symbol.getShortName(name);
Expand All @@ -882,9 +958,7 @@ org.teiid.language.Expression translate(Function function) {
//if there is any ambiguity in the function name it will be up to the translator logic to check the
//metadata
org.teiid.language.Function result = new org.teiid.language.Function(name, params, function.getType());
if (function.getFunctionDescriptor() != null) {
result.setMetadataObject(function.getFunctionDescriptor().getMethod());
}
result.setMetadataObject(method);
return result;
}

Expand Down
3 changes: 2 additions & 1 deletion engine/src/main/java/org/teiid/query/QueryPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,7 @@ public static enum Event implements BundleUtil.Event{
TEIID31301,
TEIID31302,
TEIID31303,
TEIID31304
TEIID31304,
TEIID31305
}
}
57 changes: 53 additions & 4 deletions engine/src/main/java/org/teiid/query/eval/Evaluator.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,18 @@
import org.teiid.core.ComponentNotFoundException;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.types.*;
import org.teiid.core.types.ArrayImpl;
import org.teiid.core.types.BaseClobType;
import org.teiid.core.types.BaseLob;
import org.teiid.core.types.BinaryType;
import org.teiid.core.types.BlobType;
import org.teiid.core.types.InputStreamFactory;
import org.teiid.core.types.JsonType;
import org.teiid.core.types.SQLXMLImpl;
import org.teiid.core.types.Sequencable;
import org.teiid.core.types.Streamable;
import org.teiid.core.types.TransformationException;
import org.teiid.core.types.XMLType;
import org.teiid.core.types.XMLType.Type;
import org.teiid.core.types.basic.StringToSQLXMLTransform;
import org.teiid.core.util.EquivalenceUtil;
Expand All @@ -61,10 +72,48 @@
import org.teiid.query.metadata.TempMetadataID;
import org.teiid.query.processor.ProcessorDataManager;
import org.teiid.query.sql.LanguageObject;
import org.teiid.query.sql.lang.*;
import org.teiid.query.sql.lang.AbstractSetCriteria;
import org.teiid.query.sql.lang.CollectionValueIterator;
import org.teiid.query.sql.lang.CompareCriteria;
import org.teiid.query.sql.lang.CompoundCriteria;
import org.teiid.query.sql.lang.Criteria;
import org.teiid.query.sql.lang.DependentSetCriteria;
import org.teiid.query.sql.lang.ExistsCriteria;
import org.teiid.query.sql.lang.ExpressionCriteria;
import org.teiid.query.sql.lang.IsDistinctCriteria;
import org.teiid.query.sql.lang.IsNullCriteria;
import org.teiid.query.sql.lang.MatchCriteria;
import org.teiid.query.sql.lang.NotCriteria;
import org.teiid.query.sql.lang.SetCriteria;
import org.teiid.query.sql.lang.SubqueryCompareCriteria;
import org.teiid.query.sql.lang.SubqueryContainer;
import org.teiid.query.sql.lang.SubquerySetCriteria;
import org.teiid.query.sql.proc.ExceptionExpression;
import org.teiid.query.sql.symbol.*;
import org.teiid.query.sql.symbol.Array;
import org.teiid.query.sql.symbol.CaseExpression;
import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.sql.symbol.DerivedColumn;
import org.teiid.query.sql.symbol.DerivedExpression;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Expression;
import org.teiid.query.sql.symbol.ExpressionSymbol;
import org.teiid.query.sql.symbol.Function;
import org.teiid.query.sql.symbol.GroupSymbol;
import org.teiid.query.sql.symbol.JSONObject;
import org.teiid.query.sql.symbol.QueryString;
import org.teiid.query.sql.symbol.Reference;
import org.teiid.query.sql.symbol.ScalarSubquery;
import org.teiid.query.sql.symbol.SearchedCaseExpression;
import org.teiid.query.sql.symbol.TextLine;
import org.teiid.query.sql.symbol.XMLCast;
import org.teiid.query.sql.symbol.XMLElement;
import org.teiid.query.sql.symbol.XMLExists;
import org.teiid.query.sql.symbol.XMLForest;
import org.teiid.query.sql.symbol.XMLNamespaces;
import org.teiid.query.sql.symbol.XMLNamespaces.NamespaceItem;
import org.teiid.query.sql.symbol.XMLParse;
import org.teiid.query.sql.symbol.XMLQuery;
import org.teiid.query.sql.symbol.XMLSerialize;
import org.teiid.query.sql.util.ValueIterator;
import org.teiid.query.sql.util.ValueIteratorSource;
import org.teiid.query.sql.util.VariableContext;
Expand Down Expand Up @@ -1308,7 +1357,7 @@ private Object evaluate(Function function, List<?> tuple)
}

// Execute function
return fd.invokeFunction(values, context, null);
return fd.invokeFunction(values, context, null, function.isCalledWithVarArgArrayParam());
}

protected Object evaluatePushdown(Function function, List<?> tuple,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ public class FunctionDescriptor implements Serializable, Cloneable {
private FunctionMethod method;
private String schema; //TODO: remove me - we need to create a proper schema for udf and system functions
private boolean hasWrappedArgs;
private boolean calledWithVarArgArrayParam; //TODO: could store this on the function and pass to invoke

// This is transient as it would be useless to invoke this method in
// a different VM. This function descriptor can be used to look up
Expand Down Expand Up @@ -205,6 +204,10 @@ void setReturnType(Class<?> returnType) {
* @return Result of invoking the function
*/
public Object invokeFunction(Object[] values, CommandContext context, Object functionTarget) throws FunctionExecutionException, BlockedException {
return invokeFunction(values, context, functionTarget, false);
}

public Object invokeFunction(Object[] values, CommandContext context, Object functionTarget, boolean calledWithVarArgArrayParam) throws FunctionExecutionException, BlockedException {
if (!isNullDependent()) {
for (int i = requiresContext?1:0; i < values.length; i++) {
if (values[i] == null) {
Expand Down Expand Up @@ -337,14 +340,6 @@ public static Object importValue(Object result, Class<?> expectedType, CommandCo
return result;
}

public boolean isCalledWithVarArgArrayParam() {
return calledWithVarArgArrayParam;
}

public void setCalledWithVarArgArrayParam(boolean calledWithVarArgArrayParam) {
this.calledWithVarArgArrayParam = calledWithVarArgArrayParam;
}

public boolean isSystemFunction(String name) {
return this.getName().equalsIgnoreCase(name) && CoreConstants.SYSTEM_MODEL.equals(this.getSchema());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.types.DataTypeManager;
import org.teiid.metadata.FunctionMethod;
import org.teiid.query.eval.TeiidScriptEngine;
import org.teiid.query.function.FunctionLibrary;
import org.teiid.query.mapping.relational.QueryNode;
Expand Down Expand Up @@ -541,4 +542,9 @@ public List<? extends Object> getModelIDs() {
return Collections.emptyList();
}

@Override
public FunctionMethod getPushdownFunction(Object modelID, String fullName) {
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.teiid.api.exception.query.QueryMetadataException;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.metadata.FunctionMethod;
import org.teiid.query.function.FunctionLibrary;
import org.teiid.query.mapping.relational.QueryNode;
import org.teiid.query.sql.symbol.Expression;
Expand Down Expand Up @@ -437,4 +438,9 @@ public List<? extends Object> getModelIDs() {
return actualMetadata.getModelIDs();
}

@Override
public FunctionMethod getPushdownFunction(Object modelID, String fullName) {
return actualMetadata.getPushdownFunction(modelID, fullName);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
import org.teiid.metadata.Table.TriggerEvent;
import org.teiid.metadata.Trigger;
import org.teiid.query.QueryPlugin;
import org.teiid.query.function.FunctionDescriptor;
import org.teiid.query.function.metadata.FunctionMetadataValidator;
import org.teiid.query.mapping.relational.QueryNode;
import org.teiid.query.metadata.MaterializationMetadataRepository.Scope;
Expand Down Expand Up @@ -321,6 +322,12 @@ public void execute(VDBMetaData vdb, MetadataStore store, ValidatorReport report

}

QueryMetadataInterface metadata = vdb.getAttachment(QueryMetadataInterface.class);
PushdownFunctions pushdownFunctions = null;
if (schema.isPhysical()) {
pushdownFunctions = new PushdownFunctions();
model.addAttachment(PushdownFunctions.class, pushdownFunctions);
}
for (FunctionMethod func:schema.getFunctions().values()) {
for (FunctionParameter param : func.getInputParameters()) {
if (param.isVarArg() && param != func.getInputParameters().get(func.getInputParameterCount() -1)) {
Expand All @@ -330,6 +337,27 @@ public void execute(VDBMetaData vdb, MetadataStore store, ValidatorReport report
if (func.getPushdown().equals(FunctionMethod.PushDown.MUST_PUSHDOWN) && !model.isSource()) {
metadataValidator.log(report, model, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31078, func.getFullName(), model.getName()));
}

if (pushdownFunctions != null) {
String virtualName = func.getProperty(FunctionMethod.VIRTUAL_FUNCTION);

if (virtualName != null) {
Class<?>[] types = new Class[func.getInputParameterCount()];
int i = 0;
for (FunctionParameter fp : func.getInputParameters()) {
types[i++] = fp.getJavaType();
}
FunctionDescriptor virtualFunction = metadata.getFunctionLibrary().findFunction(virtualName, types);
//if it exists and is a proper match, add it to the pushdown mapping
if (virtualFunction != null
//&& !virtualFunction.getMethod().getParent().isPhysical() -- sys/sysadmin are physical, so we won't check this just yet
&& !(func.isVarArgs() ^ virtualFunction.getMethod().isVarArgs())) {
pushdownFunctions.put(virtualName, func);
} else {
metadataValidator.log(report, model, Severity.WARNING, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31305, virtualName, func.getFullName()), func);
}
}
}
}
}
}
Expand Down
Loading

0 comments on commit 7c1fc08

Please sign in to comment.