Search in sources :

Example 6 with FunctionLibrary

use of org.teiid.query.function.FunctionLibrary in project teiid by teiid.

the class QueryRewriter method rewriteFunction.

private Expression rewriteFunction(Function function) throws TeiidComponentException, TeiidProcessingException {
    // rewrite alias functions
    String functionName = function.getName();
    String actualName = ALIASED_FUNCTIONS.get(functionName);
    FunctionLibrary funcLibrary = this.metadata.getFunctionLibrary();
    if (actualName != null) {
        function.setName(actualName);
        Expression[] args = function.getArgs();
        Class<?>[] types = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            types[i] = args[i].getType();
        }
        FunctionDescriptor descriptor = funcLibrary.findFunction(actualName, types);
        function.setFunctionDescriptor(descriptor);
    }
    if (StringUtil.startsWithIgnoreCase(functionName, "parse")) {
        // $NON-NLS-1$
        String type = functionName.substring(5);
        if (PARSE_FORMAT_TYPES.contains(type) && Number.class.isAssignableFrom(function.getType()) && !type.equals(DataTypeManager.DefaultDataTypes.BIG_DECIMAL)) {
            Function result = new Function(SourceSystemFunctions.PARSEBIGDECIMAL, function.getArgs());
            FunctionDescriptor descriptor = funcLibrary.findFunction(SourceSystemFunctions.PARSEBIGDECIMAL, new Class[] { DataTypeManager.DefaultDataClasses.STRING, DataTypeManager.DefaultDataClasses.STRING });
            result.setFunctionDescriptor(descriptor);
            result.setType(DataTypeManager.DefaultDataClasses.BIG_DECIMAL);
            return rewriteFunction(ResolverUtil.getConversion(result, DataTypeManager.DefaultDataTypes.BIG_DECIMAL, DataTypeManager.getDataTypeName(function.getType()), false, metadata.getFunctionLibrary()));
        } else if ((DataTypeManager.DefaultDataTypes.DATE.equalsIgnoreCase(type) || DataTypeManager.DefaultDataTypes.TIME.equalsIgnoreCase(type)) && function.getArg(1) instanceof Constant) {
            // $NON-NLS-1$
            String format = "yyyy-MM-dd";
            int length = 10;
            if (DataTypeManager.DefaultDataTypes.TIME.equalsIgnoreCase(type)) {
                // $NON-NLS-1$
                format = "hh:mm:ss";
                length = 8;
            }
            Constant c = (Constant) function.getArg(1);
            if (format.equals(c.getValue())) {
                Expression arg = function.getArg(0);
                if ((arg instanceof Function) && FunctionLibrary.isConvert((Function) arg) && java.util.Date.class.isAssignableFrom(((Function) arg).getArg(0).getType())) {
                    return rewriteExpressionDirect(ResolverUtil.getConversion(arg, DataTypeManager.DefaultDataTypes.STRING, type, false, metadata.getFunctionLibrary()));
                }
            }
        }
    } else if (StringUtil.startsWithIgnoreCase(functionName, "format")) {
        // $NON-NLS-1$
        String type = functionName.substring(6);
        if (PARSE_FORMAT_TYPES.contains(type) && Number.class.isAssignableFrom(function.getArg(0).getType()) && !type.equals(DataTypeManager.DefaultDataTypes.BIG_DECIMAL)) {
            Function bigDecimalParam = ResolverUtil.getConversion(function.getArg(0), DataTypeManager.getDataTypeName(function.getArg(0).getType()), DataTypeManager.DefaultDataTypes.BIG_DECIMAL, false, metadata.getFunctionLibrary());
            Function result = new Function(SourceSystemFunctions.FORMATBIGDECIMAL, new Expression[] { bigDecimalParam, function.getArg(1) });
            FunctionDescriptor descriptor = funcLibrary.findFunction(SourceSystemFunctions.FORMATBIGDECIMAL, new Class[] { DataTypeManager.DefaultDataClasses.BIG_DECIMAL, DataTypeManager.DefaultDataClasses.STRING });
            result.setFunctionDescriptor(descriptor);
            result.setType(DataTypeManager.DefaultDataClasses.STRING);
            return rewriteFunction(result);
        } else if ((DataTypeManager.DefaultDataTypes.DATE.equalsIgnoreCase(type) || DataTypeManager.DefaultDataTypes.TIME.equalsIgnoreCase(type)) && function.getArg(1) instanceof Constant) {
            // $NON-NLS-1$
            String format = "yyyy-MM-dd";
            if (DataTypeManager.DefaultDataTypes.TIME.equalsIgnoreCase(type)) {
                // $NON-NLS-1$
                format = "hh:mm:ss";
            }
            Constant c = (Constant) function.getArg(1);
            if (format.equals(c.getValue())) {
                return rewriteExpressionDirect(ResolverUtil.getConversion(function.getArg(0), DataTypeManager.getDataTypeName(function.getArg(0).getType()), DataTypeManager.DefaultDataTypes.STRING, false, metadata.getFunctionLibrary()));
            }
        }
    }
    boolean omitNull = false;
    Integer code = FUNCTION_MAP.get(functionName);
    if (code != null) {
        switch(code) {
            case 0:
                {
                    // space(x) => repeat(' ', x)
                    Function result = new Function(SourceSystemFunctions.REPEAT, // $NON-NLS-1$
                    new Expression[] { new Constant(" "), function.getArg(0) });
                    // resolve the function
                    FunctionDescriptor descriptor = funcLibrary.findFunction(SourceSystemFunctions.REPEAT, new Class[] { DataTypeManager.DefaultDataClasses.STRING, DataTypeManager.DefaultDataClasses.INTEGER });
                    result.setFunctionDescriptor(descriptor);
                    result.setType(DataTypeManager.DefaultDataClasses.STRING);
                    function = result;
                    break;
                }
            case 1:
                {
                    // TEIID-4455
                    break;
                }
            case 2:
                {
                    // rewrite nullif(a, b) => case when (a = b) then null else a
                    List when = Arrays.asList(new Criteria[] { new CompareCriteria(function.getArg(0), CompareCriteria.EQ, function.getArg(1)) });
                    Constant nullConstant = new Constant(null, function.getType());
                    List then = Arrays.asList(new Expression[] { nullConstant });
                    SearchedCaseExpression caseExpr = new SearchedCaseExpression(when, then);
                    caseExpr.setElseExpression(function.getArg(0));
                    caseExpr.setType(function.getType());
                    return rewriteExpressionDirect(caseExpr);
                }
            case 3:
                {
                    Expression[] args = function.getArgs();
                    if (args.length == 2) {
                        Function result = new Function(SourceSystemFunctions.IFNULL, new Expression[] { function.getArg(0), function.getArg(1) });
                        // resolve the function
                        FunctionDescriptor descriptor = funcLibrary.findFunction(SourceSystemFunctions.IFNULL, new Class[] { function.getType(), function.getType() });
                        result.setFunctionDescriptor(descriptor);
                        result.setType(function.getType());
                        function = result;
                    }
                    break;
                }
            case 4:
                omitNull = true;
                break;
            case 5:
                {
                    if (function.getType() != DataTypeManager.DefaultDataClasses.TIMESTAMP) {
                        FunctionDescriptor descriptor = funcLibrary.findFunction(SourceSystemFunctions.TIMESTAMPADD, new Class[] { DataTypeManager.DefaultDataClasses.STRING, DataTypeManager.DefaultDataClasses.INTEGER, DataTypeManager.DefaultDataClasses.TIMESTAMP });
                        function.setFunctionDescriptor(descriptor);
                        Class<?> type = function.getType();
                        function.setType(DataTypeManager.DefaultDataClasses.TIMESTAMP);
                        function.getArgs()[2] = ResolverUtil.getConversion(function.getArg(2), DataTypeManager.getDataTypeName(type), DataTypeManager.DefaultDataTypes.TIMESTAMP, false, funcLibrary);
                        function = ResolverUtil.getConversion(function, DataTypeManager.DefaultDataTypes.TIMESTAMP, DataTypeManager.getDataTypeName(type), false, funcLibrary);
                    }
                    break;
                }
            case 6:
            case 7:
                {
                    FunctionDescriptor descriptor = funcLibrary.findFunction(SourceSystemFunctions.PARSETIMESTAMP, new Class[] { DataTypeManager.DefaultDataClasses.STRING, DataTypeManager.DefaultDataClasses.STRING });
                    function.setName(SourceSystemFunctions.PARSETIMESTAMP);
                    function.setFunctionDescriptor(descriptor);
                    Class<?> type = function.getType();
                    function.setType(DataTypeManager.DefaultDataClasses.TIMESTAMP);
                    function = ResolverUtil.getConversion(function, DataTypeManager.DefaultDataTypes.TIMESTAMP, DataTypeManager.getDataTypeName(type), false, funcLibrary);
                    break;
                }
            case 8:
            case 9:
                {
                    FunctionDescriptor descriptor = funcLibrary.findFunction(SourceSystemFunctions.FORMATTIMESTAMP, new Class[] { DataTypeManager.DefaultDataClasses.TIMESTAMP, DataTypeManager.DefaultDataClasses.STRING });
                    function.setName(SourceSystemFunctions.FORMATTIMESTAMP);
                    function.setFunctionDescriptor(descriptor);
                    function.getArgs()[0] = ResolverUtil.getConversion(function.getArg(0), DataTypeManager.getDataTypeName(function.getArg(0).getType()), DataTypeManager.DefaultDataTypes.TIMESTAMP, false, funcLibrary);
                    break;
                }
            case 10:
                {
                    if (new Constant(" ").equals(function.getArg(1))) {
                        // $NON-NLS-1$
                        String spec = (String) ((Constant) function.getArg(0)).getValue();
                        Expression string = function.getArg(2);
                        if (!SQLConstants.Reserved.TRAILING.equalsIgnoreCase(spec)) {
                            function = new Function(SourceSystemFunctions.LTRIM, new Expression[] { string });
                            FunctionDescriptor descriptor = funcLibrary.findFunction(SourceSystemFunctions.LTRIM, new Class[] { DataTypeManager.DefaultDataClasses.STRING });
                            function.setFunctionDescriptor(descriptor);
                            function.setType(DataTypeManager.DefaultDataClasses.STRING);
                            string = function;
                        }
                        if (!SQLConstants.Reserved.LEADING.equalsIgnoreCase(spec)) {
                            function = new Function(SourceSystemFunctions.RTRIM, new Expression[] { string });
                            FunctionDescriptor descriptor = funcLibrary.findFunction(SourceSystemFunctions.RTRIM, new Class[] { DataTypeManager.DefaultDataClasses.STRING });
                            function.setFunctionDescriptor(descriptor);
                            function.setType(DataTypeManager.DefaultDataClasses.STRING);
                        }
                    }
                    break;
                }
            case 11:
                {
                    if (function.getArg(1) instanceof Constant) {
                        Constant c = (Constant) function.getArg(1);
                        if (!c.isMultiValued() && !c.isNull()) {
                            int val = (Integer) c.getValue();
                            if (val == 0) {
                                function.getArgs()[1] = new Constant(1);
                            }
                        }
                    }
                    break;
                }
        }
    }
    Expression[] args = function.getArgs();
    Expression[] newArgs = new Expression[args.length];
    // Rewrite args
    int j = 0;
    for (int i = 0; i < args.length; i++) {
        Expression ex = rewriteExpressionDirect(args[i]);
        if (isNull(ex)) {
            if (!function.getFunctionDescriptor().isNullDependent()) {
                return new Constant(null, function.getType());
            }
            if (omitNull) {
                continue;
            }
        }
        newArgs[j++] = ex;
    }
    if (omitNull) {
        if (j == 0) {
            return new Constant(null, function.getType());
        }
        if (j == 1) {
            return newArgs[0];
        }
        if (j != args.length) {
            newArgs = Arrays.copyOf(newArgs, j);
        }
    }
    function.setArgs(newArgs);
    if (FunctionLibrary.isConvert(function)) {
        Class<?> srcType = newArgs[0].getType();
        Class<?> tgtType = function.getType();
        if (srcType != null && tgtType != null && srcType.equals(tgtType)) {
            // unnecessary conversion
            return newArgs[0];
        }
        if (function.isImplicit()) {
            function.setImplicit(false);
        }
        if (!(newArgs[0] instanceof Function) || tgtType == DataTypeManager.DefaultDataClasses.OBJECT) {
            return function;
        }
        Function nested = (Function) newArgs[0];
        if (!FunctionLibrary.isConvert(nested)) {
            return function;
        }
        Class<?> nestedType = nested.getArgs()[0].getType();
        Transform t = DataTypeManager.getTransform(nestedType, nested.getType());
        if (t.isExplicit()) {
            // explicit conversions are required
            return function;
        }
        if (DataTypeManager.getTransform(nestedType, tgtType) == null) {
            // no direct conversion exists
            return function;
        }
        // can't remove a convert that would alter the lexical form
        if (tgtType == DataTypeManager.DefaultDataClasses.STRING && (nestedType == DataTypeManager.DefaultDataClasses.BOOLEAN || nestedType == DataTypeManager.DefaultDataClasses.DATE || nestedType == DataTypeManager.DefaultDataClasses.TIME || tgtType == DataTypeManager.DefaultDataClasses.BIG_DECIMAL || tgtType == DataTypeManager.DefaultDataClasses.FLOAT || (tgtType == DataTypeManager.DefaultDataClasses.DOUBLE && srcType != DataTypeManager.DefaultDataClasses.FLOAT))) {
            return function;
        }
        // nested implicit transform is not needed
        return rewriteExpressionDirect(ResolverUtil.getConversion(nested.getArgs()[0], DataTypeManager.getDataTypeName(nestedType), DataTypeManager.getDataTypeName(tgtType), false, funcLibrary));
    }
    // convert DECODESTRING function to CASE expression
    if (function.getName().equalsIgnoreCase(FunctionLibrary.DECODESTRING) || function.getName().equalsIgnoreCase(FunctionLibrary.DECODEINTEGER)) {
        return convertDecodeFunction(function);
    }
    return function;
}
Also used : FunctionLibrary(org.teiid.query.function.FunctionLibrary) FunctionDescriptor(org.teiid.query.function.FunctionDescriptor) RuleMergeCriteria(org.teiid.query.optimizer.relational.rules.RuleMergeCriteria) BigInteger(java.math.BigInteger) java.util(java.util) Transform(org.teiid.core.types.Transform)

Example 7 with FunctionLibrary

use of org.teiid.query.function.FunctionLibrary in project teiid by teiid.

the class QueryRewriter method simplifyMathematicalCriteria.

/**
 * @param criteria
 * @return CompareCriteria
 */
private CompareCriteria simplifyMathematicalCriteria(CompareCriteria criteria) throws TeiidProcessingException {
    Expression leftExpr = criteria.getLeftExpression();
    Expression rightExpr = criteria.getRightExpression();
    // Identify all the pieces of this criteria
    Function function = (Function) leftExpr;
    String funcName = function.getName();
    Expression[] args = function.getArgs();
    Constant const1 = null;
    Expression expr = null;
    if (args[1] instanceof Constant) {
        const1 = (Constant) args[1];
        expr = args[0];
    } else {
        if (funcName.equals("+") || funcName.equals("*")) {
            // $NON-NLS-1$ //$NON-NLS-2$
            const1 = (Constant) args[0];
            expr = args[1];
        } else {
            // If we have "5 - x = 10" or "5 / x = 10", abort!
            return criteria;
        }
    }
    int operator = criteria.getOperator();
    // Determine opposite function
    String oppFunc = null;
    switch(funcName.charAt(0)) {
        // $NON-NLS-1$
        case '+':
            oppFunc = "-";
            break;
        // $NON-NLS-1$
        case '-':
            oppFunc = "+";
            break;
        // $NON-NLS-1$
        case '*':
            oppFunc = "/";
            break;
        // $NON-NLS-1$
        case '/':
            oppFunc = "*";
            break;
    }
    // Create a function of the two constants and evaluate it
    Expression combinedConst = null;
    FunctionLibrary funcLib = this.metadata.getFunctionLibrary();
    FunctionDescriptor descriptor = funcLib.findFunction(oppFunc, new Class[] { rightExpr.getType(), const1.getType() });
    if (descriptor == null) {
        // See defect 9380 - this can be caused by const2 being a null Constant, for example (? + 1) < null
        return criteria;
    }
    if (rightExpr instanceof Constant) {
        Constant const2 = (Constant) rightExpr;
        try {
            Object result = descriptor.invokeFunction(new Object[] { const2.getValue(), const1.getValue() }, null, this.context);
            combinedConst = new Constant(result, descriptor.getReturnType());
        } catch (FunctionExecutionException e) {
            throw new QueryValidatorException(QueryPlugin.Event.TEIID30373, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30373, e.getMessage()));
        } catch (BlockedException e) {
            throw new QueryValidatorException(QueryPlugin.Event.TEIID30373, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30373, e.getMessage()));
        }
    } else {
        Function conversion = new Function(descriptor.getName(), new Expression[] { rightExpr, const1 });
        conversion.setType(leftExpr.getType());
        conversion.setFunctionDescriptor(descriptor);
        combinedConst = conversion;
    }
    // Flip operator if necessary
    if (!(operator == CompareCriteria.EQ || operator == CompareCriteria.NE) && (oppFunc.equals("*") || oppFunc.equals("/"))) {
        // $NON-NLS-1$ //$NON-NLS-2$
        Object value = const1.getValue();
        if (value != null) {
            Class type = const1.getType();
            Comparable comparisonObject = null;
            if (type.equals(DataTypeManager.DefaultDataClasses.INTEGER)) {
                comparisonObject = INTEGER_ZERO;
            } else if (type.equals(DataTypeManager.DefaultDataClasses.DOUBLE)) {
                comparisonObject = DOUBLE_ZERO;
            } else if (type.equals(DataTypeManager.DefaultDataClasses.FLOAT)) {
                comparisonObject = FLOAT_ZERO;
            } else if (type.equals(DataTypeManager.DefaultDataClasses.LONG)) {
                comparisonObject = LONG_ZERO;
            } else if (type.equals(DataTypeManager.DefaultDataClasses.BIG_INTEGER)) {
                comparisonObject = BIG_INTEGER_ZERO;
            } else if (type.equals(DataTypeManager.DefaultDataClasses.BIG_DECIMAL)) {
                comparisonObject = BIG_DECIMAL_ZERO;
            } else if (type.equals(DataTypeManager.DefaultDataClasses.SHORT)) {
                comparisonObject = SHORT_ZERO;
            } else if (type.equals(DataTypeManager.DefaultDataClasses.BYTE)) {
                comparisonObject = BYTE_ZERO;
            } else {
                // Unknown type
                return criteria;
            }
            // then need to switch operator.
            if (comparisonObject.compareTo(value) > 0) {
                switch(operator) {
                    case CompareCriteria.LE:
                        operator = CompareCriteria.GE;
                        break;
                    case CompareCriteria.LT:
                        operator = CompareCriteria.GT;
                        break;
                    case CompareCriteria.GE:
                        operator = CompareCriteria.LE;
                        break;
                    case CompareCriteria.GT:
                        operator = CompareCriteria.LT;
                        break;
                }
            }
        }
    }
    criteria.setLeftExpression(expr);
    criteria.setRightExpression(combinedConst);
    criteria.setOperator(operator);
    // Return new simplified criteria
    return criteria;
}
Also used : FunctionLibrary(org.teiid.query.function.FunctionLibrary) FunctionDescriptor(org.teiid.query.function.FunctionDescriptor) BlockedException(org.teiid.common.buffer.BlockedException) FunctionExecutionException(org.teiid.api.exception.query.FunctionExecutionException) QueryValidatorException(org.teiid.api.exception.query.QueryValidatorException) LanguageObject(org.teiid.query.sql.LanguageObject)

Example 8 with FunctionLibrary

use of org.teiid.query.function.FunctionLibrary in project teiid by teiid.

the class RelationalPlanner method buildTree.

/**
 * Build a join plan based on the structure in a clause.  These structures should be
 * essentially the same tree, but with different objects and details.
 * @param clause Clause to build tree from
 * @param parent Parent node to attach join node structure to
 * @param sourceMap Map of group to source node, used for connecting children to join plan
 * @param markJoinsInternal Flag saying whether joins built in this method should be marked
 * as internal
 * @throws TeiidComponentException
 * @throws QueryMetadataException
 * @throws TeiidProcessingException
 */
void buildTree(FromClause clause, final PlanNode parent) throws QueryMetadataException, TeiidComponentException, TeiidProcessingException {
    PlanNode node = null;
    if (clause instanceof UnaryFromClause) {
        // No join required
        UnaryFromClause ufc = (UnaryFromClause) clause;
        GroupSymbol group = ufc.getGroup();
        if (metadata.isVirtualGroup(group.getMetadataID()) && !group.isTempGroupSymbol()) {
            hints.hasVirtualGroups = true;
        }
        if (!hints.hasRowBasedSecurity && RowBasedSecurityHelper.applyRowSecurity(metadata, group, context)) {
            hints.hasRowBasedSecurity = true;
        }
        if (metadata.getFunctionBasedExpressions(group.getMetadataID()) != null) {
            hints.hasFunctionBasedColumns = true;
        }
        boolean planningStackEntry = true;
        Command nestedCommand = ufc.getExpandedCommand();
        if (nestedCommand != null) {
            // other paths are inlining, so there isn't a proper virtual layer
            if (!group.isProcedure()) {
                planningStackEntry = false;
                hints.hasVirtualGroups = true;
            }
        } else if (!group.isProcedure()) {
            Object id = getTrackableGroup(group, metadata);
            if (id != null) {
                context.accessedPlanningObject(id);
            }
            if (!group.isTempGroupSymbol() && metadata.isVirtualGroup(group.getMetadataID())) {
                nestedCommand = resolveVirtualGroup(group);
            }
        }
        node = NodeFactory.getNewNode(NodeConstants.Types.SOURCE);
        if (ufc.isNoUnnest()) {
            node.setProperty(Info.NO_UNNEST, Boolean.TRUE);
        }
        node.addGroup(group);
        if (nestedCommand != null) {
            UpdateInfo info = ProcedureContainerResolver.getUpdateInfo(group, metadata);
            if (info != null && info.getPartitionInfo() != null && !info.getPartitionInfo().isEmpty()) {
                Map<ElementSymbol, List<Set<Constant>>> partitionInfo = info.getPartitionInfo();
                if (group.getDefinition() != null) {
                    partitionInfo = remapPartitionInfo(group, partitionInfo);
                }
                node.setProperty(NodeConstants.Info.PARTITION_INFO, partitionInfo);
            }
            SourceHint previous = this.sourceHint;
            if (nestedCommand.getSourceHint() != null) {
                this.sourceHint = SourceHint.combine(previous, nestedCommand.getSourceHint());
            }
            addNestedCommand(node, group, nestedCommand, nestedCommand, true, planningStackEntry);
            this.sourceHint = previous;
        } else if (this.sourceHint != null) {
            node.setProperty(Info.SOURCE_HINT, this.sourceHint);
        }
        if (group.getName().contains(RulePlaceAccess.RECONTEXT_STRING)) {
            this.context.getGroups().add(group.getName());
        }
        parent.addLastChild(node);
    } else if (clause instanceof JoinPredicate) {
        JoinPredicate jp = (JoinPredicate) clause;
        // Set up new join node corresponding to this join predicate
        node = NodeFactory.getNewNode(NodeConstants.Types.JOIN);
        node.setProperty(NodeConstants.Info.JOIN_TYPE, jp.getJoinType());
        node.setProperty(NodeConstants.Info.JOIN_STRATEGY, JoinStrategyType.NESTED_LOOP);
        node.setProperty(NodeConstants.Info.JOIN_CRITERIA, jp.getJoinCriteria());
        if (jp.isPreserve()) {
            node.setProperty(Info.PRESERVE, Boolean.TRUE);
        }
        // Attach join node to parent
        parent.addLastChild(node);
        // Handle each child
        FromClause[] clauses = new FromClause[] { jp.getLeftClause(), jp.getRightClause() };
        for (int i = 0; i < 2; i++) {
            if (jp.isPreserve() && clauses[i] instanceof JoinPredicate) {
                ((JoinPredicate) clauses[i]).setPreserve(true);
            }
            buildTree(clauses[i], node);
            // Add groups to joinNode
            node.addGroups(node.getLastChild().getGroups());
        }
    } else if (clause instanceof SubqueryFromClause) {
        SubqueryFromClause sfc = (SubqueryFromClause) clause;
        GroupSymbol group = sfc.getGroupSymbol();
        Command nestedCommand = sfc.getCommand();
        node = NodeFactory.getNewNode(NodeConstants.Types.SOURCE);
        if (sfc.isLateral()) {
            sfc.getCommand().setCorrelatedReferences(getCorrelatedReferences(parent, node, sfc));
        }
        if (sfc.isNoUnnest()) {
            node.setProperty(Info.NO_UNNEST, Boolean.TRUE);
        }
        SourceHint previous = this.sourceHint;
        if (nestedCommand.getSourceHint() != null) {
            this.sourceHint = SourceHint.combine(previous, nestedCommand.getSourceHint());
        }
        node.addGroup(group);
        addNestedCommand(node, group, nestedCommand, nestedCommand, true, false);
        this.sourceHint = previous;
        if (nestedCommand instanceof SetQuery) {
            Map<ElementSymbol, List<Set<Constant>>> partitionInfo = PartitionAnalyzer.extractPartionInfo((SetQuery) nestedCommand, ResolverUtil.resolveElementsInGroup(group, metadata));
            if (!partitionInfo.isEmpty()) {
                node.setProperty(NodeConstants.Info.PARTITION_INFO, partitionInfo);
            }
        }
        hints.hasVirtualGroups = true;
        parent.addLastChild(node);
        if (group.getName().contains(RulePlaceAccess.RECONTEXT_STRING)) {
            this.context.getGroups().add(group.getName());
        }
    } else if (clause instanceof TableFunctionReference) {
        TableFunctionReference tt = (TableFunctionReference) clause;
        GroupSymbol group = tt.getGroupSymbol();
        if (group.getName().contains(RulePlaceAccess.RECONTEXT_STRING)) {
            this.context.getGroups().add(group.getName());
        }
        // special handling to convert array table into a mergable construct
        if (parent.getType() == NodeConstants.Types.JOIN && tt instanceof ArrayTable) {
            JoinType jt = (JoinType) parent.getProperty(Info.JOIN_TYPE);
            if (jt != JoinType.JOIN_FULL_OUTER && parent.getChildCount() > 0) {
                ArrayTable at = (ArrayTable) tt;
                // rewrite if free of subqueries
                if (ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(at).isEmpty()) {
                    List<ElementSymbol> symbols = at.getProjectedSymbols();
                    FunctionLibrary funcLib = this.metadata.getFunctionLibrary();
                    FunctionDescriptor descriptor = funcLib.findFunction(FunctionLibrary.ARRAY_GET, new Class[] { DataTypeManager.DefaultDataClasses.OBJECT, DataTypeManager.DefaultDataClasses.INTEGER });
                    Query query = new Query();
                    Select select = new Select();
                    query.setSelect(select);
                    for (int i = 0; i < symbols.size(); i++) {
                        ElementSymbol es = symbols.get(i);
                        Function f = new Function(FunctionLibrary.ARRAY_GET, new Expression[] { (Expression) at.getArrayValue().clone(), new Constant(i + 1) });
                        f.setType(DataTypeManager.DefaultDataClasses.OBJECT);
                        f.setFunctionDescriptor(descriptor);
                        Expression ex = f;
                        if (es.getType() != DataTypeManager.DefaultDataClasses.OBJECT) {
                            ex = ResolverUtil.getConversion(ex, DataTypeManager.DefaultDataTypes.OBJECT, DataTypeManager.getDataTypeName(es.getType()), false, metadata.getFunctionLibrary());
                        }
                        select.addSymbol(new AliasSymbol(es.getShortName(), ex));
                    }
                    SubqueryFromClause sfc = new SubqueryFromClause(at.getGroupSymbol(), query);
                    sfc.setLateral(true);
                    buildTree(sfc, parent);
                    if (!jt.isOuter()) {
                        // insert is null criteria
                        IsNullCriteria criteria = new IsNullCriteria((Expression) at.getArrayValue().clone());
                        if (sfc.getCommand().getCorrelatedReferences() != null) {
                            RuleMergeCriteria.ReferenceReplacementVisitor rrv = new RuleMergeCriteria.ReferenceReplacementVisitor(sfc.getCommand().getCorrelatedReferences());
                            PreOrPostOrderNavigator.doVisit(criteria, rrv, PreOrPostOrderNavigator.PRE_ORDER);
                        }
                        criteria.setNegated(true);
                        if (jt == JoinType.JOIN_CROSS) {
                            parent.setProperty(NodeConstants.Info.JOIN_TYPE, JoinType.JOIN_INNER);
                        }
                        List<Criteria> joinCriteria = (List<Criteria>) parent.getProperty(Info.JOIN_CRITERIA);
                        if (joinCriteria == null) {
                            joinCriteria = new ArrayList<Criteria>(2);
                        }
                        joinCriteria.add(criteria);
                        parent.setProperty(NodeConstants.Info.JOIN_CRITERIA, joinCriteria);
                    }
                    return;
                }
            }
        }
        node = NodeFactory.getNewNode(NodeConstants.Types.SOURCE);
        node.setProperty(NodeConstants.Info.TABLE_FUNCTION, tt);
        tt.setCorrelatedReferences(getCorrelatedReferences(parent, node, tt));
        node.addGroup(group);
        parent.addLastChild(node);
    } else {
        // $NON-NLS-1$
        throw new AssertionError("Unknown Type");
    }
    if (clause.isOptional()) {
        node.setProperty(NodeConstants.Info.IS_OPTIONAL, Boolean.TRUE);
    }
    if (clause.getMakeDep() != null) {
        node.setProperty(NodeConstants.Info.MAKE_DEP, clause.getMakeDep());
    } else if (clause.isMakeNotDep()) {
        node.setProperty(NodeConstants.Info.MAKE_NOT_DEP, Boolean.TRUE);
    }
    if (clause.getMakeInd() != null) {
        node.setProperty(NodeConstants.Info.MAKE_IND, clause.getMakeInd());
    }
}
Also used : FunctionLibrary(org.teiid.query.function.FunctionLibrary) FunctionDescriptor(org.teiid.query.function.FunctionDescriptor) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) UpdateInfo(org.teiid.query.validator.UpdateValidator.UpdateInfo) CreateProcedureCommand(org.teiid.query.sql.proc.CreateProcedureCommand) LanguageObject(org.teiid.query.sql.LanguageObject)

Example 9 with FunctionLibrary

use of org.teiid.query.function.FunctionLibrary in project teiid by teiid.

the class QueryRewriter method simplifyParseFormatFunction.

private Criteria simplifyParseFormatFunction(CompareCriteria crit) {
    // TODO: this can be relaxed for order preserving operations
    if (!(crit.getOperator() == CompareCriteria.EQ || crit.getOperator() == CompareCriteria.NE)) {
        return crit;
    }
    boolean isFormat = false;
    Function leftFunction = (Function) crit.getLeftExpression();
    String funcName = leftFunction.getName();
    String inverseFunction = null;
    if (StringUtil.startsWithIgnoreCase(funcName, "parse")) {
        // $NON-NLS-1$
        String type = funcName.substring(5);
        if (!PARSE_FORMAT_TYPES.contains(type)) {
            return crit;
        }
        // $NON-NLS-1$
        inverseFunction = "format" + type;
    } else if (StringUtil.startsWithIgnoreCase(funcName, "format")) {
        // $NON-NLS-1$
        String type = funcName.substring(6);
        if (!PARSE_FORMAT_TYPES.contains(type)) {
            return crit;
        }
        // $NON-NLS-1$
        inverseFunction = "parse" + type;
        isFormat = true;
    } else {
        return crit;
    }
    Expression rightExpr = crit.getRightExpression();
    if (!(rightExpr instanceof Constant)) {
        return crit;
    }
    Expression leftExpr = leftFunction.getArgs()[0];
    Expression formatExpr = leftFunction.getArgs()[1];
    if (!(formatExpr instanceof Constant)) {
        return crit;
    }
    String format = (String) ((Constant) formatExpr).getValue();
    FunctionLibrary funcLib = this.metadata.getFunctionLibrary();
    FunctionDescriptor descriptor = funcLib.findFunction(inverseFunction, new Class[] { rightExpr.getType(), formatExpr.getType() });
    if (descriptor == null) {
        return crit;
    }
    Object value = ((Constant) rightExpr).getValue();
    try {
        Object result = descriptor.invokeFunction(new Object[] { context, ((Constant) rightExpr).getValue(), format }, null, this.context);
        result = leftFunction.getFunctionDescriptor().invokeFunction(new Object[] { context, result, format }, null, this.context);
        if (Constant.COMPARATOR.compare(value, result) != 0) {
            return getSimpliedCriteria(crit, leftExpr, crit.getOperator() != CompareCriteria.EQ, true);
        }
    } catch (FunctionExecutionException e) {
        // Not all numeric formats are invertable, so just return the criteria as it may still be valid
        return crit;
    } catch (BlockedException e) {
        return crit;
    }
    // parseFunctions are all potentially narrowing
    if (!isFormat) {
        return crit;
    }
    // TODO: if format is not lossy, then invert the function
    return crit;
}
Also used : FunctionExecutionException(org.teiid.api.exception.query.FunctionExecutionException) FunctionLibrary(org.teiid.query.function.FunctionLibrary) LanguageObject(org.teiid.query.sql.LanguageObject) FunctionDescriptor(org.teiid.query.function.FunctionDescriptor) BlockedException(org.teiid.common.buffer.BlockedException)

Example 10 with FunctionLibrary

use of org.teiid.query.function.FunctionLibrary in project teiid by teiid.

the class TranslationUtility method addUDF.

public void addUDF(String schema, Collection<FunctionMethod> methods) {
    if (methods == null || methods.isEmpty()) {
        return;
    }
    this.functions.add(new FunctionTree(schema, new UDFSource(methods)));
    SystemFunctionManager sfm = SystemMetadata.getInstance().getSystemFunctionManager();
    functionLibrary = new FunctionLibrary(sfm.getSystemFunctions(), this.functions.toArray(new FunctionTree[this.functions.size()]));
}
Also used : UDFSource(org.teiid.query.function.UDFSource) FunctionTree(org.teiid.query.function.FunctionTree) SystemFunctionManager(org.teiid.query.function.SystemFunctionManager) FunctionLibrary(org.teiid.query.function.FunctionLibrary)

Aggregations

FunctionLibrary (org.teiid.query.function.FunctionLibrary)10 FunctionDescriptor (org.teiid.query.function.FunctionDescriptor)7 Test (org.junit.Test)3 LanguageObject (org.teiid.query.sql.LanguageObject)3 Constant (org.teiid.query.sql.symbol.Constant)3 Expression (org.teiid.query.sql.symbol.Expression)3 Function (org.teiid.query.sql.symbol.Function)3 FunctionExecutionException (org.teiid.api.exception.query.FunctionExecutionException)2 BlockedException (org.teiid.common.buffer.BlockedException)2 FunctionTree (org.teiid.query.function.FunctionTree)2 ElementSymbol (org.teiid.query.sql.symbol.ElementSymbol)2 BigInteger (java.math.BigInteger)1 java.util (java.util)1 TreeMap (java.util.TreeMap)1 QueryValidatorException (org.teiid.api.exception.query.QueryValidatorException)1 Transform (org.teiid.core.types.Transform)1 FunctionMethod (org.teiid.metadata.FunctionMethod)1 SystemFunctionManager (org.teiid.query.function.SystemFunctionManager)1 UDFSource (org.teiid.query.function.UDFSource)1 BasicQueryMetadataWrapper (org.teiid.query.metadata.BasicQueryMetadataWrapper)1