package org.fnppl.dbaccess;
import java.sql.*;
import java.util.*;
/*
* Copyright (C) 2010-2015
* fine people e.V. <opensdx@fnppl.org>
* Henning Thieß <ht@fnppl.org>
*
* http://fnppl.org
*/
/*
* Software license
*
* As far as this file or parts of this file is/are software, rather than documentation, this software-license applies / shall be applied.
*
* This file is part of openSDX
* openSDX 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 3 of the License, or
* (at your option) any later version.
*
* openSDX 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 Lesser General Public License
* and GNU General Public License along with openSDX.
* If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Documentation license
*
* As far as this file or parts of this file is/are documentation, rather than software, this documentation-license applies / shall be applied.
*
* This file is part of openSDX.
* Permission is granted to copy, distribute and/or modify this document
* under the terms of the GNU Free Documentation License, Version 1.3
* or any later version published by the Free Software Foundation;
* with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
* A copy of the license is included in the section entitled "GNU
* Free Documentation License" resp. in the file called "FDL.txt".
*
*/
//wrapper around a fully-fetched database-resultset
public class DBResultSet implements java.io.Serializable, Cloneable {
static final long serialVersionUID = 6;
private String errortext = null;
private Vector<String> columnNames = new Vector<String>();//columname, columnlabel
private Vector<String> columnLabels = new Vector<String>();//columname, columnlabel
private String[][] data;
private ColumnNameMappings
colNameMappings = DUMMY_MAPPINGS,
qualifiedMappings = DUMMY_MAPPINGS
;
private int width=-1;
private int height=-1;
@Override
public Object clone() {
System.out.println("DBRESULTSET::clone");
try {
DBResultSet ret = (DBResultSet) super.clone();
ret.data = data.clone();
return ret;
}
catch (CloneNotSupportedException x){
throw new InternalError(x.toString());
}
}
public DBResultSet(Statement Stmt, String sql) {
Object[] key = new Object[]{sql,new Long(System.currentTimeMillis())};
try {
// if(DBStatement.statme) {
// DBStatement.currentexecs.add(key);
// }
ResultSet rs = Stmt.executeQuery(sql);
// if(DBStatement.statme) {
// DBStatement.currentexecs.remove(key);
// }
//Stmt.setFetchSize(rs.getMetaData().
fetch(rs);
// System.err.println("rs.closing");
rs.close();
// System.err.println("rs.closed");
// Stmt.close();
}
catch (SQLException E) {
java.util.Date d = new java.util.Date();
this.errortext = "SQLException ["+d+"]: \n\t" + E.getMessage()+"\n\tSQLState: " + E.getSQLState()+"\n\tVendorError: " + E.getErrorCode() ;
// if(DBStatement.statme) {
// DBStatement.currentexecs.remove(key);
// }
}
}
public DBResultSet(ResultSet rs) {
try{
fetch( rs );
}
catch (SQLException E){
java.util.Date d = new java.util.Date();
this.errortext = "SQLException ["+d+"]: \n\t" + E.getMessage()+"\n\tSQLState: " + E.getSQLState()+"\n\tVendorError: " + E.getErrorCode() ;
}
}
// private DBResultSet() {}
private void fetch(ResultSet rs) throws SQLException {
if( rs == null )
return ;
// System.err.println("going to fetch...");
ResultSetMetaData meta = rs.getMetaData();
// System.err.println("going to fetch 1...");
int widthcache = meta.getColumnCount();
// System.err.println("going to fetch 2...");
columnNames.clear(); // = new String[ widthcache ];
columnLabels.clear(); // = new String[ widthcache ];
Vector<String> qualified = new Vector<String>();
//[ widthcache ];
// for(int xx=0, nn = columnNames.size(); xx < nn; xx++){
for(int xx=0; xx<widthcache; xx++){
columnNames.addElement(meta.getColumnName(xx+1)); //
columnLabels.addElement(meta.getColumnLabel(xx+1)); //
// columnLabels[xx] = meta.getColumnLabel(xx+1); //columnnames 1 basiert.-
// qualified[xx] = meta.getTableName(xx+1) + "." + columnNames.lastElement();
qualified.addElement(meta.getTableName(xx+1) + "." + columnNames.lastElement());
}
//4:
colNameMappings = new ColumnNameMappings(columnNames);
qualifiedMappings = new ColumnNameMappings(qualified);
// System.err.println("going to fetch 3...");
List l = new LinkedList();
String[] row;
for(; rs.next(); ){
row = new String[ widthcache ];
for(int xx=0; xx < widthcache; xx++){
row[xx] = rs.getString(xx+1); //ALLE indices 1 basiert ?!-
}
l.add(row);
}
data = (String[][]) l.toArray(new String[ height = l.size() ][]);
width = widthcache;
// System.err.println("going to fetch 4...");
}
//4:
@Override
protected void finalize() throws Throwable {
data = null;
//4:
columnNames = null;
colNameMappings = null;
super.finalize();
}
public String gimmeNameAt(int index) {
if(index >= 0 && index < width) {
return columnNames.elementAt(index);
//[index] ;
}
return null;
}
public String gimmeLabelAt(int index) {
if(index >= 0 && index < width) {
return columnLabels.elementAt(index);
//[index] ;
}
return null;
}
public static String[] vtoa(Vector<String> v) {
String[] a = new String[v.size()];
for(int i=0;i<a.length;i++) {
a[i] = v.elementAt(i);
}
return a;
}
public Vector<String> gimmeColNames() {
return (Vector<String>)columnNames.clone();
}
public Vector<String> gimmeColLabels() {
return (Vector<String>)columnLabels.clone();
}
public Vector<String> gimmeColNamesRef(){
return columnNames;
}
public int gimmeIndexOf(String name) {
return colNameMappings.getColumnIndex(name);
}
public int gimmeQualifiedIndexOf(String table, String column){
return qualifiedMappings.getColumnIndex(table+"."+column);
}
public String[] getColumnData(int columnIndex){
if( columnIndex < 0 || columnIndex >= width ){
throw new IndexOutOfBoundsException("columnIndex out of bounds: "+columnIndex);
}
String ret[] = new String[ height() ];
for(int xx=0; xx < ret.length; xx++){
ret[xx] = data[xx][columnIndex];
}
return ret;
}
public String[] getColumnData(String colname){
try{
return getColumnData( gimmeIndexOf(colname) );
}
catch (IndexOutOfBoundsException x){
throw new IllegalArgumentException("Column does not exist: "+colname);
}
}
public String[] getRowData(int rowIndex){
if( rowIndex < 0 || rowIndex >= height ){
throw new IndexOutOfBoundsException("rowIndex out of bounds: "+rowIndex);
}
return data[ rowIndex ]; //kein kopiern. Scheiss drauf.
}
public String getValueAt(int rowIndex, int columnIndex) {
if( rowIndex < 0 || rowIndex >= height() )
// throw new IndexOutOfBoundsException("rowIndex out of bounds: "+rowIndex);
return null;
if( columnIndex < 0 || columnIndex >= width() )
// throw new IndexOutOfBoundsException("columnIndex out of bounds: "+columnIndex);
return null;
return data[rowIndex][columnIndex];
}
public String getValueOf(int row, String columnname) {
int index = gimmeIndexOf(columnname);
return index >= 0 ? getValueAt(row, index) : null;
}
public String getValueOf(int row, String table, String column){
int index = gimmeQualifiedIndexOf(table, column);
return index >= 0 ? getValueAt(row, index) : null;
}
public long getLongOf(int i, String columname) {
try {
return Long.parseLong(getValueOf(i, columname));
} catch (Exception e) {
// TODO: handle exception
}
return -1;
}
public long getLongAt(int row, int column) {
try {
return Long.parseLong(getValueAt(row, column));
} catch (Exception e) {
// TODO: handle exception
}
return -1;
}
public int getIntOf(int i, String columname) {
try {
return Integer.parseInt(getValueOf(i, columname));
} catch (Exception e) {
// TODO: handle exception
}
return -1;
}
public int getIntAt(int row, int column) {
try {
return Integer.parseInt(getValueAt(row, column));
} catch (Exception e) {
// TODO: handle exception
}
return -1;
}
public boolean getBooleanOf(int i, String columname) {
try {
return getValueOf(i, columname).indexOf("t")==0;
} catch (Exception e) {
// TODO: handle exception
}
return false;
}
public boolean getBooleanAt(int row, int column) {
try {
return getValueAt(row, column).indexOf("t")==0;
} catch (Exception e) {
// TODO: handle exception
}
return false;
}
public int width() {
return this.width ;
}
public int height() {
return this.height;
}
public boolean errorOccured() {
if(errortext==null)
return false;
else
return true;
}
public String gimmeErrorText() {
return this.errortext;
}
public void reset() {
// data = new String[0][];
// columnNames = new String[0];
// colNameMappings = null;
// width = height = 0;
}
public void closeRS() { }
// ICH WILL POSTGRES 8.0 !
public synchronized void addColumn(String name){
String[] niounames = new String[ width + 1 ];
for(int i=0;i<columnNames.size();i++){
niounames[i] = columnNames.elementAt(i);
}
// System.arraycopy(columnNames, 0, niounames, 0, width);
niounames[width] = name;
String[][] rev = (String[][]) reverseArray(data, width, height);
String[][] nioudata = new String[ width + 1 ][];
System.arraycopy(rev, 0, nioudata, 0, width); //hier kopiere ich Spalten
nioudata[width] = new String[ height ];
Arrays.fill(nioudata[width], "");
nioudata = (String[][]) reverseArray(nioudata, height, width+1);
columnNames.clear();
for(int i=0; i<niounames.length; i++) {
columnNames.addElement(niounames[i]);
}
columnLabels.addElement(name);
colNameMappings = new ColumnNameMappings(columnNames);
data = nioudata;
width++;
}
// public static Object[][] addColumn(Object[][] array, int width, int height){
//
// Object[][] rev = reverseArray(array, width, height);
//
// Object[][] nioudata = new Object[ width + 1 ][];
// System.arraycopy(rev, 0, nioudata, 0, width);
// nioudata[width] = new Object[ height ];
//
// nioudata = reverseArray(nioudata, height, ++width);
//
// width++;
// return nioudata;
// }
public synchronized void removeRow(int rowIndex){
if(rowIndex < 0 || rowIndex >= height())
throw new IndexOutOfBoundsException();
//hier nur einmal verschieben...
System.arraycopy(data, rowIndex+1, data, rowIndex, data.length-rowIndex-1);
height--;
}
public synchronized void setValueAt(int rowindex, int columnindex, String value){
if(rowindex < 0 || rowindex >= height() )
throw new IndexOutOfBoundsException("Row index out of bounds: "+rowindex);
if( columnindex < 0 || columnindex >= width())
throw new IndexOutOfBoundsException("Column index out of bounds: "+rowindex);
data[rowindex][columnindex] = encode(value);
}
public synchronized void addRow(){
String[][] no = new String[height+1][width];
//hier nur einmal verschieben...
System.arraycopy(data, 0, no, 0, data.length);
String[] col= new String[width];
Arrays.fill(col, "");
no[height] = col;
data = no;
height++;
}
public synchronized void setValueOf(int rowindex, String column, String value){
setValueAt(rowindex, gimmeIndexOf(column), value);
}
public String encode(String s) {
//�berf�hrt einen string in einen html-string
if(s==null) return "";
return s;
}
public String[] toArray(int col) {
int h = height();
if(h < 0) {
h = 0;
}
String[] ret = new String[h];
for(int i=0;i<ret.length;i++) {
ret[i] = getValueAt(i, col);
}
return ret;
}
public void addResultSet(DBResultSet Rs, int offsetRow, int rowCount) throws Exception {
if(Rs.width() != width()) {
throw new Exception("WIDTHs does not match: "+Rs.width()+"!="+width());
}
String[][] no = new String[height + (rowCount>Rs.height() ? Rs.height() : rowCount)][width];
//hier nur einmal verschieben...
System.arraycopy(data, 0, no, 0, data.length);
for(int i=0;i<Rs.height && i<rowCount; i++) {
no[i+height] = Rs.getRowData(i + offsetRow);
}
data = no;
height = height + Rs.height();
}
public String[] toArray(String colname) {
int col = gimmeIndexOf(colname);
return toArray(col);
}
private static Object[][] reverseArray(Object[][] array, int width, int height){
if( width == height ){
reverseArray0(array, array, width, height);
return array;
}
String[][] rev = new String[width][];
for(int jj=0; jj < rev.length; jj++) rev[jj] = new String[height];
reverseArray0(array, rev, width, height);
return rev;
}
//TODO optimizien über zweistufige HASHTABLE HT 26.10.2007
public int getLineOfValue(String value, String colname) {
int col = gimmeIndexOf(colname);
return getLineOfValue(value,col);
}
public int getLineOfValue(String value, int col) {
for(int i=0;i<height();i++) {
String s = getValueAt(i, col);
if(s.equals(value)) {
return i;
}
}
return -1;
}
private static void reverseArray0(Object[][] array, Object[][] output, int width, int height){
if( array == output ){
Object tmp;
for(int xx=0; xx < width; xx++){
for(int yy=xx; yy < height; yy++){
tmp = array[xx][yy];
array[xx][yy] = array[yy][xx];
array[yy][xx] = tmp;
}
}
}
else {
for(int xx=0; xx < width; xx++){
for(int yy=0; yy < height; yy++){
output[xx][yy] = array[yy][xx];
}
}
}
}
public void distinctMe(String columname) {
HashSet vs = new HashSet();
Vector dels = new Vector();
for(int i=0;i<height();i++) {
String v = ""+getValueOf(i, columname);
if(vs.contains(v)) {
dels.addElement(new Integer(i));
}
else {
vs.add(v);
}
}
for(int i=dels.size()-1;i>=0;i--) {
Integer ii = (Integer)dels.elementAt(i);
removeRow(ii.intValue());
}
}
//4:
private static class ColumnNameMappings
implements java.io.Serializable, Cloneable
{
String[] sortedNames;
int[] indices;
public ColumnNameMappings(Vector<String> colnames){
sortedNames = colnames.toArray(new String[]{});
Arrays.sort(sortedNames);
indices = new int[ colnames.size()];
for(int ii = colnames.size() - 1; ii >= 0; ii--){
int index = index0(colnames.elementAt(ii));
indices[index] = ii;
}
}
private int index0(String name){
return name == null ? -1 : Arrays.binarySearch(sortedNames, name);
}
public int getColumnIndex(String colname){
int index = index0(colname);
return index >= 0 ? indices[index] : -1;
}
@Override
public Object clone(){
try{
ColumnNameMappings clone = (ColumnNameMappings) super.clone();
clone.sortedNames = sortedNames.clone();
clone.indices = indices.clone();
return clone;
}
catch (CloneNotSupportedException x){
throw new InternalError(x.toString());
}
}
static final long serialVersionUID = 2;
}
private static final ColumnNameMappings
DUMMY_MAPPINGS = new ColumnNameMappings(new Vector<String>()) {
@Override
public int getColumnIndex(String s){
return -1;
}
}
;
public static class SQLResult {
public int affected = -1;
public boolean error_occured = false;
public String error_text = null;
public Exception ex = null;
}
}