package org.gjt.bugrat.dbi;
import java.io.IOException;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.util.Date;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
public class
BugRatJDBC extends Object
{
private static final boolean DEBUG = false;
public static final String TRUE_VALUE = "Y";
public static final String FALSE_VALUE = "N";
public static final String NO_VALUE = "N";
public static final String YES_VALUE = "Y";
/**
* If this is set to true, we use the Oracle method
* of managing LONGVARCHAR fields, which can only be
* accessed by streams.
*/
protected JDBCHandler handler;
public
BugRatJDBC( JDBCHandler handler )
{
this.handler = handler;
}
protected JDBCHandler
getHandler()
{
return this.handler;
}
protected String
getString( ResultSet rs, int col )
throws SQLException
{
String result = rs.getString( col );
if ( result == null )
result = "";
return result;
}
public void
setNullString( PreparedStatement pS, int idx, String val, int sqlType )
throws SQLException
{
if ( val == null )
pS.setNull( idx, sqlType );
else
pS.setString( idx, val );
}
public Timestamp
normalizeDate( Date d )
throws SQLException
{
// UNDONE
// This code will convert the Date d from a local time (e.g., EDT)
// into the 'normal' date based on GMT...
//
return (d == null) ? null : new Timestamp( d.getTime() );
}
public Date
localizeDate( Timestamp t )
throws SQLException
{
// UNDONE
// This code will convert the Date d from 'normal' GMT time into
// the 'local' date (e.g., EDT)...
//
return (t == null) ? null : new Date( t.getTime() );
}
/**
* Large string support.
*
* Some utterly lame database products can not handle
* strings larger than 4000 bytes. Wow. So, to better
* support these products, we have defined this special
* method in the event that the developer needs to hack
* in support for their special database.
*
* In the default case, this simply calls through to the
* getString() method.
*
* Oracle (aka lame database) users have been accomodated
* here with code that may or may not work. Since I would
* never choose Oracle as a database, I am not able to
* test this code. However, if someone is willing to make
* sure the code works and send me the patches, I will make
* sure they are applied. Note that you must set the servlet
* initial parameter to get this code to select "usingOracle".
*
* See web.xml for more details.
*
* Other database users are also free to send patches.
*
* NOTE: Hacks that require JDBC 2.0 are not likely to make
* direct release, as I do not want to tie BugRat to
* that API just yet. However, they will be included
* as comments (like the Clobs below) for those who
* need them.
*
*/
public String
getLargeString( ResultSet rs, int col )
throws SQLException
{
if ( ! this.handler.isUsingOracle() )
return this.getString( rs, col );
InputStream is = rs.getAsciiStream( col );
if ( is == null )
return "";
StringBuffer strBuf = new StringBuffer();
try {
for ( byte[] byteBuf = new byte[1024] ; ; )
{
int numRead = is.read( byteBuf );
if ( numRead == -1 )
break;
strBuf.append( new String( byteBuf, 0, numRead ) );
}
}
catch ( IOException ex )
{
throw new SQLException
( "IOException reading large string, " + ex.getMessage() );
}
finally
{
try { is.close(); }
catch ( IOException ex ) {}
}
return strBuf.toString();
}
/**
* Large string support.
*
* Some utterly lame database products can not handle
* strings larger than 4000 bytes. Wow. So, to better
* support these products, we have defined this special
* method in the event that the developer needs to hack
* in support for their special database.
*
* In the default case, this simply calls through to the
* setNullString() method.
*
* Oracle (aka lame database) users have been accomodated
* here with code that may or may not work. Since I would
* never choose Oracle as a database, I am not able to
* test this code. However, if someone is willing to make
* sure the code works and send me the patches, I will make
* sure they are applied. Note that you must set the servlet
* initial parameter to get this code to select "usingOracle".
*
* See web.xml for more details.
*
* Other database users are also free to send patches.
*
* NOTE: Hacks that require JDBC 2.0 are not likely to make
* direct release, as I do not want to tie BugRat to
* that API just yet. However, they will be included
* as comments (like the Clobs below) for those who
* need them.
*
*/
public void
setLargeString( PreparedStatement pS, int col, String val, int sqlType )
throws SQLException
{
if ( ! this.handler.isUsingOracle() )
this.setNullString( pS, col, val, sqlType );
if ( val == null )
{
pS.setNull( col, java.sql.Types.LONGVARCHAR );
}
else
{
ByteArrayInputStream baIn =
new ByteArrayInputStream( val.getBytes() );
pS.setAsciiStream( col, baIn, baIn.available() );
}
}
/**
* FOR ORACLE USERS
*
* This method retrieves a Character Large Object (CLOB) from the
* database. This is used where the MySQL "mediumblob" can not.
*
* This is used for description.desctext, properties.propval,
* emailcontent.content, and envdesc.envdesc.
*
* DO NOT CALL THIS DIRECT. Call it via getLargeString() and
* set the oracle servlet parameter.
*
* @param rs The ResultSet having the proper row in its cursor.
* @param col The Column-counter of the field which has the CLOB.
* @returns a java.lang.String that contains the whole CLOB.
*/
/* ***
public String
getClob( ResultSet rs, int col )
throws SQLException
{
java.sql.Clob clob = ((OracleResultSet) rs).getClob( col );
char[] cdata = new char[ (int)clob.length() ];
Reader cs = clob.getCharacterStream();
try {
cs.read( cdata );
}
catch ( IOException ex )
{
throw new SQLException
( "reading CLOB field - " + ex.getMessage() );
}
return new String( cdata );
}
* ***/
/**
* FOR ORACLE USERS - UNDONE
*
* This method set a Character Large Object (CLOB) in the
* database. This is used where the MySQL "mediumblob" can not.
*
* This is used for description.desctext, properties.propval,
* emailcontent.content, and envdesc.envdesc.
*
* It appears that you must select to get the clobs, then modify
* the CLOB which in turn modifies the database?!?! Wow!
*
* DO NOT CALL THIS DIRECT. Call it via setLargeString() and
* set the oracle servlet parameter.
*
* @param rs The ResultSet having the proper row in its cursor.
* @param col The Column-counter of the field which has the CLOB.
* @returns a java.lang.String that contains the whole CLOB.
*/
/* ***
public void
setClob( PreparedStatement pS, int col, String value )
throws SQLException
{
// UNDONE
// UNDONE
}
* ***/
public int
getNextId( String name )
throws DBIException
{
int result = 0;
StringBuffer qBuf = new StringBuffer();
try {
qBuf.append( "SELECT " );
qBuf.append( " sequence.nextseq " );
qBuf.append( "FROM " );
qBuf.append( " sequence " );
qBuf.append( "WHERE " );
qBuf.append( " sequence.name = '" );
qBuf.append( name );
qBuf.append( "' " );
if ( DEBUG )
System.err.println
( "BugRatJDBC.getNextId: STATEMENT = '" + qBuf + "'" );
Statement stmt = this.handler.createStatement();
ResultSet rs = stmt.executeQuery( qBuf.toString() );
boolean hasRow = rs.next();
if ( DEBUG )
System.err.println
( "BugRatJDBC.getNextId: HAS ROW? '" + hasRow + "'" );
if ( hasRow )
{
result = rs.getInt( 1 );
if ( DEBUG )
System.err.println
( "BugRatJDBC.getNextId: RESULT '" + result + "'" );
}
rs.close();
stmt.close();
if ( ! hasRow )
{
if ( DEBUG )
System.err.println
( "BugRatJDBC.getNextId: CREATE SEQ = '" + name + "'" );
qBuf.setLength(0);
qBuf.append( "INSERT INTO sequence " );
qBuf.append( " ( name, nextseq ) " );
qBuf.append( "VALUES " );
qBuf.append( " ( ?, ? ) " );
PreparedStatement pS =
this.handler.createPreparedStatement( qBuf.toString() );
int fld = 1;
int nextId = 2;
pS.setString( fld++, name );
pS.setInt( fld++, nextId );
int rows = pS.executeUpdate();
if ( DEBUG )
System.err.println
( "BugRatJDBC.getNextId: ROWS = '" + rows + "'" );
pS.close();
// Be sure to send back the new id of 1, and previously
// we set the nextId to 2.
result = 1;
}
else
{
qBuf.setLength(0);
qBuf.append( "UPDATE " );
qBuf.append( " sequence " );
qBuf.append( "SET " );
qBuf.append( " sequence.nextseq = ? " );
qBuf.append( "WHERE " );
qBuf.append( " sequence.name = '" + name + "' " );
PreparedStatement pS =
this.handler.createPreparedStatement( qBuf.toString() );
pS.setInt( 1, result + 1 );
int rows = pS.executeUpdate();
if ( DEBUG )
System.err.println
( "BugRatJDBC.getNextId: ROWS = '" + rows + "'" );
pS.close();
}
}
catch ( SQLException ex )
{
if ( DEBUG )
ex.printStackTrace( System.err );
throw new DBIException
( ex, "get sequence '" + name
+ "', statement '" + qBuf + "'" );
}
return result;
}
}