Search in sources :

Example 6 with Transform

use of org.teiid.core.types.Transform in project teiid by teiid.

the class FunctionLibrary method determineNecessaryConversions.

/**
 * Get the conversions that are needed to call the named function with arguments
 * of the given type.  In the case of an exact match, the list will contain all nulls.
 * In other cases the list will contain one or more non-null values where the value
 * is a conversion function that can be used to convert to the proper types for
 * executing the function.
 * @param name Name of function
 * @param returnType
 * @param args
 * @param types Existing types passed to the function
 * @throws InvalidFunctionException
 * @throws QueryResolverException
 */
public ConversionResult determineNecessaryConversions(String name, Class<?> returnType, Expression[] args, Class<?>[] types, boolean hasUnknownType) throws InvalidFunctionException {
    // First find existing functions with same name and same number of parameters
    final Collection<FunctionMethod> functionMethods = new LinkedList<FunctionMethod>();
    functionMethods.addAll(this.systemFunctions.findFunctionMethods(name, types.length));
    if (this.userFunctions != null) {
        for (FunctionTree tree : this.userFunctions) {
            functionMethods.addAll(tree.findFunctionMethods(name, types.length));
        }
    }
    // Score each match, reject any where types can not be converted implicitly
    // Score of current method (lower score means better match with less converts
    // Current best score (lower score is best.  Higher score results in more implicit conversions
    int bestScore = Integer.MAX_VALUE;
    boolean ambiguous = false;
    FunctionMethod result = null;
    boolean isSystem = false;
    boolean narrowing = false;
    outer: for (FunctionMethod nextMethod : functionMethods) {
        int currentScore = 0;
        boolean nextNarrowing = false;
        final List<FunctionParameter> methodTypes = nextMethod.getInputParameters();
        // no implicit conversion is possible
        for (int i = 0; i < types.length; i++) {
            final String tmpTypeName = methodTypes.get(Math.min(i, methodTypes.size() - 1)).getRuntimeType();
            Class<?> targetType = DataTypeManager.getDataTypeClass(tmpTypeName);
            Class<?> sourceType = types[i];
            if (sourceType == null) {
                currentScore++;
                continue;
            }
            if (sourceType.isArray() && targetType.isArray() && sourceType.getComponentType().equals(targetType.getComponentType())) {
                currentScore++;
                continue;
            }
            if (sourceType.isArray()) {
                if (isVarArgArrayParam(nextMethod, types, i, targetType)) {
                    // vararg array parameter
                    continue;
                }
                // treat the array as object type until proper type handling is added
                sourceType = DataTypeManager.DefaultDataClasses.OBJECT;
            }
            try {
                Transform t = getConvertFunctionDescriptor(sourceType, targetType);
                if (t != null) {
                    if (t.isExplicit()) {
                        if (!(args[i] instanceof Constant) || ResolverUtil.convertConstant(DataTypeManager.getDataTypeName(sourceType), tmpTypeName, (Constant) args[i]) == null) {
                            continue outer;
                        }
                        nextNarrowing = true;
                        currentScore++;
                    } else {
                        currentScore++;
                    }
                }
            } catch (InvalidFunctionException e) {
                continue outer;
            }
        }
        // If the method is valid match and it is the current best score, capture those values as current best match
        if (currentScore > bestScore) {
            continue;
        }
        if (hasUnknownType) {
            if (returnType != null) {
                try {
                    Transform t = getConvertFunctionDescriptor(DataTypeManager.getDataTypeClass(nextMethod.getOutputParameter().getRuntimeType()), returnType);
                    if (t != null) {
                        if (t.isExplicit()) {
                            // there still may be a common type, but use any other valid conversion over this one
                            currentScore += types.length + 1;
                            nextNarrowing = true;
                        } else {
                            currentScore++;
                        }
                    }
                } catch (InvalidFunctionException e) {
                    // there still may be a common type, but use any other valid conversion over this one
                    currentScore += (types.length * types.length);
                }
            }
        }
        if (nextNarrowing && result != null && !narrowing) {
            continue;
        }
        boolean useNext = false;
        if (!nextNarrowing && narrowing) {
            useNext = true;
        }
        boolean isSystemNext = nextMethod.getParent() == null || INTERNAL_SCHEMAS.contains(nextMethod.getParent().getName());
        if ((isSystem && isSystemNext) || (!isSystem && !isSystemNext && result != null)) {
            int partCount = partCount(result.getName());
            int nextPartCount = partCount(nextMethod.getName());
            if (partCount < nextPartCount) {
                // this makes us more consistent with the table resolving logic
                continue outer;
            }
            if (nextPartCount < partCount) {
                useNext = true;
            }
        } else if (isSystemNext) {
            useNext = true;
        }
        if (currentScore == bestScore && !useNext) {
            ambiguous = true;
            boolean useCurrent = false;
            List<FunctionParameter> bestParams = result.getInputParameters();
            for (int j = 0; j < types.length; j++) {
                String t1 = bestParams.get(Math.min(j, bestParams.size() - 1)).getRuntimeType();
                String t2 = methodTypes.get((Math.min(j, methodTypes.size() - 1))).getRuntimeType();
                if (types[j] == null || t1.equals(t2)) {
                    continue;
                }
                String commonType = ResolverUtil.getCommonRuntimeType(new String[] { t1, t2 });
                if (commonType == null) {
                    // still ambiguous
                    continue outer;
                }
                if (commonType.equals(t1)) {
                    if (!useCurrent) {
                        useNext = true;
                    }
                } else if (commonType.equals(t2)) {
                    if (!useNext) {
                        useCurrent = true;
                    }
                } else {
                    continue outer;
                }
            }
            if (useCurrent) {
                // prefer narrower
                ambiguous = false;
            } else {
                String sysName = result.getProperty(FunctionMethod.SYSTEM_NAME, false);
                String sysNameOther = nextMethod.getProperty(FunctionMethod.SYSTEM_NAME, false);
                if (sysName != null && sysName.equalsIgnoreCase(sysNameOther)) {
                    ambiguous = false;
                }
            }
        }
        if (currentScore < bestScore || useNext) {
            ambiguous = false;
            if (currentScore == 0 && isSystemNext) {
                return new ConversionResult(nextMethod);
            }
            bestScore = currentScore;
            result = nextMethod;
            isSystem = isSystemNext;
            narrowing = nextNarrowing;
        }
    }
    if (ambiguous) {
        throw GENERIC_EXCEPTION;
    }
    ConversionResult cr = new ConversionResult(result);
    if (result != null) {
        cr.needsConverion = (bestScore != 0);
    }
    return cr;
}
Also used : Constant(org.teiid.query.sql.symbol.Constant) LinkedList(java.util.LinkedList) FunctionMethod(org.teiid.metadata.FunctionMethod) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) List(java.util.List) Transform(org.teiid.core.types.Transform) InvalidFunctionException(org.teiid.api.exception.query.InvalidFunctionException)

Aggregations

Transform (org.teiid.core.types.Transform)6 TransformationException (org.teiid.core.types.TransformationException)3 BigInteger (java.math.BigInteger)2 Blob (java.sql.Blob)2 Date (java.sql.Date)2 SQLXML (java.sql.SQLXML)2 List (java.util.List)2 BasicDBList (com.mongodb.BasicDBList)1 BasicDBObject (com.mongodb.BasicDBObject)1 DBRef (com.mongodb.DBRef)1 GridFS (com.mongodb.gridfs.GridFS)1 GridFSDBFile (com.mongodb.gridfs.GridFSDBFile)1 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 ObjectOutputStream (java.io.ObjectOutputStream)1 Serializable (java.io.Serializable)1 BigDecimal (java.math.BigDecimal)1 Array (java.sql.Array)1 SQLException (java.sql.SQLException)1