/* * DBeaver - Universal Database Manager * Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jkiss.dbeaver.ext.postgresql.model.plan; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor; import org.jkiss.dbeaver.model.preferences.DBPPropertySource; import org.jkiss.dbeaver.model.exec.plan.DBCPlanNode; import org.jkiss.dbeaver.model.meta.Property; import org.jkiss.dbeaver.model.impl.PropertyDescriptor; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import org.jkiss.utils.CommonUtils; import org.jkiss.utils.xml.XMLUtils; import org.w3c.dom.Element; import org.w3c.dom.Node; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * Postgre execution plan node */ public class PostgrePlanNode implements DBCPlanNode, DBPPropertySource { public static final String ATTR_NODE_TYPE = "Node-Type"; public static final String ATTR_RELATION_NAME = "Relation-Name"; public static final String ATTR_ALIAS = "Alias"; public static final String ATTR_TOTAL_COST = "Total-Cost"; public static final String ATTR_STARTUP_COST = "Startup-Cost"; public static final String ATTR_INDEX_NAME = "Index-Name"; private PostgrePlanNode parent; private List<PostgrePlanNode> nested; private String nodeType; private String entity; private String cost; private Map<String, String> attributes = new LinkedHashMap<>(); public PostgrePlanNode(PostgrePlanNode parent, Element element) { this.parent = parent; for (Node child = element.getFirstChild(); child != null; child = child.getNextSibling()) { if (child instanceof Element && !"Plans".equals(child.getNodeName())) { attributes.put(child.getNodeName(), child.getTextContent()); } } nodeType = attributes.remove(ATTR_NODE_TYPE); entity = attributes.get(ATTR_RELATION_NAME); if (entity != null) { String alias = attributes.get(ATTR_ALIAS); if (alias != null && !alias.equals(entity)) { entity += " as " + alias; } } else { entity = attributes.get(ATTR_INDEX_NAME); } String startCost = attributes.remove(ATTR_STARTUP_COST); String totalCost = attributes.remove(ATTR_TOTAL_COST); cost = startCost + " - " + totalCost; Element nestedPlansElement = XMLUtils.getChildElement(element, "Plans"); if (nestedPlansElement != null) { for (Element planElement : XMLUtils.getChildElementList(nestedPlansElement, "Plan")) { if (nested == null) { nested = new ArrayList<>(); } nested.add(new PostgrePlanNode(null, planElement)); } } } @Property(order = 0, viewable = true) public String getNodeType() { return nodeType; } @Property(order = 2, viewable = true) public String getEntity() { return entity; } @Property(order = 3, viewable = true) public String getCost() { return cost; } @Override public DBCPlanNode getParent() { return parent; } @Override public List<PostgrePlanNode> getNested() { return nested; } @Override public Object getEditableValue() { return this; } @Override public DBPPropertyDescriptor[] getPropertyDescriptors2() { DBPPropertyDescriptor[] props = new DBPPropertyDescriptor[attributes.size()]; int index = 0; for (Map.Entry<String, String> attr : attributes.entrySet()) { props[index++] = new PropertyDescriptor("Source", attr.getKey(), attr.getKey(), null, String.class, false, null, null, false); } return props; } @Override public Object getPropertyValue(@Nullable DBRProgressMonitor monitor, Object id) { return attributes.get(id.toString()); } @Override public boolean isPropertySet(Object id) { return false;//attributes.containsKey(id.toString()); } @Override public boolean isPropertyResettable(Object id) { return false; } @Override public void resetPropertyValue(@Nullable DBRProgressMonitor monitor, Object id) { } @Override public void resetPropertyValueToDefault(Object id) { } @Override public void setPropertyValue(@Nullable DBRProgressMonitor monitor, Object id, Object value) { } @Override public boolean isDirty(Object id) { return false; } @Override public String toString() { StringBuilder title = new StringBuilder(); title.append("Type: ").append(nodeType); String joinType = attributes.get("Join-Type"); if (!CommonUtils.isEmpty(joinType)) { title.append(" (").append(joinType).append(")"); } title.append("; "); if (!CommonUtils.isEmpty(entity)) { title.append("Rel: ").append(entity).append(" "); } title.append("; Cost: ").append(cost); return title.toString(); } }