提交 249abe5c 编写于 作者: S serge-rider

#403 JDBC arrays model. Array value binding


Former-commit-id: 53a1b108
上级 7a03aa08
......@@ -20,14 +20,12 @@ package org.jkiss.dbeaver.ext.phoenix.model.data;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.exec.DBCSession;
import org.jkiss.dbeaver.model.exec.DBCStatement;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCPreparedStatement;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCSession;
import org.jkiss.dbeaver.model.impl.jdbc.data.JDBCArray;
import org.jkiss.dbeaver.model.impl.jdbc.data.JDBCCollection;
import org.jkiss.dbeaver.model.impl.jdbc.data.handlers.JDBCArrayValueHandler;
import org.jkiss.dbeaver.model.struct.DBSTypedObject;
import java.lang.reflect.Method;
import java.sql.Array;
import java.sql.SQLException;
......@@ -44,31 +42,9 @@ public class PhoenixArrayValueHandler extends JDBCArrayValueHandler {
public Object getValueFromObject(@NotNull DBCSession session, @NotNull DBSTypedObject type, Object object, boolean copy) throws DBCException
{
if (object != null && object.getClass().getSimpleName().contains(PHOENIX_ARRAY_TYPE)) {
return JDBCArray.makeArray((JDBCSession) session, (Array)object);
return JDBCCollection.makeArray((JDBCSession) session, (Array) object);
}
return super.getValueFromObject(session, type, object, copy);
}
@Override
protected void bindParameter(
JDBCSession session,
JDBCPreparedStatement statement,
DBSTypedObject paramType,
int paramIndex,
Object value)
throws DBCException, SQLException
{
if (value instanceof JDBCArray) {
JDBCArray jdbcArray = (JDBCArray)value;
String elementType = jdbcArray.getComponentType().getTypeName();
Array arrayVal = statement.getConnection().createArrayOf(elementType, (Object [])jdbcArray.getRawValue());
statement.setArray(paramIndex, arrayVal);
} else {
throw new DBCException("Unsupported value type: " + value);
}
}
}
......@@ -25,7 +25,7 @@ import org.jkiss.dbeaver.ext.postgresql.model.PostgreDataType;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.exec.DBCSession;
import org.jkiss.dbeaver.model.impl.jdbc.data.JDBCArray;
import org.jkiss.dbeaver.model.impl.jdbc.data.JDBCCollection;
import org.jkiss.dbeaver.model.impl.jdbc.data.handlers.JDBCArrayValueHandler;
import org.jkiss.dbeaver.model.struct.DBSTypedObject;
......@@ -56,13 +56,13 @@ public class PostgreArrayValueHandler extends JDBCArrayValueHandler {
return convertStringToArray(session, itemType, (String)value);
} else if (itemType != null) {
// Can't parse
return new JDBCArray(itemType, DBUtils.findValueHandler(session, itemType), new Object[] { value } );
return new JDBCCollection(itemType, DBUtils.findValueHandler(session, itemType), new Object[] { value } );
}
}
return super.getValueFromObject(session, type, object, copy);
}
private JDBCArray convertStringToArray(@NotNull DBCSession session, @NotNull PostgreDataType itemType, @NotNull String value) {
private JDBCCollection convertStringToArray(@NotNull DBCSession session, @NotNull PostgreDataType itemType, @NotNull String value) {
List<String> strings = new ArrayList<>(10);
StringTokenizer st = new StringTokenizer(value, " ");
while (st.hasMoreTokens()) {
......@@ -72,7 +72,7 @@ public class PostgreArrayValueHandler extends JDBCArrayValueHandler {
for (int i = 0; i < strings.size(); i++) {
contents[i] = PostgreUtils.convertStringToValue(itemType, strings.get(i), false);
}
return new JDBCArray(itemType, DBUtils.findValueHandler(session, itemType), contents);
return new JDBCCollection(itemType, DBUtils.findValueHandler(session, itemType), contents);
}
}
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2016 Serge Rieder (serge@jkiss.org)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jkiss.dbeaver.model.impl.jdbc.data;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBConstants;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.data.*;
import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.exec.DBCResultSet;
import org.jkiss.dbeaver.model.exec.DBCSession;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCSession;
import org.jkiss.dbeaver.model.impl.jdbc.JDBCArrayImpl;
import org.jkiss.dbeaver.model.impl.jdbc.JDBCStructImpl;
import org.jkiss.dbeaver.model.impl.jdbc.exec.JDBCColumnMetaData;
import org.jkiss.dbeaver.model.impl.jdbc.exec.JDBCResultSetImpl;
import org.jkiss.dbeaver.model.impl.jdbc.struct.JDBCDataType;
import org.jkiss.dbeaver.model.messages.ModelMessages;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.runtime.VoidProgressMonitor;
import org.jkiss.dbeaver.model.sql.SQLConstants;
import org.jkiss.dbeaver.model.sql.SQLUtils;
import org.jkiss.dbeaver.model.struct.DBSDataType;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* Array holder
*/
public class JDBCArray implements DBDCollection, DBDValueCloneable {
private static final Log log = Log.getLog(JDBCArray.class);
private Object[] contents;
private final DBSDataType type;
private final DBDValueHandler valueHandler;
@Nullable
public static Object makeArray(JDBCSession session, Array array) {
if (array == null) {
return null;
}
DBSDataType type = null;
try {
String baseTypeName = array.getBaseTypeName();
type = session.getDataSource().resolveDataType(session.getProgressMonitor(), baseTypeName);
} catch (Exception e) {
log.warn("Error resolving data type", e);
}
try {
if (type == null) {
try {
return extractDataFromResultSet(session, array, null, null);
} catch (SQLException e) {
throw new DBCException(e, session.getDataSource()); //$NON-NLS-1$
}
}
DBDValueHandler valueHandler = DBUtils.findValueHandler(session, type);
try {
return extractDataFromArray(session, array, type, valueHandler);
} catch (SQLException e) {
try {
return extractDataFromResultSet(session, array, type, valueHandler);
} catch (SQLException e1) {
throw new DBCException(e1, session.getDataSource()); //$NON-NLS-1$
}
}
} catch (DBException e) {
log.warn("Can't extract array data from JDBC array", e); //$NON-NLS-1$
return null;
}
}
@Nullable
private static JDBCArray extractDataFromResultSet(JDBCSession session, Array array, @Nullable DBSDataType type, @Nullable DBDValueHandler valueHandler) throws SQLException, DBException {
ResultSet dbResult = array.getResultSet();
if (dbResult == null) {
log.debug("JDBC array type was not resolved and result set was not provided by driver. Return NULL.");
return null;
}
if (type == null || valueHandler == null) {
JDBCColumnMetaData itemMeta = new JDBCColumnMetaData(session.getDataSource(), dbResult.getMetaData(), 1);
if (type == null) {
type = DBUtils.resolveDataType(session.getProgressMonitor(), session.getDataSource(), itemMeta.getTypeName());
if (type == null) {
type = new JDBCDataType(session.getDataSource(), itemMeta);
}
}
valueHandler = DBUtils.findValueHandler(session, itemMeta);
}
try {
try (DBCResultSet resultSet = JDBCResultSetImpl.makeResultSet(session, null, dbResult, ModelMessages.model_jdbc_array_result_set, true)) {
List<Object> data = new ArrayList<>();
while (dbResult.next()) {
// Fetch second column - it contains value
data.add(valueHandler.fetchValueObject(session, resultSet, type, 1));
}
return new JDBCArray(type, valueHandler, data.toArray());
}
} finally {
try {
dbResult.close();
} catch (SQLException e) {
log.debug("Can't close array result set", e); //$NON-NLS-1$
}
}
}
@Nullable
private static JDBCArray extractDataFromArray(JDBCSession session, Array array, DBSDataType type, DBDValueHandler valueHandler) throws SQLException, DBCException {
Object arrObject = array.getArray();
if (arrObject == null) {
return null;
}
int arrLength = java.lang.reflect.Array.getLength(arrObject);
Object[] contents = new Object[arrLength];
for (int i = 0; i < arrLength; i++) {
Object item = java.lang.reflect.Array.get(arrObject, i);
item = valueHandler.getValueFromObject(session, type, item, false);
contents[i] = item;
}
return new JDBCArray(type, valueHandler, contents);
}
public JDBCArray(DBSDataType type, DBDValueHandler valueHandler, @Nullable Object[] contents) {
this.type = type;
this.valueHandler = valueHandler;
this.contents = contents;
}
@NotNull
@Override
public DBSDataType getComponentType() {
return type;
}
@NotNull
@Override
public DBDValueHandler getComponentValueHandler() {
return valueHandler;
}
@Override
public DBDValueCloneable cloneValue(DBRProgressMonitor monitor) {
return new JDBCArray(type, valueHandler, contents);
}
@Override
public Object getRawValue() {
return contents;
}
@Override
public boolean isNull() {
return contents == null;
}
@Override
public void release() {
contents = null;
}
public String toString() {
if (isNull()) {
return DBConstants.NULL_VALUE_LABEL;
} else {
return makeArrayString();
}
}
@NotNull
public String makeArrayString() {
if (isNull()) {
return SQLConstants.NULL_VALUE;
}
if (contents.length == 0) {
return "";
} else if (contents.length == 1) {
return valueHandler.getValueDisplayString(type, contents[0], DBDDisplayFormat.UI);
} else {
StringBuilder str = new StringBuilder(contents.length * 32);
for (Object item : contents) {
if (str.length() > 0) {
str.append(' '); //$NON-NLS-1$
}
String itemString = valueHandler.getValueDisplayString(type, item, DBDDisplayFormat.UI);
SQLUtils.appendValue(str, type, itemString);
}
return str.toString();
}
}
@Override
public int getItemCount() {
return contents == null ? 0 : contents.length;
}
@Override
public Object getItem(int index) {
return contents[index];
}
@Override
public void setItem(int index, Object value) {
contents[index] = value;
}
public Array getArrayValue() throws DBCException {
Object[] attrs = new Object[contents.length];
for (int i = 0; i < contents.length; i++) {
Object attr = contents[i];
if (attr instanceof DBDValue) {
attr = ((DBDValue) attr).getRawValue();
}
attrs[i] = attr;
}
final DBSDataType dataType = getComponentType();
try (DBCSession session = DBUtils.openUtilSession(VoidProgressMonitor.INSTANCE, dataType.getDataSource(), "Create JDBC array")) {
if (session instanceof Connection) {
return ((Connection) session).createArrayOf(dataType.getTypeName(), attrs);
} else {
return new JDBCArrayImpl(dataType.getTypeName(), dataType.getTypeID(), attrs);
}
} catch (Throwable e) {
throw new DBCException("Error creating struct", e);
}
}
}
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2016 Serge Rieder (serge@jkiss.org)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jkiss.dbeaver.model.impl.jdbc.data;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBConstants;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.data.*;
import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.exec.DBCResultSet;
import org.jkiss.dbeaver.model.exec.DBCSession;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCSession;
import org.jkiss.dbeaver.model.impl.jdbc.JDBCArrayImpl;
import org.jkiss.dbeaver.model.impl.jdbc.exec.JDBCColumnMetaData;
import org.jkiss.dbeaver.model.impl.jdbc.exec.JDBCResultSetImpl;
import org.jkiss.dbeaver.model.impl.jdbc.struct.JDBCDataType;
import org.jkiss.dbeaver.model.messages.ModelMessages;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.runtime.VoidProgressMonitor;
import org.jkiss.dbeaver.model.sql.SQLConstants;
import org.jkiss.dbeaver.model.sql.SQLUtils;
import org.jkiss.dbeaver.model.struct.DBSDataType;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* Array holder
*/
public class JDBCCollection implements DBDCollection, DBDValueCloneable {
private static final Log log = Log.getLog(JDBCCollection.class);
private Object[] contents;
private final DBSDataType type;
private final DBDValueHandler valueHandler;
@Nullable
public static Object makeArray(JDBCSession session, Array array) {
if (array == null) {
return null;
}
DBSDataType type = null;
try {
String baseTypeName = array.getBaseTypeName();
type = session.getDataSource().resolveDataType(session.getProgressMonitor(), baseTypeName);
} catch (Exception e) {
log.warn("Error resolving data type", e);
}
try {
if (type == null) {
try {
return extractDataFromResultSet(session, array, null, null);
} catch (SQLException e) {
throw new DBCException(e, session.getDataSource()); //$NON-NLS-1$
}
}
DBDValueHandler valueHandler = DBUtils.findValueHandler(session, type);
try {
return extractDataFromArray(session, array, type, valueHandler);
} catch (SQLException e) {
try {
return extractDataFromResultSet(session, array, type, valueHandler);
} catch (SQLException e1) {
throw new DBCException(e1, session.getDataSource()); //$NON-NLS-1$
}
}
} catch (DBException e) {
log.warn("Can't extract array data from JDBC array", e); //$NON-NLS-1$
return null;
}
}
@Nullable
private static JDBCCollection extractDataFromResultSet(JDBCSession session, Array array, @Nullable DBSDataType type, @Nullable DBDValueHandler valueHandler) throws SQLException, DBException {
ResultSet dbResult = array.getResultSet();
if (dbResult == null) {
log.debug("JDBC array type was not resolved and result set was not provided by driver. Return NULL.");
return null;
}
if (type == null || valueHandler == null) {
JDBCColumnMetaData itemMeta = new JDBCColumnMetaData(session.getDataSource(), dbResult.getMetaData(), 1);
if (type == null) {
type = DBUtils.resolveDataType(session.getProgressMonitor(), session.getDataSource(), itemMeta.getTypeName());
if (type == null) {
type = new JDBCDataType(session.getDataSource(), itemMeta);
}
}
valueHandler = DBUtils.findValueHandler(session, itemMeta);
}
try {
try (DBCResultSet resultSet = JDBCResultSetImpl.makeResultSet(session, null, dbResult, ModelMessages.model_jdbc_array_result_set, true)) {
List<Object> data = new ArrayList<>();
while (dbResult.next()) {
// Fetch second column - it contains value
data.add(valueHandler.fetchValueObject(session, resultSet, type, 1));
}
return new JDBCCollection(type, valueHandler, data.toArray());
}
} finally {
try {
dbResult.close();
} catch (SQLException e) {
log.debug("Can't close array result set", e); //$NON-NLS-1$
}
}
}
@Nullable
private static JDBCCollection extractDataFromArray(JDBCSession session, Array array, DBSDataType type, DBDValueHandler valueHandler) throws SQLException, DBCException {
Object arrObject = array.getArray();
if (arrObject == null) {
return null;
}
int arrLength = java.lang.reflect.Array.getLength(arrObject);
Object[] contents = new Object[arrLength];
for (int i = 0; i < arrLength; i++) {
Object item = java.lang.reflect.Array.get(arrObject, i);
item = valueHandler.getValueFromObject(session, type, item, false);
contents[i] = item;
}
return new JDBCCollection(type, valueHandler, contents);
}
public JDBCCollection(DBSDataType type, DBDValueHandler valueHandler, @Nullable Object[] contents) {
this.type = type;
this.valueHandler = valueHandler;
this.contents = contents;
}
@NotNull
@Override
public DBSDataType getComponentType() {
return type;
}
@NotNull
@Override
public DBDValueHandler getComponentValueHandler() {
return valueHandler;
}
@Override
public DBDValueCloneable cloneValue(DBRProgressMonitor monitor) {
return new JDBCCollection(type, valueHandler, contents);
}
@Override
public Object getRawValue() {
return contents;
}
@Override
public boolean isNull() {
return contents == null;
}
@Override
public void release() {
contents = null;
}
public String toString() {
if (isNull()) {
return DBConstants.NULL_VALUE_LABEL;
} else {
return makeArrayString();
}
}
@NotNull
public String makeArrayString() {
if (isNull()) {
return SQLConstants.NULL_VALUE;
}
if (contents.length == 0) {
return "";
} else if (contents.length == 1) {
return valueHandler.getValueDisplayString(type, contents[0], DBDDisplayFormat.UI);
} else {
StringBuilder str = new StringBuilder(contents.length * 32);
for (Object item : contents) {
if (str.length() > 0) {
str.append(' '); //$NON-NLS-1$
}
String itemString = valueHandler.getValueDisplayString(type, item, DBDDisplayFormat.UI);
SQLUtils.appendValue(str, type, itemString);
}
return str.toString();
}
}
@Override
public int getItemCount() {
return contents == null ? 0 : contents.length;
}
@Override
public Object getItem(int index) {
return contents[index];
}
@Override
public void setItem(int index, Object value) {
contents[index] = value;
}
public Array getArrayValue() throws DBCException {
Object[] attrs = new Object[contents.length];
for (int i = 0; i < contents.length; i++) {
Object attr = contents[i];
if (attr instanceof DBDValue) {
attr = ((DBDValue) attr).getRawValue();
}
attrs[i] = attr;
}
final DBSDataType dataType = getComponentType();
try (DBCSession session = DBUtils.openUtilSession(VoidProgressMonitor.INSTANCE, dataType.getDataSource(), "Create JDBC array")) {
if (session instanceof Connection) {
return ((Connection) session).createArrayOf(dataType.getTypeName(), attrs);
} else {
return new JDBCArrayImpl(dataType.getTypeName(), dataType.getTypeID(), attrs);
}
} catch (Throwable e) {
throw new DBCException("Error creating struct", e);
}
}
}
......@@ -18,15 +18,19 @@
package org.jkiss.dbeaver.model.impl.jdbc.data.handlers;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.model.data.DBDCollection;
import org.jkiss.dbeaver.model.data.DBDDisplayFormat;
import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.exec.DBCSession;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCPreparedStatement;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCSession;
import org.jkiss.dbeaver.model.impl.jdbc.data.JDBCArray;
import org.jkiss.dbeaver.model.impl.jdbc.data.JDBCCollection;
import org.jkiss.dbeaver.model.messages.ModelMessages;
import org.jkiss.dbeaver.model.struct.DBSTypedObject;
import java.sql.Array;
import java.sql.SQLException;
import java.sql.Types;
/**
* JDBC Array value handler.
......@@ -40,20 +44,20 @@ public class JDBCArrayValueHandler extends JDBCComplexValueHandler {
@NotNull
@Override
public Class<JDBCArray> getValueObjectType(@NotNull DBSTypedObject attribute)
public Class<JDBCCollection> getValueObjectType(@NotNull DBSTypedObject attribute)
{
return JDBCArray.class;
return JDBCCollection.class;
}
@Override
public Object getValueFromObject(@NotNull DBCSession session, @NotNull DBSTypedObject type, Object object, boolean copy) throws DBCException
{
if (object == null) {
return JDBCArray.makeArray((JDBCSession) session, null);
} else if (object instanceof JDBCArray) {
return copy ? ((JDBCArray) object).cloneValue(session.getProgressMonitor()) : object;
return JDBCCollection.makeArray((JDBCSession) session, null);
} else if (object instanceof JDBCCollection) {
return copy ? ((JDBCCollection) object).cloneValue(session.getProgressMonitor()) : object;
} else if (object instanceof Array) {
return JDBCArray.makeArray((JDBCSession) session, (Array)object);
return JDBCCollection.makeArray((JDBCSession) session, (Array) object);
} else {
throw new DBCException(ModelMessages.model_jdbc_exception_unsupported_array_type_ + object.getClass().getName());
}
......@@ -63,11 +67,35 @@ public class JDBCArrayValueHandler extends JDBCComplexValueHandler {
@Override
public String getValueDisplayString(@NotNull DBSTypedObject column, Object value, @NotNull DBDDisplayFormat format)
{
if (value instanceof JDBCArray) {
return ((JDBCArray) value).makeArrayString();
if (value instanceof JDBCCollection) {
return ((JDBCCollection) value).makeArrayString();
}
return super.getValueDisplayString(column, value, format);
}
@Override
protected void bindParameter(
JDBCSession session,
JDBCPreparedStatement statement,
DBSTypedObject paramType,
int paramIndex,
Object value)
throws DBCException, SQLException
{
if (value == null) {
statement.setNull(paramIndex, Types.ARRAY);
} else if (value instanceof DBDCollection) {
DBDCollection collection = (DBDCollection) value;
if (collection.isNull()) {
statement.setNull(paramIndex, Types.ARRAY);
} else if (collection instanceof JDBCCollection) {
statement.setObject(paramIndex, ((JDBCCollection) collection).getArrayValue(), Types.ARRAY);
} else {
statement.setObject(paramIndex, collection.getRawValue());
}
} else {
throw new DBCException("Array parameter type '" + value.getClass().getName() + "' not supported");
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册