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);
}
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;
}
}
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));
}
}
}
}
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);
}
}
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));
}
Aggregations