提交 64bcb772 编写于 作者: A Andrew Khitrin

Merge branch 'devel' into 5005_MSSQL_Plan

...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
package org.jkiss.dbeaver.data.gis.handlers; package org.jkiss.dbeaver.data.gis.handlers;
import org.jkiss.code.NotNull; import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.model.data.DBDDisplayFormat;
import org.jkiss.dbeaver.model.exec.DBCException; import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.exec.DBCSession; import org.jkiss.dbeaver.model.exec.DBCSession;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCPreparedStatement; import org.jkiss.dbeaver.model.exec.jdbc.JDBCPreparedStatement;
...@@ -94,7 +95,11 @@ public class GISGeometryValueHandler extends JDBCAbstractValueHandler { ...@@ -94,7 +95,11 @@ public class GISGeometryValueHandler extends JDBCAbstractValueHandler {
if (object == null) { if (object == null) {
geometry = new DBGeometry(); geometry = new DBGeometry();
} else if (object instanceof DBGeometry) { } else if (object instanceof DBGeometry) {
geometry = (DBGeometry) object; if (copy) {
geometry = ((DBGeometry) object).copy();
} else {
geometry = (DBGeometry) object;
}
} else if (object instanceof Geometry) { } else if (object instanceof Geometry) {
geometry = new DBGeometry((Geometry)object); geometry = new DBGeometry((Geometry)object);
} else if (object instanceof byte[]) { } else if (object instanceof byte[]) {
...@@ -115,6 +120,15 @@ public class GISGeometryValueHandler extends JDBCAbstractValueHandler { ...@@ -115,6 +120,15 @@ public class GISGeometryValueHandler extends JDBCAbstractValueHandler {
return geometry; return geometry;
} }
@NotNull
@Override
public String getValueDisplayString(@NotNull DBSTypedObject column, Object value, @NotNull DBDDisplayFormat format) {
if (value instanceof DBGeometry && format == DBDDisplayFormat.NATIVE) {
return "'" + value.toString() + "'";
}
return super.getValueDisplayString(column, value, format);
}
protected byte[] fetchBytes(JDBCResultSet resultSet, int index) throws SQLException { protected byte[] fetchBytes(JDBCResultSet resultSet, int index) throws SQLException {
return resultSet.getBytes(index); return resultSet.getBytes(index);
} }
......
...@@ -25,6 +25,7 @@ import org.locationtech.jts.geom.Geometry; ...@@ -25,6 +25,7 @@ import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.ParseException; import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader; import org.locationtech.jts.io.WKTReader;
import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
/** /**
...@@ -44,6 +45,12 @@ public class DBGeometry implements DBDValue { ...@@ -44,6 +45,12 @@ public class DBGeometry implements DBDValue {
this.rawValue = rawValue; this.rawValue = rawValue;
} }
public DBGeometry(DBGeometry source) {
this.rawValue = source.rawValue;
this.srid = source.srid;
this.properties = source.properties == null ? null : new LinkedHashMap<>(source.properties);
}
public DBGeometry(Geometry rawValue) { public DBGeometry(Geometry rawValue) {
this.rawValue = rawValue; this.rawValue = rawValue;
this.srid = rawValue == null ? 0 : rawValue.getSRID(); this.srid = rawValue == null ? 0 : rawValue.getSRID();
...@@ -118,4 +125,7 @@ public class DBGeometry implements DBDValue { ...@@ -118,4 +125,7 @@ public class DBGeometry implements DBDValue {
this.properties = properties; this.properties = properties;
} }
public DBGeometry copy() {
return new DBGeometry(this);
}
} }
...@@ -96,6 +96,8 @@ public interface PostgreServerExtension ...@@ -96,6 +96,8 @@ public interface PostgreServerExtension
List<PostgrePrivilege> readObjectPermissions(DBRProgressMonitor monitor, PostgreTableBase object, boolean includeNestedObjects) throws DBException; List<PostgrePrivilege> readObjectPermissions(DBRProgressMonitor monitor, PostgreTableBase object, boolean includeNestedObjects) throws DBException;
boolean supportsExplainPlan();
boolean supportsExplainPlanXML(); boolean supportsExplainPlanXML();
boolean supportsExplainPlanVerbose(); boolean supportsExplainPlanVerbose();
......
...@@ -16,16 +16,20 @@ ...@@ -16,16 +16,20 @@
*/ */
package org.jkiss.dbeaver.ext.postgresql.model.data; package org.jkiss.dbeaver.ext.postgresql.model.data;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.data.gis.handlers.WKGUtils; import org.jkiss.dbeaver.data.gis.handlers.WKGUtils;
import org.jkiss.dbeaver.ext.postgresql.PostgreConstants; import org.jkiss.dbeaver.ext.postgresql.PostgreConstants;
import org.jkiss.dbeaver.ext.postgresql.PostgreUtils; import org.jkiss.dbeaver.ext.postgresql.PostgreUtils;
import org.jkiss.dbeaver.model.data.DBDDisplayFormat;
import org.jkiss.dbeaver.model.exec.DBCException; import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.exec.DBCSession; import org.jkiss.dbeaver.model.exec.DBCSession;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCPreparedStatement; import org.jkiss.dbeaver.model.exec.jdbc.JDBCPreparedStatement;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCResultSet; import org.jkiss.dbeaver.model.exec.jdbc.JDBCResultSet;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCSession; import org.jkiss.dbeaver.model.exec.jdbc.JDBCSession;
import org.jkiss.dbeaver.model.gis.DBGeometry; import org.jkiss.dbeaver.model.gis.DBGeometry;
import org.jkiss.dbeaver.model.gis.GisAttribute;
import org.jkiss.dbeaver.model.impl.jdbc.data.handlers.JDBCAbstractValueHandler; import org.jkiss.dbeaver.model.impl.jdbc.data.handlers.JDBCAbstractValueHandler;
import org.jkiss.dbeaver.model.sql.SQLUtils;
import org.jkiss.dbeaver.model.struct.DBSTypedObject; import org.jkiss.dbeaver.model.struct.DBSTypedObject;
import org.jkiss.utils.CommonUtils; import org.jkiss.utils.CommonUtils;
import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.Geometry;
...@@ -60,29 +64,48 @@ public class PostgreGeometryValueHandler extends JDBCAbstractValueHandler { ...@@ -60,29 +64,48 @@ public class PostgreGeometryValueHandler extends JDBCAbstractValueHandler {
@Override @Override
protected void bindParameter(JDBCSession session, JDBCPreparedStatement statement, DBSTypedObject paramType, int paramIndex, Object value) throws DBCException, SQLException { protected void bindParameter(JDBCSession session, JDBCPreparedStatement statement, DBSTypedObject paramType, int paramIndex, Object value) throws DBCException, SQLException {
int valueSRID = 0;
if (value instanceof DBGeometry) { if (value instanceof DBGeometry) {
valueSRID = ((DBGeometry) value).getSRID();
value = ((DBGeometry) value).getRawValue(); value = ((DBGeometry) value).getRawValue();
} }
if (valueSRID == 0 && paramType instanceof GisAttribute) {
valueSRID = ((GisAttribute) paramType).getAttributeGeometrySRID(session.getProgressMonitor());
}
if (value == null) { if (value == null) {
statement.setNull(paramIndex, paramType.getTypeID()); statement.setNull(paramIndex, paramType.getTypeID());
} else if (value instanceof Geometry) { } else if (value instanceof Geometry) {
if (((Geometry) value).getSRID() == 0) {
((Geometry) value).setSRID(valueSRID);
}
statement.setObject(paramIndex, getStringFromGeometry(session, (Geometry)value), Types.OTHER); statement.setObject(paramIndex, getStringFromGeometry(session, (Geometry)value), Types.OTHER);
} else if (value.getClass().getName().equals(PostgreConstants.PG_GEOMETRY_CLASS)) { } else if (value.getClass().getName().equals(PostgreConstants.PG_GEOMETRY_CLASS)) {
statement.setObject(paramIndex, value, Types.OTHER); statement.setObject(paramIndex, value, Types.OTHER);
} else { } else {
statement.setObject(paramIndex, value.toString(), Types.OTHER); String strValue = value.toString();
if (valueSRID != 0 && !strValue.startsWith("SRID=")) {
strValue = "SRID=" + valueSRID + ";" + strValue;
}
statement.setObject(paramIndex, strValue, Types.OTHER);
} }
} }
@NotNull
@Override @Override
public Class<?> getValueObjectType(DBSTypedObject attribute) { public Class<?> getValueObjectType(@NotNull DBSTypedObject attribute) {
return DBGeometry.class; return DBGeometry.class;
} }
@Override @Override
public Object getValueFromObject(DBCSession session, DBSTypedObject type, Object object, boolean copy) throws DBCException { public Object getValueFromObject(@NotNull DBCSession session, @NotNull DBSTypedObject type, Object object, boolean copy) throws DBCException {
if (object == null) { if (object == null) {
return new DBGeometry(); return new DBGeometry();
} else if (object instanceof DBGeometry) {
if (copy) {
return ((DBGeometry) object).copy();
} else {
return object;
}
} else if (object instanceof Geometry) { } else if (object instanceof Geometry) {
return new DBGeometry((Geometry) object); return new DBGeometry((Geometry) object);
} else if (object instanceof String) { } else if (object instanceof String) {
...@@ -96,6 +119,15 @@ public class PostgreGeometryValueHandler extends JDBCAbstractValueHandler { ...@@ -96,6 +119,15 @@ public class PostgreGeometryValueHandler extends JDBCAbstractValueHandler {
} }
} }
@NotNull
@Override
public String getValueDisplayString(@NotNull DBSTypedObject column, Object value, @NotNull DBDDisplayFormat format) {
if (value instanceof DBGeometry && format == DBDDisplayFormat.NATIVE) {
return "'" + value.toString() + "'";
}
return super.getValueDisplayString(column, value, format);
}
private DBGeometry makeGeometryFromWKB(DBCSession session, String hexString) throws DBCException { private DBGeometry makeGeometryFromWKB(DBCSession session, String hexString) throws DBCException {
byte[] binaryData = WKBReader.hexToBytes(hexString); byte[] binaryData = WKBReader.hexToBytes(hexString);
try { try {
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
*/ */
package org.jkiss.dbeaver.ext.postgresql.model.data; package org.jkiss.dbeaver.ext.postgresql.model.data;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.ext.postgresql.PostgreConstants; import org.jkiss.dbeaver.ext.postgresql.PostgreConstants;
import org.jkiss.dbeaver.model.data.DBDDisplayFormat; import org.jkiss.dbeaver.model.data.DBDDisplayFormat;
...@@ -70,8 +71,9 @@ public class PostgreIntervalValueHandler extends JDBCStringValueHandler { ...@@ -70,8 +71,9 @@ public class PostgreIntervalValueHandler extends JDBCStringValueHandler {
} }
} }
@NotNull
@Override @Override
public String getValueDisplayString(DBSTypedObject column, Object value, DBDDisplayFormat format) { public String getValueDisplayString(@NotNull DBSTypedObject column, Object value, @NotNull DBDDisplayFormat format) {
if (value != null && value.getClass().getName().equals(PostgreConstants.PG_INTERVAL_CLASS)) { if (value != null && value.getClass().getName().equals(PostgreConstants.PG_INTERVAL_CLASS)) {
try { try {
Number years = (Number) BeanUtils.readObjectProperty(value, "years"); Number years = (Number) BeanUtils.readObjectProperty(value, "years");
......
...@@ -141,6 +141,21 @@ public class PostgreServerCockroachDB extends PostgreServerExtensionBase { ...@@ -141,6 +141,21 @@ public class PostgreServerCockroachDB extends PostgreServerExtensionBase {
return false; return false;
} }
@Override
public boolean supportsExplainPlan() {
return false;
}
@Override
public boolean supportsExplainPlanVerbose() {
return false;
}
@Override
public boolean supportsExplainPlanXML() {
return false;
}
@Override @Override
public List<PostgrePrivilege> readObjectPermissions(DBRProgressMonitor monitor, PostgreTableBase table, boolean includeNestedObjects) throws DBException { public List<PostgrePrivilege> readObjectPermissions(DBRProgressMonitor monitor, PostgreTableBase table, boolean includeNestedObjects) throws DBException {
try (JDBCSession session = DBUtils.openMetaSession(monitor, table, "Load CockroachDB table grants")) { try (JDBCSession session = DBUtils.openMetaSession(monitor, table, "Load CockroachDB table grants")) {
......
...@@ -307,6 +307,11 @@ public abstract class PostgreServerExtensionBase implements PostgreServerExtensi ...@@ -307,6 +307,11 @@ public abstract class PostgreServerExtensionBase implements PostgreServerExtensi
return tablePermissions; return tablePermissions;
} }
@Override
public boolean supportsExplainPlan() {
return true;
}
@Override @Override
public boolean supportsExplainPlanXML() { public boolean supportsExplainPlanXML() {
return dataSource.isServerVersionAtLeast(9, 0); return dataSource.isServerVersionAtLeast(9, 0);
......
...@@ -149,12 +149,12 @@ public class PostgrePlanAnalyser extends AbstractExecutionPlan { ...@@ -149,12 +149,12 @@ public class PostgrePlanAnalyser extends AbstractExecutionPlan {
private void parsePlanText(DBCSession session, List<String> lines) { private void parsePlanText(DBCSession session, List<String> lines) {
PostgreDataSource dataSource = (PostgreDataSource) session.getDataSource(); PostgreDataSource dataSource = (PostgreDataSource) session.getDataSource();
List<PostgrePlanNodeText> nodes = new ArrayList<>(lines.size());
PostgrePlanNodeText rootNode = null, curNode = null; PostgrePlanNodeText rootNode = null, curNode = null, curParentNode = null;
int curIndent = 0; int curIndent = 0;
for (String line : lines) { for (String line : lines) {
int lineIndent = 0; int lineIndent = 0;
for (int i = 0; i < line.length(); i++) { for (int i = lineIndent; i < line.length(); i++) {
if (line.charAt(i) != ' ') { if (line.charAt(i) != ' ') {
break; break;
} }
...@@ -162,31 +162,51 @@ public class PostgrePlanAnalyser extends AbstractExecutionPlan { ...@@ -162,31 +162,51 @@ public class PostgrePlanAnalyser extends AbstractExecutionPlan {
} }
if (curIndent == 0 && lineIndent == 0) { if (curIndent == 0 && lineIndent == 0) {
// Root node // Root node
curNode = rootNode = new PostgrePlanNodeText(dataSource, null, line, lineIndent); curParentNode = curNode = rootNode = new PostgrePlanNodeText(dataSource, null, line, lineIndent);
nodes.add(rootNode);
} else if (lineIndent >= curIndent) { } else if (lineIndent >= curIndent) {
// Child node // Child node
if (line.substring(lineIndent).startsWith(NODE_PREFIX)) { if (line.substring(lineIndent).startsWith(NODE_PREFIX)) {
//log.debug("New child " + line); //log.debug("New child " + line);
if (lineIndent > curNode.getIndent()) {
curParentNode = curNode;
}
lineIndent += NODE_PREFIX.length(); lineIndent += NODE_PREFIX.length();
} else if (lineIndent == curIndent || lineIndent == curIndent + 2) { curNode = new PostgrePlanNodeText(dataSource, curParentNode, line, lineIndent);
nodes.add(0,curNode);
} else if (lineIndent == curIndent || lineIndent == curIndent) {
// Property // Property
//log.debug("New prop " + line); curNode.addProp(line);
continue;
} else { } else {
log.debug("Wrong text opening line (must start with nested node prefix): " + line); if (curNode != null) {
curNode.addProp(line);
} else {
log.debug("Unexpected node line: " + line);
}
continue;
} }
curIndent = lineIndent; curIndent = lineIndent;
} else if (lineIndent < curIndent) { } else if (lineIndent < curIndent) {
// Go to parent node if (lineIndent == 0) {
if (lineIndent == 0) {
// Trailing plan statuses // Trailing plan statuses
} else { } else {
//log.debug("Go upper " + line); if (lineIndent + NODE_PREFIX.length() < curNode.getIndent()) {
//need find upper parent
curParentNode = rootNode;
for(int i = 0;i<nodes.size();i++) {
if(nodes.get(i).getIndent() == lineIndent - 2) {
curParentNode = nodes.get(i);
break;
}
}
}
if (!line.substring(lineIndent).startsWith(NODE_PREFIX)) { if (!line.substring(lineIndent).startsWith(NODE_PREFIX)) {
log.debug("Wrong text closing line (must start with nested node prefix): " + line); curNode.addProp(line);
} else { } else {
lineIndent += NODE_PREFIX.length(); lineIndent += NODE_PREFIX.length();
curNode = new PostgrePlanNodeText(dataSource, curParentNode, line, lineIndent);
nodes.add(0,curNode);
} }
} }
curIndent = lineIndent; curIndent = lineIndent;
......
...@@ -19,7 +19,6 @@ package org.jkiss.dbeaver.ext.postgresql.model.plan; ...@@ -19,7 +19,6 @@ package org.jkiss.dbeaver.ext.postgresql.model.plan;
import org.jkiss.code.Nullable; import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.ext.postgresql.model.PostgreDataSource; import org.jkiss.dbeaver.ext.postgresql.model.PostgreDataSource;
import org.jkiss.dbeaver.model.exec.plan.DBCPlanCostNode; import org.jkiss.dbeaver.model.exec.plan.DBCPlanCostNode;
import org.jkiss.dbeaver.model.exec.plan.DBCPlanNode;
import org.jkiss.dbeaver.model.impl.PropertyDescriptor; import org.jkiss.dbeaver.model.impl.PropertyDescriptor;
import org.jkiss.dbeaver.model.impl.plan.AbstractExecutionPlanNode; import org.jkiss.dbeaver.model.impl.plan.AbstractExecutionPlanNode;
import org.jkiss.dbeaver.model.meta.Property; import org.jkiss.dbeaver.model.meta.Property;
...@@ -28,17 +27,16 @@ import org.jkiss.dbeaver.model.preferences.DBPPropertySource; ...@@ -28,17 +27,16 @@ import org.jkiss.dbeaver.model.preferences.DBPPropertySource;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.sql.SQLUtils; import org.jkiss.dbeaver.model.sql.SQLUtils;
import org.jkiss.utils.CommonUtils; import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.xml.XMLUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import java.util.*; import java.util.*;
/** /**
* Postgre execution plan node * Postgre execution plan node
*/ */
public abstract class PostgrePlanNodeBase<NODE extends PostgrePlanNodeBase> extends AbstractExecutionPlanNode implements DBCPlanCostNode, DBPPropertySource { public abstract class PostgrePlanNodeBase<NODE extends PostgrePlanNodeBase<?>> extends AbstractExecutionPlanNode implements DBCPlanCostNode, DBPPropertySource {
private static final String ATTR_JOIN_TYPE = "Join-Type";
private static final String ATTR_HASH_COND = "Hash-Cond";
public static final String ATTR_INDEX_COND = "Index-Cond";
public static final String ATTR_NODE_TYPE = "Node-Type"; public static final String ATTR_NODE_TYPE = "Node-Type";
public static final String ATTR_RELATION_NAME = "Relation-Name"; public static final String ATTR_RELATION_NAME = "Relation-Name";
public static final String ATTR_FUNCTION_NAME = "Function-Name"; public static final String ATTR_FUNCTION_NAME = "Function-Name";
...@@ -50,6 +48,8 @@ public abstract class PostgrePlanNodeBase<NODE extends PostgrePlanNodeBase> exte ...@@ -50,6 +48,8 @@ public abstract class PostgrePlanNodeBase<NODE extends PostgrePlanNodeBase> exte
public static final String ATTR_ACTUAL_ROWS = "Actual-Rows"; public static final String ATTR_ACTUAL_ROWS = "Actual-Rows";
public static final String ATTR_PLAN_ROWS = "Plan-Rows"; public static final String ATTR_PLAN_ROWS = "Plan-Rows";
public static final String ATTR_FILTER = "Filter"; public static final String ATTR_FILTER = "Filter";
public static final String ATTR_OBJECT_NAME = "Object name";
private PostgreDataSource dataSource; private PostgreDataSource dataSource;
protected NODE parent; protected NODE parent;
...@@ -130,9 +130,9 @@ public abstract class PostgrePlanNodeBase<NODE extends PostgrePlanNodeBase> exte ...@@ -130,9 +130,9 @@ public abstract class PostgrePlanNodeBase<NODE extends PostgrePlanNodeBase> exte
@Property(order = 23, viewable = true) @Property(order = 23, viewable = true)
public String getNodeCondition() { public String getNodeCondition() {
String cond = attributes.get("Index-Cond"); String cond = attributes.get(ATTR_INDEX_COND);
if (cond == null) { if (cond == null) {
cond = attributes.get("Hash-Cond"); cond = attributes.get(ATTR_HASH_COND);
} }
if (cond == null) { if (cond == null) {
cond = attributes.get(ATTR_FILTER); cond = attributes.get(ATTR_FILTER);
...@@ -177,6 +177,9 @@ public abstract class PostgrePlanNodeBase<NODE extends PostgrePlanNodeBase> exte ...@@ -177,6 +177,9 @@ public abstract class PostgrePlanNodeBase<NODE extends PostgrePlanNodeBase> exte
@Override @Override
public Number getNodeRowCount() { public Number getNodeRowCount() {
String rows = attributes.get(ATTR_ACTUAL_ROWS); String rows = attributes.get(ATTR_ACTUAL_ROWS);
if (rows == null) {
rows = attributes.get(ATTR_PLAN_ROWS);
}
return rows == null ? null : CommonUtils.toLong(rows); return rows == null ? null : CommonUtils.toLong(rows);
} }
...@@ -184,7 +187,7 @@ public abstract class PostgrePlanNodeBase<NODE extends PostgrePlanNodeBase> exte ...@@ -184,7 +187,7 @@ public abstract class PostgrePlanNodeBase<NODE extends PostgrePlanNodeBase> exte
public String toString() { public String toString() {
StringBuilder title = new StringBuilder(); StringBuilder title = new StringBuilder();
title.append("Type: ").append(nodeType); title.append("Type: ").append(nodeType);
String joinType = attributes.get("Join-Type"); String joinType = attributes.get(ATTR_JOIN_TYPE);
if (!CommonUtils.isEmpty(joinType)) { if (!CommonUtils.isEmpty(joinType)) {
title.append(" (").append(joinType).append(")"); title.append(" (").append(joinType).append(")");
} }
......
...@@ -17,28 +17,271 @@ ...@@ -17,28 +17,271 @@
package org.jkiss.dbeaver.ext.postgresql.model.plan; package org.jkiss.dbeaver.ext.postgresql.model.plan;
import org.jkiss.dbeaver.ext.postgresql.model.PostgreDataSource; import org.jkiss.dbeaver.ext.postgresql.model.PostgreDataSource;
import org.jkiss.utils.xml.XMLUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* Postgre execution plan node * Postgre execution plan node
*/ */
public class PostgrePlanNodeText extends PostgrePlanNodeBase<PostgrePlanNodeText> { public class PostgrePlanNodeText extends PostgrePlanNodeBase<PostgrePlanNodeText> {
private static final String SEPARATOR = " ";
private static final String OPTIONS_SEPARATOR = ":";
private static final Set<String> OPERATION_TABLES = new HashSet<String>(Arrays.asList("Insert", "Update", "Delete", "Seq", "Foreign"));
private static final Set<String> OPERATION_INDEXES = new HashSet<String>(Arrays.asList("Index"));
private static final Set<String> OPERATION_FUNCTION = new HashSet<String>(Arrays.asList("Subquery", "Function"));
public static final String ATTR_ADD_NAME = "Info";
private int infoSeq = 0;
private int indent; private int indent;
public int getIndent() {
return indent;
}
private int getTokenIndex(String tokens[], int start, String marker) {
return getTokenIndex(tokens, start, marker, false);
}
private int getTokenIndex(String tokens[], int start, String marker, boolean caseSensetive) {
if (start < 0 || start >= tokens.length) {
return -1;
}
for (int index = start; index < tokens.length; index++) {
if (caseSensetive) {
if (tokens[index].equals(marker)) {
return index;
}
} else {
if (tokens[index].equalsIgnoreCase(marker)) {
return index;
}
}
}
return -1;
}
private String getTokenAfter(String tokens[], int start, String marker) {
int tokenIndex = getTokenIndex(tokens, start, marker);
if (tokenIndex < 0) {
return null;
}
for (int index = tokenIndex; index < tokens.length; index++) {
if (tokens[index].length() == 0 || tokens[index] == SEPARATOR) {
continue;
}
return ((index + 1) < tokens.length) ? tokens[index+1] : "";
}
return "";
}
private String removePrefix(String value) {
int firstChar = 0;
for(int index =0;index < value.length();index++) {
if(Character.isLetter(value.charAt(index))) {
firstChar = index;
break;
}
}
if (firstChar == (value.length() -1) ) {
return "";
}
return value.substring(firstChar);
}
private String[] splitPair(String value) {
String[] result = new String[] {"",""};
if (value == null) {
return result;
}
String split[] = value.split("\\.\\.");
if (split.length == 0) {
return result;
} else if (split.length == 1) {
result[0] = split[0];
result[1] = null;
} else {
result[0] = split[0];
result[1] = split[1];
}
return result;
}
private String getAdditional(String tokens[]) {
StringBuilder sb = new StringBuilder();
boolean isObjectName = false;
for(int index = 1; index < tokens.length;index++) {
if (tokens[index].equals(SEPARATOR)) {
continue;
}
if (tokens[index].startsWith("(")) {
break;
}
if (isObjectName) {
isObjectName = false;
continue;
}
if (tokens[index].equalsIgnoreCase("on")) {
isObjectName = true;
continue;
}
if (sb.length() > 0) {
sb.append(SEPARATOR);
}
sb.append(tokens[index]);
}
return sb.toString().trim();
}
private void addAttr(Map<String, String> attributes,String attrName1,String attrName2, String attrVal) {
String[] pair = splitPair(attrVal);
attributes.put(attrName1,pair[0]);
attributes.put(attrName2,pair[1]);
}
private void addAttr(Map<String, String> attributes,String attrName, String attrVal) {
attrName = attrName.startsWith("(") ? attrName.substring(1) : attrName;
attrVal = attrVal.endsWith(")") ? attrVal.substring(0,attrVal.length()-1) : attrVal;
switch (attrName) {
case "cost":
addAttr(attributes,PostgrePlanNodeBase.ATTR_STARTUP_COST,PostgrePlanNodeBase.ATTR_TOTAL_COST,attrVal);
break;
case "rows":
addAttr(attributes,PostgrePlanNodeBase.ATTR_PLAN_ROWS,PostgrePlanNodeBase.ATTR_ACTUAL_ROWS,attrVal);
break;
default:
attributes.put(attrName,attrVal);
}
}
private void parseAttr(Map<String, String> attributes, String tokens[]) {
for(String token : tokens) {
int posSep = token.indexOf('=');
if (posSep > 0) {
addAttr(attributes,token.substring(0, posSep),token.substring(posSep+1));
}
}
}
public void addProp(String line) {
int optIdx = line.indexOf(OPTIONS_SEPARATOR);
if (optIdx == -1) {
this.attributes.put("Info " + (++infoSeq), line);
} else {
this.attributes.put( line.substring(0,optIdx).trim(),line.substring(optIdx+1,line.length()).trim());
}
}
public PostgrePlanNodeText(PostgreDataSource dataSource, PostgrePlanNodeText parent, String line, int indent) { public PostgrePlanNodeText(PostgreDataSource dataSource, PostgrePlanNodeText parent, String line, int indent) {
super(dataSource, parent); super(dataSource, parent);
this.indent = indent; this.indent = indent;
Map<String, String> attributes = new LinkedHashMap<>(); Map<String, String> attributes = new LinkedHashMap<>();
String str = removePrefix(line);
String tokens[] = str.split(SEPARATOR);
if (tokens.length > 0) {
String operation = tokens[0];
parseObjName(attributes, tokens, operation);
attributes.put(PostgrePlanNodeBase.ATTR_NODE_TYPE, operation);
String addInfo = getAdditional(tokens);
if (addInfo.length() > 0) {
attributes.put(ATTR_ADD_NAME, addInfo);
}
parseAttr(attributes, tokens);
}
setAttributes(attributes); setAttributes(attributes);
if (parent != null) {
parent.nested.add(this);
}
}
private void parseObjName(Map<String, String> attributes, String[] tokens, String operation) {
String objName = getTokenAfter(tokens, 1, "on");
if (objName != null) {
if (OPERATION_TABLES.contains(operation)) {
attributes.put(PostgrePlanNodeBase.ATTR_RELATION_NAME, objName);
} else if (OPERATION_INDEXES.contains(operation)) {
attributes.put(PostgrePlanNodeBase.ATTR_INDEX_NAME, objName);
} else if (OPERATION_FUNCTION.contains(operation)) {
attributes.put(PostgrePlanNodeBase.ATTR_FUNCTION_NAME, objName);
} else {
attributes.put(PostgrePlanNodeBase.ATTR_OBJECT_NAME, objName);
}
}
} }
} }
...@@ -56,9 +56,9 @@ public class PostgreQueryPlaner extends AbstractExecutionPlanSerializer implemen ...@@ -56,9 +56,9 @@ public class PostgreQueryPlaner extends AbstractExecutionPlanSerializer implemen
@Override @Override
public DBCPlan planQueryExecution(@NotNull DBCSession session, @NotNull String query) throws DBCException { public DBCPlan planQueryExecution(@NotNull DBCSession session, @NotNull String query) throws DBCException {
PostgrePlanAnalyser plan = new PostgrePlanAnalyser( PostgrePlanAnalyser plan = new PostgrePlanAnalyser(
getPlanStyle() == DBCPlanStyle.QUERY, !dataSource.getServerType().supportsExplainPlanXML(),
dataSource.getServerType().supportsExplainPlanVerbose(), dataSource.getServerType().supportsExplainPlanVerbose(),
query); query);
plan.explain(session); plan.explain(session);
return plan; return plan;
} }
...@@ -66,11 +66,11 @@ public class PostgreQueryPlaner extends AbstractExecutionPlanSerializer implemen ...@@ -66,11 +66,11 @@ public class PostgreQueryPlaner extends AbstractExecutionPlanSerializer implemen
@NotNull @NotNull
@Override @Override
public DBCPlanStyle getPlanStyle() { public DBCPlanStyle getPlanStyle() {
return dataSource.getServerType().supportsExplainPlanXML() ? DBCPlanStyle.PLAN : DBCPlanStyle.QUERY; return dataSource.getServerType().supportsExplainPlan() ? DBCPlanStyle.PLAN : DBCPlanStyle.QUERY;
} }
@Override @Override
public void serialize(Writer writer, DBCPlan plan) throws IOException { public void serialize(@NotNull Writer writer, @NotNull DBCPlan plan) throws IOException {
serializeJson(writer, plan, dataSource.getInfo().getDriverName(), new DBCQueryPlannerSerialInfo() { serializeJson(writer, plan, dataSource.getInfo().getDriverName(), new DBCQueryPlannerSerialInfo() {
@Override @Override
...@@ -97,7 +97,7 @@ public class PostgreQueryPlaner extends AbstractExecutionPlanSerializer implemen ...@@ -97,7 +97,7 @@ public class PostgreQueryPlaner extends AbstractExecutionPlanSerializer implemen
} }
@Override @Override
public DBCPlan deserialize(Reader planData) throws IOException, InvocationTargetException { public DBCPlan deserialize(@NotNull Reader planData) throws IOException, InvocationTargetException {
PostgresPlanLoader plan = new PostgresPlanLoader(); PostgresPlanLoader plan = new PostgresPlanLoader();
plan.deserialize(dataSource, planData); plan.deserialize(dataSource, planData);
return plan; return plan;
......
...@@ -76,6 +76,7 @@ public class SQLiteValueHandler extends JDBCAbstractValueHandler { ...@@ -76,6 +76,7 @@ public class SQLiteValueHandler extends JDBCAbstractValueHandler {
return object; return object;
} }
@NotNull
public synchronized String getValueDisplayString(@NotNull DBSTypedObject column, @Nullable Object value, @NotNull DBDDisplayFormat format) public synchronized String getValueDisplayString(@NotNull DBSTypedObject column, @Nullable Object value, @NotNull DBDDisplayFormat format)
{ {
if (value instanceof Number) { if (value instanceof Number) {
......
...@@ -22,6 +22,7 @@ import org.jkiss.code.Nullable; ...@@ -22,6 +22,7 @@ import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
...@@ -69,7 +70,7 @@ public interface DBDDocument extends DBDValue { ...@@ -69,7 +70,7 @@ public interface DBDDocument extends DBDValue {
* @throws DBException * @throws DBException
*/ */
void serializeDocument(@NotNull DBRProgressMonitor monitor, @NotNull OutputStream stream, @Nullable String encoding) void serializeDocument(@NotNull DBRProgressMonitor monitor, @NotNull OutputStream stream, @Nullable String encoding)
throws DBException; throws IOException, DBException;
/** /**
* Updates document from stream * Updates document from stream
...@@ -80,6 +81,6 @@ public interface DBDDocument extends DBDValue { ...@@ -80,6 +81,6 @@ public interface DBDDocument extends DBDValue {
* @throws DBException * @throws DBException
*/ */
void updateDocument(@NotNull DBRProgressMonitor monitor, @NotNull InputStream stream, @Nullable String encoding) void updateDocument(@NotNull DBRProgressMonitor monitor, @NotNull InputStream stream, @Nullable String encoding)
throws DBException; throws IOException, DBException;
} }
\ No newline at end of file
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2019 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.model.impl;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.DBPDataKind;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.struct.DBSObject;
import org.jkiss.dbeaver.model.struct.DBSTypedObject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* SimpleTypedObject
*/
public class SimpleTypedObject implements DBSTypedObject {
public static final SimpleTypedObject DEFAULT_TYPE = new SimpleTypedObject("Object");
private String typeName;
public SimpleTypedObject(String typeName) {
this.typeName = typeName;
}
@Override
public String getTypeName() {
return typeName;
}
@Override
public String getFullTypeName() {
return getTypeName();
}
@Override
public int getTypeID() {
return 0;
}
@Override
public DBPDataKind getDataKind() {
return DBPDataKind.OBJECT;
}
@Override
public Integer getScale() {
return null;
}
@Override
public Integer getPrecision() {
return null;
}
@Override
public long getMaxLength() {
return 0;
}
}
\ No newline at end of file
...@@ -40,7 +40,7 @@ public abstract class BaseValueHandler implements DBDValueHandler { ...@@ -40,7 +40,7 @@ public abstract class BaseValueHandler implements DBDValueHandler {
} }
@Override @Override
public Object createNewValueObject(DBCSession session, DBSTypedObject type) throws DBCException { public Object createNewValueObject(@NotNull DBCSession session, @NotNull DBSTypedObject type) throws DBCException {
throw new DBCException("New '" + type.getTypeName() + "' object create not supported"); throw new DBCException("New '" + type.getTypeName() + "' object create not supported");
} }
......
...@@ -70,7 +70,7 @@ public class JDBCArrayValueHandler extends JDBCComplexValueHandler { ...@@ -70,7 +70,7 @@ public class JDBCArrayValueHandler extends JDBCComplexValueHandler {
} }
@Override @Override
public Object createNewValueObject(DBCSession session, DBSTypedObject type) throws DBCException { public Object createNewValueObject(@NotNull DBCSession session, @NotNull DBSTypedObject type) throws DBCException {
DBSDataType dataType; DBSDataType dataType;
if (type instanceof DBSDataType) { if (type instanceof DBSDataType) {
dataType = (DBSDataType) type; dataType = (DBSDataType) type;
......
...@@ -21,6 +21,7 @@ import org.jkiss.code.Nullable; ...@@ -21,6 +21,7 @@ import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.*; import org.jkiss.dbeaver.model.*;
import org.jkiss.dbeaver.model.data.DBDBinaryFormatter; import org.jkiss.dbeaver.model.data.DBDBinaryFormatter;
import org.jkiss.dbeaver.model.data.DBDDataFilter; import org.jkiss.dbeaver.model.data.DBDDataFilter;
import org.jkiss.dbeaver.model.data.DBDValue;
import org.jkiss.dbeaver.model.impl.data.formatters.BinaryFormatterHexNative; import org.jkiss.dbeaver.model.impl.data.formatters.BinaryFormatterHexNative;
import org.jkiss.dbeaver.model.sql.*; import org.jkiss.dbeaver.model.sql.*;
import org.jkiss.dbeaver.model.sql.parser.SQLSemanticProcessor; import org.jkiss.dbeaver.model.sql.parser.SQLSemanticProcessor;
......
...@@ -22,8 +22,6 @@ import org.eclipse.jface.viewers.ISelection; ...@@ -22,8 +22,6 @@ import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.events.MenuAdapter;
import org.eclipse.swt.events.MenuEvent;
import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Point;
...@@ -41,7 +39,6 @@ import org.jkiss.dbeaver.ui.DBeaverIcons; ...@@ -41,7 +39,6 @@ import org.jkiss.dbeaver.ui.DBeaverIcons;
import org.jkiss.dbeaver.ui.UIIcon; import org.jkiss.dbeaver.ui.UIIcon;
import org.jkiss.dbeaver.ui.UIUtils; import org.jkiss.dbeaver.ui.UIUtils;
import org.jkiss.dbeaver.ui.controls.resultset.*; import org.jkiss.dbeaver.ui.controls.resultset.*;
import org.jkiss.dbeaver.ui.controls.resultset.IResultSetPanel;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.DecimalFormat; import java.text.DecimalFormat;
...@@ -290,7 +287,9 @@ public class AggregateColumnsPanel implements IResultSetPanel { ...@@ -290,7 +287,9 @@ public class AggregateColumnsPanel implements IResultSetPanel {
} else { } else {
strValue = result.toString(); strValue = result.toString();
} }
treeItem.setText(1, strValue); if (strValue != null) {
treeItem.setText(1, strValue);
}
} }
} }
} }
......
...@@ -44,6 +44,7 @@ import org.jkiss.dbeaver.model.exec.DBCException; ...@@ -44,6 +44,7 @@ import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.exec.DBCExecutionContext; import org.jkiss.dbeaver.model.exec.DBCExecutionContext;
import org.jkiss.dbeaver.model.exec.DBCExecutionPurpose; import org.jkiss.dbeaver.model.exec.DBCExecutionPurpose;
import org.jkiss.dbeaver.model.exec.DBCSession; import org.jkiss.dbeaver.model.exec.DBCSession;
import org.jkiss.dbeaver.model.impl.SimpleTypedObject;
import org.jkiss.dbeaver.model.impl.data.DefaultValueHandler; import org.jkiss.dbeaver.model.impl.data.DefaultValueHandler;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.runtime.DBRRunnableWithResult; import org.jkiss.dbeaver.model.runtime.DBRRunnableWithResult;
...@@ -58,6 +59,7 @@ import org.jkiss.dbeaver.ui.UIUtils; ...@@ -58,6 +59,7 @@ import org.jkiss.dbeaver.ui.UIUtils;
import org.jkiss.dbeaver.ui.controls.resultset.ResultSetPreferences; import org.jkiss.dbeaver.ui.controls.resultset.ResultSetPreferences;
import org.jkiss.dbeaver.ui.controls.resultset.ThemeConstants; import org.jkiss.dbeaver.ui.controls.resultset.ThemeConstants;
import org.jkiss.dbeaver.ui.data.*; import org.jkiss.dbeaver.ui.data.*;
import org.jkiss.dbeaver.ui.data.managers.DefaultValueManager;
import org.jkiss.dbeaver.ui.data.registry.ValueManagerRegistry; import org.jkiss.dbeaver.ui.data.registry.ValueManagerRegistry;
import org.jkiss.dbeaver.ui.internal.UIMessages; import org.jkiss.dbeaver.ui.internal.UIMessages;
import org.jkiss.utils.ArrayUtils; import org.jkiss.utils.ArrayUtils;
...@@ -438,9 +440,14 @@ public class ComplexObjectEditor extends TreeViewer { ...@@ -438,9 +440,14 @@ public class ComplexObjectEditor extends TreeViewer {
value = arrayItem.value; value = arrayItem.value;
} else if (this.item instanceof MapEntry) { } else if (this.item instanceof MapEntry) {
valueHandler = DefaultValueHandler.INSTANCE; valueHandler = DefaultValueHandler.INSTANCE;
type = null; type = SimpleTypedObject.DEFAULT_TYPE;
name = ((MapEntry) this.item).name; name = ((MapEntry) this.item).name;
value = ((MapEntry) this.item).value; value = ((MapEntry) this.item).value;
} else if (this.item instanceof CollItem) {
valueHandler = DefaultValueHandler.INSTANCE;
type = SimpleTypedObject.DEFAULT_TYPE;
name = String.valueOf(((CollItem) this.item).index);
value = ((CollItem) this.item).value;
} else { } else {
throw new DBCException("Unsupported complex object element: " + this.item); throw new DBCException("Unsupported complex object element: " + this.item);
} }
...@@ -507,7 +514,7 @@ public class ComplexObjectEditor extends TreeViewer { ...@@ -507,7 +514,7 @@ public class ComplexObjectEditor extends TreeViewer {
public IValueManager getValueManager() { public IValueManager getValueManager() {
DBSTypedObject valueType = getValueType(); DBSTypedObject valueType = getValueType();
if (valueType == null) { if (valueType == null) {
return null; return DefaultValueManager.INSTANCE;
} }
return ValueManagerRegistry.findValueManager( return ValueManagerRegistry.findValueManager(
getExecutionContext().getDataSource(), getExecutionContext().getDataSource(),
......
...@@ -52,7 +52,7 @@ public class StringValueManager extends ContentValueManager { ...@@ -52,7 +52,7 @@ public class StringValueManager extends ContentValueManager {
case INLINE: case INLINE:
// Open inline/panel editor // Open inline/panel editor
Object value = controller.getValue(); Object value = controller.getValue();
if (dataKind == DBPDataKind.STRING || dataKind == DBPDataKind.NUMERIC || dataKind == DBPDataKind.DATETIME || dataKind == DBPDataKind.BOOLEAN) { if (dataKind == DBPDataKind.STRING || dataKind == DBPDataKind.NUMERIC || dataKind == DBPDataKind.DATETIME || dataKind == DBPDataKind.BOOLEAN || dataKind == DBPDataKind.OBJECT) {
return new StringInlineEditor(controller); return new StringInlineEditor(controller);
} else if (value instanceof DBDContentCached && } else if (value instanceof DBDContentCached &&
ContentUtils.isTextValue(((DBDContentCached) value).getCachedValue())) ContentUtils.isTextValue(((DBDContentCached) value).getCachedValue()))
......
...@@ -116,10 +116,10 @@ public class SQLQueryJob extends DataSourceJob ...@@ -116,10 +116,10 @@ public class SQLQueryJob extends DataSourceJob
@NotNull IWorkbenchPartSite partSite, @NotNull IWorkbenchPartSite partSite,
@NotNull String name, @NotNull String name,
@NotNull DBCExecutionContext executionContext, @NotNull DBCExecutionContext executionContext,
@NotNull DBSDataContainer dataContainer, @Nullable DBSDataContainer dataContainer,
@NotNull List<SQLScriptElement> queries, @NotNull List<SQLScriptElement> queries,
@NotNull SQLScriptContext scriptContext, @NotNull SQLScriptContext scriptContext,
@NotNull SQLResultsConsumer resultsConsumer, @Nullable SQLResultsConsumer resultsConsumer,
@Nullable SQLQueryListener listener) @Nullable SQLQueryListener listener)
{ {
super(name, executionContext); super(name, executionContext);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册