//{HEADER
/**
* This class is part of jnex 'Nexirius Application Framework for Java'
*
* Copyright (C) Nexirius GmbH, CH-4450 Sissach, Switzerland (www.nexirius.ch)
*
* <p>This library is free software; you can redistribute it and/or<br>
* modify it under the terms of the GNU Lesser General Public<br>
* License as published by the Free Software Foundation; either<br>
* version 2.1 of the License, or (at your option) any later version.</p>
*
* <p>This library is distributed in the hope that it will be useful,<br>
* but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU<br>
* Lesser General Public License for more details.</p>
*
* <p>You should have received a copy of the GNU Lesser General Public<br>
* License along with this library; if not, write to the Free Software<br>
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA</p>
* </blockquote>
*
* <p>
* Nexirius GmbH, hereby disclaims all copyright interest in<br>
* the library jnex' 'Nexirius Application Framework for Java' written<br>
* by Marcel Baumann.</p>
*/
//}HEADER
package com.nexirius.framework.jdbc;
import com.nexirius.framework.application.ErrorMessageException;
import com.nexirius.util.SortedVector;
import com.nexirius.util.Sorter;
import java.sql.*;
import java.util.Iterator;
public class JnexPreparedStatement {
public static final int TYPE_OBJECT = Types.JAVA_OBJECT;
public static final int TYPE_DATE = Types.DATE;
public static final int TYPE_DOUBLE = Types.DOUBLE;
public static final int TYPE_INT = Types.INTEGER;
public static final int TYPE_LONG = Types.BIGINT;
public static final int TYPE_STRING = Types.VARCHAR;
public static final int TYPE_TIMESTAMP = Types.TIMESTAMP;
public static class STOREDPROCEDURETYPE {
public static STOREDPROCEDURETYPE INSERT = new STOREDPROCEDURETYPE("INSERT");
public static STOREDPROCEDURETYPE UPDATE = new STOREDPROCEDURETYPE("UPDATE");
public static STOREDPROCEDURETYPE DELETE = new STOREDPROCEDURETYPE("DELETE");
public static STOREDPROCEDURETYPE SELECT = new STOREDPROCEDURETYPE("SELECT");
private String code;
private STOREDPROCEDURETYPE(String code) {
this.code = code;
}
public boolean equals(Object obj) {
if (obj instanceof STOREDPROCEDURETYPE) {
return code.equals(((STOREDPROCEDURETYPE)obj).code);
}
return false;
}
public String toString() {
return this.code.toString();
}
}
private static boolean debug = System.getProperty("debug") != null ? System.getProperty("debug").equalsIgnoreCase("true") : false;
private static int counter = 0;
private static ParameterSorter parameterSorter = new ParameterSorter();
PreparedStatement preparedStatement;
String sql;
SortedVector parameters = null;
protected DatabaseTableMapping mapping;
private boolean readOnly;
private boolean lastStatementResult = false;
public JnexPreparedStatement(DatabaseTableMapping mapping, String sql, boolean readOnly) throws SQLException {
this.mapping = mapping;
this.sql = sql;
this.readOnly = readOnly;
}
// public JnexPreparedStatement(PreparedStatement preparedStatement, String sql) {
// this.preparedStatement = preparedStatement;
// this.sql = sql;
// }
public PreparedStatement getPreparedStatement() {
return preparedStatement;
}
public void execute() {
execute(false);
}
public void executeQuery() {
execute(true);
}
private void execute(boolean query) {
int retry = 5;
do {
try {
initPreparedStatement();
assignParameters();
if (query) {
preparedStatement.executeQuery();
} else {
lastStatementResult = preparedStatement.execute();
}
if (debug) {
System.out.println("debug=true: " + ++counter + ") " + toString());
}
parameters = null;
return;
} catch (SQLException sqlEx) {
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (Throwable e) {
e.printStackTrace();
}
preparedStatement = null;
}
String sqlState = sqlEx.getSQLState();
if ("08S01".equals(sqlState) || "40001".equals(sqlState)) {
if (debug) {
System.out.println("try to re-establish connection retry=" + retry);
}
retry--;
} else {
retry = 0;
}
if (retry <= 0) {
String message = toString();
parameters = null;
throw new ErrorMessageException(message, sqlEx, null);
}
}
}
while (retry > 0);
}
protected void initPreparedStatement() throws SQLException {
if (preparedStatement == null) {
preparedStatement = mapping.getConnection(readOnly).prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
}
}
public void close() {
try {
if (preparedStatement != null && preparedStatement.getConnection() != null) {
preparedStatement.getConnection().close();
}
} catch (SQLException e) {
// ignore
}
}
private void assignParameters() {
if (preparedStatement != null && parameters != null) {
for (Iterator iterator = parameters.iterator(); iterator.hasNext();) {
Parameter parameter = (Parameter) iterator.next();
try {
parameter.setParameter();
} catch (SQLException e) {
String message = toString();
parameters = null;
throw new ErrorMessageException(message, e, null);
}
}
}
}
private void addParameter(int index, Object value, int type, boolean isNull) {
if (parameters == null) {
parameters = new SortedVector();
}
parameters.sortInsert(new Parameter(index, value, type, isNull), parameterSorter);
}
public void setObject(int index, Object value, boolean isNull) {
addParameter(index, value, TYPE_OBJECT, isNull);
}
public void setInt(int index, int i) {
setInt(index, i, false);
}
public void setInt(int index, int i, boolean isNull) {
addParameter(index, new Integer(i), TYPE_INT, isNull);
}
public void setTimestamp(int index, Timestamp timestamp, boolean isNull) {
addParameter(index, timestamp, TYPE_TIMESTAMP, isNull);
}
public void setDate(int index, Date date, boolean isNull) {
addParameter(index, date, TYPE_DATE, isNull);
}
public void setDouble(int index, double v, boolean isNull) {
addParameter(index, new Double(v), TYPE_DOUBLE, isNull);
}
public void setLong(int index, long l, boolean isNull) {
addParameter(index, new Long(l), TYPE_LONG, isNull);
}
public void setString(int index, String s) {
setString(index, s, false);
}
public void setString(int index, String s, boolean isNull) {
addParameter(index, s, TYPE_STRING, isNull);
}
public String toString() {
StringBuffer ret = new StringBuffer();
ret.append(sql);
if (parameters != null) {
ret.append(" [");
for (Iterator it = parameters.iterator(); it.hasNext();) {
Parameter parameter = (Parameter) it.next();
ret.append(parameter.toString());
if (it.hasNext()) {
ret.append(" ");
}
}
ret.append("]");
}
return ret.toString();
}
class Parameter {
private boolean isNull;
private int index;
private Object value;
private int type;
public Parameter(int index, Object value, int type, boolean isNull) {
this.index = index;
this.value = value;
this.type = type;
this.isNull = isNull;
}
public void setParameter() throws SQLException {
if (isNull) {
preparedStatement.setNull(index, type);
} else {
switch (type) {
case TYPE_OBJECT:
preparedStatement.setObject(index, value);
break;
case TYPE_DATE:
preparedStatement.setDate(index, (Date) value);
break;
case TYPE_DOUBLE:
preparedStatement.setDouble(index, ((Double) value).doubleValue());
break;
case TYPE_INT:
preparedStatement.setInt(index, ((Integer) value).intValue());
break;
case TYPE_LONG:
preparedStatement.setLong(index, ((Long) value).longValue());
break;
case TYPE_STRING:
preparedStatement.setString(index, (String) value);
break;
case TYPE_TIMESTAMP:
preparedStatement.setTimestamp(index, (Timestamp) value);
break;
}
}
}
//todo check if ok to return with no index
public String toString() {
/*if (isNull) {
return index + ") [NULL]";
}
return index + ") " + value;*/
if (isNull) {
return "";
}
return value.toString();
}
}
private static class ParameterSorter implements Sorter {
public int compare(Object o1, Object o2) {
return ((Parameter) o2).index - ((Parameter) o1).index;
}
}
//todo
public boolean getLastStatementResult() {
return lastStatementResult;
}
}