/*
* Copyright (C) 2008-2015 by Holger Arndt
*
* This file is part of the Universal Java Matrix Package (UJMP).
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership and licensing.
*
* UJMP is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* UJMP 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with UJMP; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package org.ujmp.jdbc.matrix;
import java.io.Closeable;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Map;
import org.ujmp.core.collections.map.SoftHashMap;
import org.ujmp.core.objectmatrix.DenseObjectMatrix2D;
import org.ujmp.core.objectmatrix.stub.AbstractDenseObjectMatrix2D;
import org.ujmp.jdbc.autoclose.AutoCloseConnection;
public abstract class AbstractDenseJDBCMatrix2D extends AbstractDenseObjectMatrix2D implements Closeable {
private static final long serialVersionUID = -9077208839474846706L;
private int chunkSize = 1000;
private Map<Long, DenseObjectMatrix2D> dataCache = new SoftHashMap<Long, DenseObjectMatrix2D>();
private String url = null;
private String username = null;
private String password = null;
private String sqlStatement = null;
private Connection connection = null;
public AbstractDenseJDBCMatrix2D(String url, String sqlStatement, String username, String password) {
super(0, 0);
this.url = url;
this.username = username;
this.password = password;
this.sqlStatement = sqlStatement;
}
public AbstractDenseJDBCMatrix2D(Connection connection, String sqlStatement) {
super(0, 0);
this.connection = connection;
this.sqlStatement = sqlStatement;
}
public String getSQLStatement() {
return sqlStatement;
}
public synchronized Object getObject(int row, int column) {
return getObject((long) row, (long) column);
}
public synchronized Object getObject(long row, long column) {
try {
long chunkId = row / chunkSize;
DenseObjectMatrix2D m = dataCache.get(chunkId);
if (m == null) {
String sql = sqlStatement + " LIMIT ?,?";
PreparedStatement ps = getConnection().prepareStatement(sql);
System.out.println(row + " - " + chunkId);
long offset = chunkId * chunkSize;
ps.setLong(1, offset);
ps.setLong(2, chunkSize);
ResultSet rs = ps.executeQuery();
m = DenseObjectMatrix2D.Factory.zeros(chunkSize, getColumnCount());
long r = 0;
while (rs.next()) {
for (int c = 0; c < getColumnCount(); c++) {
try {
m.setObject(rs.getObject(c + 1), r, c);
} catch (SQLException e) {
if ("S1009".equals(e.getSQLState())) {
// ignore Value '0000-00-00' can not be
// represented
} else {
throw e;
}
}
}
r++;
}
dataCache.put(chunkId, m);
rs.close();
ps.close();
}
return m.getObject(row % chunkSize, column);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public final String getSelectString() {
return sqlStatement;
}
public synchronized void setObject(Object value, long row, long column) {
}
public synchronized void setObject(Object value, int row, int column) {
}
public synchronized long[] getSize() {
try {
if (getRowCount() == 0) {
long rowCount = 0;
PreparedStatement ps = getConnection()
.prepareStatement("SELECT COUNT(1) FROM (" + sqlStatement + ") t");
ResultSet rsRows = ps.executeQuery();
if (rsRows.next()) {
rowCount = rsRows.getLong(1);
}
rsRows.close();
ps.close();
long columnCount = 0;
ps = getConnection().prepareStatement("SELECT * FROM (" + sqlStatement + ") t LIMIT 1");
ResultSet rsCols = ps.executeQuery();
if (rsCols.next()) {
columnCount = rsCols.getMetaData().getColumnCount();
}
if (getLabelObject() == null) {
setLabel(getUrl() + " " + getSelectString());
ResultSetMetaData rsm = rsCols.getMetaData();
for (int c = 0; c < rsm.getColumnCount(); c++) {
setColumnLabel(c, rsm.getColumnLabel(c + 1));
}
}
rsCols.close();
ps.close();
size[ROW] = rowCount;
size[COLUMN] = columnCount;
}
return size;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public synchronized void close() throws IOException {
try {
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
throw new IOException(e.toString());
}
}
public synchronized Connection getConnection() throws SQLException {
if (connection == null) {
connection = new AutoCloseConnection(DriverManager.getConnection(getUrl(), getUsername(), getPassword()));
}
return connection;
}
public String getUrl() {
return url;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}