Search in sources :

Example 6 with Annotation

use of org.teiid.client.plan.Annotation in project teiid by teiid.

the class StatementImpl method executeShow.

ResultsFuture<Boolean> executeShow(Matcher match) throws SQLException {
    String show = match.group(1);
    show = unescapeId(show);
    if (show.equalsIgnoreCase("PLAN")) {
        // $NON-NLS-1$
        List<ArrayList<Object>> records = new ArrayList<ArrayList<Object>>(1);
        PlanNode plan = driverConnection.getCurrentPlanDescription();
        String connDebugLog = driverConnection.getDebugLog();
        if (plan != null || connDebugLog != null) {
            ArrayList<Object> row = new ArrayList<Object>(3);
            if (plan != null) {
                row.add(DataTypeTransformer.getClob(plan.toString()));
                row.add(new SQLXMLImpl(plan.toXml()));
            } else {
                row.add(null);
                row.add(null);
            }
            row.add(DataTypeTransformer.getClob(connDebugLog));
            records.add(row);
        }
        createResultSet(// $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
        records, // $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
        new String[] { "PLAN_TEXT", "PLAN_XML", "DEBUG_LOG" }, new String[] { DataTypeManager.DefaultDataTypes.CLOB, DataTypeManager.DefaultDataTypes.XML, DataTypeManager.DefaultDataTypes.CLOB });
        return booleanFuture(true);
    }
    if (show.equalsIgnoreCase("ANNOTATIONS")) {
        // $NON-NLS-1$
        List<ArrayList<Object>> records = new ArrayList<ArrayList<Object>>(1);
        Collection<Annotation> annos = driverConnection.getAnnotations();
        for (Annotation annotation : annos) {
            ArrayList<Object> row = new ArrayList<Object>(4);
            row.add(annotation.getCategory());
            row.add(annotation.getPriority().name());
            row.add(annotation.getAnnotation());
            row.add(annotation.getResolution());
            records.add(row);
        }
        createResultSet(// $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
        records, // $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
        new String[] { "CATEGORY", "PRIORITY", "ANNOTATION", "RESOLUTION" }, new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING });
        return booleanFuture(true);
    }
    if (show.equalsIgnoreCase("ALL")) {
        // $NON-NLS-1$
        List<ArrayList<Object>> records = new ArrayList<ArrayList<Object>>(1);
        for (String key : driverConnection.getExecutionProperties().stringPropertyNames()) {
            ArrayList<Object> row = new ArrayList<Object>(4);
            row.add(key);
            row.add(driverConnection.getExecutionProperties().get(key));
            records.add(row);
        }
        createResultSet(// $NON-NLS-1$ //$NON-NLS-2$
        records, // $NON-NLS-1$ //$NON-NLS-2$
        new String[] { "NAME", "VALUE" }, new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING });
        return booleanFuture(true);
    }
    if (show.equalsIgnoreCase("transaction isolation level")) {
        // $NON-NLS-1$
        List<ArrayList<Object>> records = new ArrayList<ArrayList<Object>>(1);
        ArrayList<Object> row = new ArrayList<Object>(1);
        switch(driverConnection.getTransactionIsolation()) {
            case Connection.TRANSACTION_READ_COMMITTED:
                // $NON-NLS-1$
                row.add("READ COMMITTED");
                break;
            case Connection.TRANSACTION_READ_UNCOMMITTED:
                // $NON-NLS-1$
                row.add("READ UNCOMMITTED");
                break;
            case Connection.TRANSACTION_REPEATABLE_READ:
                // $NON-NLS-1$
                row.add("REPEATABLE READ");
                break;
            case Connection.TRANSACTION_SERIALIZABLE:
                // $NON-NLS-1$
                row.add("SERIALIZABLE");
                break;
            default:
                // $NON-NLS-1$
                row.add("UNKNOWN");
        }
        records.add(row);
        createResultSet(// $NON-NLS-1$
        records, // $NON-NLS-1$
        new String[] { "TRANSACTION ISOLATION" }, new String[] { DataTypeManager.DefaultDataTypes.STRING });
        return booleanFuture(true);
    }
    List<List<String>> records = Collections.singletonList(Collections.singletonList(driverConnection.getExecutionProperty(show)));
    createResultSet(records, new String[] { show }, new String[] { DataTypeManager.DefaultDataTypes.STRING });
    return booleanFuture(true);
}
Also used : SQLXMLImpl(org.teiid.core.types.SQLXMLImpl) PlanNode(org.teiid.client.plan.PlanNode) Annotation(org.teiid.client.plan.Annotation)

Example 7 with Annotation

use of org.teiid.client.plan.Annotation in project teiid by teiid.

the class RuleMergeCriteria method planMergeJoin.

/**
 * Look for:
 * [NOT] EXISTS ( )
 * IN ( ) / SOME ( )
 *
 * and replace with a semi join
 */
private PlanNode planMergeJoin(PlanNode current, PlanNode root) throws QueryMetadataException, TeiidComponentException {
    float sourceCost = NewCalculateCostUtil.computeCostForTree(current.getFirstChild(), metadata);
    Criteria crit = (Criteria) current.getProperty(NodeConstants.Info.SELECT_CRITERIA);
    PlannedResult plannedResult = findSubquery(crit, true);
    if (plannedResult.query == null) {
        return current;
    }
    if (sourceCost != NewCalculateCostUtil.UNKNOWN_VALUE && sourceCost < RuleChooseDependent.DEFAULT_INDEPENDENT_CARDINALITY && !plannedResult.mergeJoin) {
        // TODO: see if a dependent join applies the other direction
        return current;
    }
    RelationalPlan originalPlan = (RelationalPlan) plannedResult.query.getProcessorPlan();
    Number originalCardinality = originalPlan.getRootNode().getEstimateNodeCardinality();
    if (!plannedResult.mergeJoin && originalCardinality.floatValue() == NewCalculateCostUtil.UNKNOWN_VALUE) {
        // if it's currently unknown, removing criteria won't make it any better
        return current;
    }
    Collection<GroupSymbol> leftGroups = FrameUtil.findJoinSourceNode(current).getGroups();
    if (!planQuery(leftGroups, false, plannedResult)) {
        if (plannedResult.mergeJoin && analysisRecord != null && analysisRecord.recordAnnotations()) {
            // $NON-NLS-1$ //$NON-NLS-2$
            this.analysisRecord.addAnnotation(new Annotation(Annotation.HINTS, "Could not plan as a merge join: " + crit, "ignoring MJ hint", Priority.HIGH));
        }
        return current;
    }
    // check if the child is already ordered.  TODO: see if the ordering is compatible.
    PlanNode childSort = NodeEditor.findNodePreOrder(root, NodeConstants.Types.SORT, NodeConstants.Types.SOURCE | NodeConstants.Types.JOIN);
    if (childSort != null) {
        if (plannedResult.mergeJoin && analysisRecord != null && analysisRecord.recordAnnotations()) {
            // $NON-NLS-1$ //$NON-NLS-2$
            this.analysisRecord.addAnnotation(new Annotation(Annotation.HINTS, "Could not plan as a merge join since the parent join requires a sort: " + crit, "ignoring MJ hint", Priority.HIGH));
        }
        return current;
    }
    // add an order by, which hopefully will get pushed down
    plannedResult.query.setOrderBy(new OrderBy(plannedResult.rightExpressions).clone());
    for (OrderByItem item : plannedResult.query.getOrderBy().getOrderByItems()) {
        int index = plannedResult.query.getProjectedSymbols().indexOf(item.getSymbol());
        if (index >= 0 && !(item.getSymbol() instanceof ElementSymbol)) {
            item.setSymbol((Expression) plannedResult.query.getProjectedSymbols().get(index).clone());
        }
        item.setExpressionPosition(index);
    }
    try {
        // clone the symbols as they may change during planning
        List<Expression> projectedSymbols = LanguageObject.Util.deepClone(plannedResult.query.getProjectedSymbols(), Expression.class);
        // NOTE: we could tap into the relationalplanner at a lower level to get this in a plan node form,
        // the major benefit would be to reuse the dependent join planning logic if possible.
        RelationalPlan subPlan = (RelationalPlan) QueryOptimizer.optimizePlan(plannedResult.query, metadata, idGenerator, capFinder, analysisRecord, context);
        Number planCardinality = subPlan.getRootNode().getEstimateNodeCardinality();
        if (!plannedResult.mergeJoin) {
            // if we don't have a specific hint, then use costing
            if (planCardinality.floatValue() == NewCalculateCostUtil.UNKNOWN_VALUE || planCardinality.floatValue() > 10000000 || (sourceCost == NewCalculateCostUtil.UNKNOWN_VALUE && planCardinality.floatValue() > 1000) || (sourceCost != NewCalculateCostUtil.UNKNOWN_VALUE && sourceCost * originalCardinality.floatValue() < planCardinality.floatValue() / (100 * Math.log(Math.max(4, sourceCost))))) {
                // bail-out if both are unknown or the new plan is too large
                if (analysisRecord != null && analysisRecord.recordDebug()) {
                    // $NON-NLS-1$ //$NON-NLS-2$
                    current.recordDebugAnnotation("cost of merge join plan was not favorable", null, "semi merge join will not be used", analysisRecord, metadata);
                }
                return current;
            }
        }
        // assume dependent
        if ((sourceCost != NewCalculateCostUtil.UNKNOWN_VALUE && planCardinality.floatValue() != NewCalculateCostUtil.UNKNOWN_VALUE && planCardinality.floatValue() < sourceCost / 8) || (sourceCost == NewCalculateCostUtil.UNKNOWN_VALUE && planCardinality.floatValue() <= 1000)) {
            plannedResult.makeInd = true;
        }
        /*if (plannedResult.makeInd 
					&& plannedResult.query.getCorrelatedReferences() == null
					&& !plannedResult.not
					&& plannedResult.leftExpressions.size() == 1) {
            	//TODO: this should just be a dependent criteria node to avoid sorts
            }*/
        // $NON-NLS-1$ //$NON-NLS-2$
        current.recordDebugAnnotation("Conditions met (hint or cost)", null, "Converting to a semi merge join", analysisRecord, metadata);
        PlanNode semiJoin = NodeFactory.getNewNode(NodeConstants.Types.JOIN);
        semiJoin.addGroups(current.getGroups());
        Set<GroupSymbol> groups = GroupsUsedByElementsVisitor.getGroups(plannedResult.rightExpressions);
        semiJoin.addGroups(groups);
        semiJoin.setProperty(NodeConstants.Info.JOIN_STRATEGY, JoinStrategyType.MERGE);
        semiJoin.setProperty(NodeConstants.Info.JOIN_TYPE, plannedResult.not ? JoinType.JOIN_ANTI_SEMI : JoinType.JOIN_SEMI);
        semiJoin.setProperty(NodeConstants.Info.NON_EQUI_JOIN_CRITERIA, plannedResult.nonEquiJoinCriteria);
        List<Criteria> joinCriteria = new ArrayList<Criteria>();
        joinCriteria.addAll(plannedResult.nonEquiJoinCriteria);
        for (int i = 0; i < plannedResult.leftExpressions.size(); i++) {
            joinCriteria.add(new CompareCriteria((Expression) plannedResult.rightExpressions.get(i), CompareCriteria.EQ, (Expression) plannedResult.leftExpressions.get(i)));
        }
        semiJoin.setProperty(NodeConstants.Info.JOIN_CRITERIA, joinCriteria);
        // nested subqueries are possibly being promoted, so they need their references updated
        List<SymbolMap> refMaps = semiJoin.getAllReferences();
        SymbolMap parentRefs = plannedResult.query.getCorrelatedReferences();
        for (SymbolMap refs : refMaps) {
            for (Map.Entry<ElementSymbol, Expression> ref : refs.asUpdatableMap().entrySet()) {
                Expression expr = ref.getValue();
                if (expr instanceof ElementSymbol) {
                    Expression convertedExpr = parentRefs.getMappedExpression((ElementSymbol) expr);
                    if (convertedExpr != null) {
                        ref.setValue(convertedExpr);
                    }
                }
                semiJoin.getGroups().addAll(GroupsUsedByElementsVisitor.getGroups(ref.getValue()));
            }
        }
        semiJoin.setProperty(NodeConstants.Info.LEFT_EXPRESSIONS, plannedResult.leftExpressions);
        semiJoin.getGroups().addAll(GroupsUsedByElementsVisitor.getGroups(plannedResult.leftExpressions));
        semiJoin.setProperty(NodeConstants.Info.RIGHT_EXPRESSIONS, plannedResult.rightExpressions);
        semiJoin.getGroups().addAll(GroupsUsedByElementsVisitor.getGroups(plannedResult.rightExpressions));
        semiJoin.setProperty(NodeConstants.Info.SORT_RIGHT, SortOption.ALREADY_SORTED);
        semiJoin.setProperty(NodeConstants.Info.OUTPUT_COLS, root.getProperty(NodeConstants.Info.OUTPUT_COLS));
        List childOutput = (List) current.getFirstChild().getProperty(NodeConstants.Info.OUTPUT_COLS);
        PlanNode toCorrect = root;
        while (toCorrect != current) {
            toCorrect.setProperty(NodeConstants.Info.OUTPUT_COLS, childOutput);
            toCorrect = toCorrect.getFirstChild();
        }
        PlanNode node = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
        node.setProperty(NodeConstants.Info.PROCESSOR_PLAN, subPlan);
        node.setProperty(NodeConstants.Info.OUTPUT_COLS, projectedSymbols);
        node.setProperty(NodeConstants.Info.EST_CARDINALITY, planCardinality);
        node.addGroups(groups);
        root.addAsParent(semiJoin);
        semiJoin.addLastChild(node);
        PlanNode result = current.getParent();
        NodeEditor.removeChildNode(result, current);
        RuleImplementJoinStrategy.insertSort(semiJoin.getFirstChild(), (List<Expression>) plannedResult.leftExpressions, semiJoin, metadata, capFinder, true, context);
        if (plannedResult.makeInd && !plannedResult.not) {
            // TODO: would like for an enhanced sort merge with the semi dep option to avoid the sorting
            // this is a little different than a typical dependent join in that the right is the independent side
            String id = RuleChooseDependent.nextId();
            PlanNode dep = RuleChooseDependent.getDependentCriteriaNode(id, plannedResult.rightExpressions, plannedResult.leftExpressions, node, metadata, null, false, null);
            semiJoin.getFirstChild().addAsParent(dep);
            semiJoin.setProperty(NodeConstants.Info.DEPENDENT_VALUE_SOURCE, id);
            this.dependent = true;
        }
        return result;
    } catch (QueryPlannerException e) {
        // can't be done - probably access patterns - what about dependent
        return current;
    }
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) ArrayList(java.util.ArrayList) RelationalPlan(org.teiid.query.processor.relational.RelationalPlan) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) SymbolMap(org.teiid.query.sql.util.SymbolMap) Annotation(org.teiid.client.plan.Annotation) Expression(org.teiid.query.sql.symbol.Expression) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) Map(java.util.Map) SymbolMap(org.teiid.query.sql.util.SymbolMap) QueryPlannerException(org.teiid.api.exception.query.QueryPlannerException)

Example 8 with Annotation

use of org.teiid.client.plan.Annotation in project teiid by teiid.

the class RelationalPlanner method distributeDependentHints.

/**
 * Distribute and "make (not) dependent" hints specified in the query into the
 * fully resolved query plan.  This is done after virtual group resolution so
 * that all groups in the plan are known.  The hint is attached to all SOURCE
 * nodes for each group that should be made dependent/not dependent.
 * @param groups List of groups (Strings) to be made dependent
 * @param plan The canonical plan
 */
private void distributeDependentHints(Collection<String> groups, PlanNode plan, NodeConstants.Info hintProperty, Collection<? extends Object> vals) throws QueryMetadataException, TeiidComponentException {
    if (groups == null || groups.isEmpty()) {
        return;
    }
    // Get all source nodes
    List<PlanNode> nodes = NodeEditor.findAllNodes(plan, NodeConstants.Types.SOURCE);
    Iterator<? extends Object> valIter = vals.iterator();
    // attach to the correct source node
    for (String groupName : groups) {
        Object val = valIter.next();
        // Walk through nodes and apply hint to all that match group name
        boolean appliedHint = false;
        if (groupName.startsWith("@")) {
            // $NON-NLS-1$
            appliedHint = applyGlobalTableHint(plan, hintProperty, groupName.substring(1), val);
        }
        if (!appliedHint) {
            appliedHint = applyHint(nodes, groupName, hintProperty, val);
        }
        if (!appliedHint) {
            // check if it is partial group name
            Collection groupNames = metadata.getGroupsForPartialName(groupName);
            if (groupNames.size() == 1) {
                groupName = (String) groupNames.iterator().next();
                appliedHint = applyHint(nodes, groupName, hintProperty, val);
            }
            if (!appliedHint && this.analysisRecord.recordAnnotations()) {
                // $NON-NLS-1$
                String msg = QueryPlugin.Util.getString("ERR.015.004.0010", groupName);
                // $NON-NLS-1$
                this.analysisRecord.addAnnotation(new Annotation(Annotation.HINTS, msg, "ignoring hint", Priority.MEDIUM));
            }
        }
    }
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) LanguageObject(org.teiid.query.sql.LanguageObject) Annotation(org.teiid.client.plan.Annotation)

Example 9 with Annotation

use of org.teiid.client.plan.Annotation in project teiid by teiid.

the class RelationalPlanner method recordAnnotation.

private static void recordAnnotation(AnalysisRecord analysis, String type, Priority priority, String msgKey, Object... parts) {
    if (analysis.recordAnnotations()) {
        Annotation annotation = new Annotation(type, QueryPlugin.Util.getString(msgKey, parts), null, priority);
        analysis.addAnnotation(annotation);
    }
}
Also used : Annotation(org.teiid.client.plan.Annotation)

Example 10 with Annotation

use of org.teiid.client.plan.Annotation in project teiid by teiid.

the class TestAnalysisRecord method testAnnotations.

public void testAnnotations() {
    AnalysisRecord rec = new AnalysisRecord(true, false);
    assertTrue(rec.recordAnnotations());
    // $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    Annotation ann1 = new Annotation("cat", "ann", "res", Priority.MEDIUM);
    // $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    Annotation ann2 = new Annotation("cat2", "ann2", "res2", Priority.HIGH);
    rec.addAnnotation(ann1);
    rec.addAnnotation(ann2);
    Collection<Annotation> annotations = rec.getAnnotations();
    assertEquals(2, annotations.size());
    assertTrue(annotations.contains(ann1));
    assertTrue(annotations.contains(ann2));
}
Also used : Annotation(org.teiid.client.plan.Annotation)

Aggregations

Annotation (org.teiid.client.plan.Annotation)14 Test (org.junit.Test)9 AnalysisRecord (org.teiid.query.analysis.AnalysisRecord)9 Command (org.teiid.query.sql.lang.Command)9 QueryMetadataInterface (org.teiid.query.metadata.QueryMetadataInterface)6 RelationalPlan (org.teiid.query.processor.relational.RelationalPlan)4 TransformationMetadata (org.teiid.query.metadata.TransformationMetadata)3 GlobalTableStoreImpl (org.teiid.query.tempdata.GlobalTableStoreImpl)3 CommandContext (org.teiid.query.util.CommandContext)3 PlanNode (org.teiid.query.optimizer.relational.plantree.PlanNode)2 ProcessorPlan (org.teiid.query.processor.ProcessorPlan)2 ArrayList (java.util.ArrayList)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1 Map (java.util.Map)1 Ignore (org.junit.Ignore)1 QueryPlannerException (org.teiid.api.exception.query.QueryPlannerException)1 PlanNode (org.teiid.client.plan.PlanNode)1 SQLXMLImpl (org.teiid.core.types.SQLXMLImpl)1 BasicSourceCapabilities (org.teiid.query.optimizer.capabilities.BasicSourceCapabilities)1