/*
* 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.ui.controls.resultset;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.core.DBeaverUI;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.data.DBDAttributeBindingMeta;
import org.jkiss.dbeaver.model.data.DBDDataReceiver;
import org.jkiss.dbeaver.model.exec.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Data pump for SQL queries
*/
class ResultSetDataReceiver implements DBDDataReceiver {
private static final Log log = Log.getLog(ResultSetDataReceiver.class);
private ResultSetViewer resultSetViewer;
private int columnsCount;
private DBDAttributeBindingMeta[] metaColumns;
private List<Object[]> rows = new ArrayList<>();
private boolean hasMoreData;
private boolean nextSegmentRead;
private long offset;
private long maxRows;
// Attribute fetching errors. Collect them to avoid tons of similar error in log
private Map<DBCAttributeMetaData, List<String>> attrErrors = new HashMap<>();
// All (unique) errors happened during fetch
private List<Throwable> errorList = new ArrayList<>();
ResultSetDataReceiver(ResultSetViewer resultSetViewer)
{
this.resultSetViewer = resultSetViewer;
}
boolean isHasMoreData() {
return hasMoreData;
}
void setHasMoreData(boolean hasMoreData) {
this.hasMoreData = hasMoreData;
}
void setNextSegmentRead(boolean nextSegmentRead) {
this.nextSegmentRead = nextSegmentRead;
}
public List<Throwable> getErrorList() {
return errorList;
}
@Override
public void fetchStart(DBCSession session, final DBCResultSet resultSet, long offset, long maxRows)
throws DBCException
{
this.errorList.clear();
this.rows.clear();
this.offset = offset;
this.maxRows = maxRows;
if (!nextSegmentRead) {
// Get columns metadata
DBCResultSetMetaData metaData = resultSet.getMeta();
List<DBCAttributeMetaData> rsAttributes = metaData.getAttributes();
columnsCount = rsAttributes.size();
// Extract column info
metaColumns = new DBDAttributeBindingMeta[columnsCount];
for (int i = 0; i < columnsCount; i++) {
metaColumns[i] = DBUtils.getAttributeBinding(session, rsAttributes.get(i));
}
resultSetViewer.setMetaData(resultSet, metaColumns);
}
}
@Override
public void fetchRow(DBCSession session, DBCResultSet resultSet)
throws DBCException
{
Object[] row = new Object[columnsCount];
for (int i = 0; i < columnsCount; i++) {
try {
row[i] = metaColumns[i].getValueHandler().fetchValueObject(
session,
resultSet,
metaColumns[i].getAttribute(),
metaColumns[i].getOrdinalPosition());
}
catch (Throwable e) {
// Do not reports the same error multiple times
// There are a lot of error could occur during result set fetch
// We report certain error only once
List<String> attrErrors = this.attrErrors.get(metaColumns[i].getMetaAttribute());
if (attrErrors == null) {
attrErrors = new ArrayList<>();
this.attrErrors.put(metaColumns[i].getMetaAttribute(), attrErrors);
}
String errMessage = e.getClass().getName();
if (!errMessage.startsWith("java.lang.")) {
errMessage += ":" + e.getMessage();
}
if (!attrErrors.contains(errMessage)) {
log.warn("Can't read column '" + metaColumns[i].getName() + "' value", e);
attrErrors.add(errMessage);
errorList.add(e);
}
}
}
rows.add(row);
}
@Override
public void fetchEnd(DBCSession session, final DBCResultSet resultSet)
throws DBCException
{
if (!nextSegmentRead) {
try {
// Read locators' metadata
ResultSetUtils.bindAttributes(session, resultSet, metaColumns, rows);
} catch (Throwable e) {
errorList.add(e);
}
}
final List<Object[]> tmpRows = rows;
final boolean nextSegmentRead = this.nextSegmentRead;
DBeaverUI.syncExec(new Runnable() {
@Override
public void run() {
// Push data into viewer
if (!nextSegmentRead) {
resultSetViewer.updatePresentation(resultSet);
resultSetViewer.setData(tmpRows);
resultSetViewer.getActivePresentation().refreshData(true, false, !resultSetViewer.getModel().isMetadataChanged());
} else {
resultSetViewer.appendData(tmpRows);
resultSetViewer.getActivePresentation().refreshData(false, true, false);
}
resultSetViewer.updateStatusMessage();
// Check for more data
hasMoreData = maxRows > 0 && tmpRows.size() >= maxRows;
}
});
}
@Override
public void close()
{
nextSegmentRead = false;
attrErrors.clear();
rows = new ArrayList<>();
}
}