Imported a slightly modified version of JORA.
git-svn-id: https://samskivert.googlecode.com/svn/trunk@39 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -0,0 +1,240 @@
|
||||
//-< Cursor.java >---------------------------------------------------*--------*
|
||||
// JORA Version 2.0 (c) 1998 GARRET * ? *
|
||||
// (Java Object Relational Adapter) * /\| *
|
||||
// * / \ *
|
||||
// Created: 10-Jun-98 K.A. Knizhnik * / [] \ *
|
||||
// Last update: 20-Jun-98 K.A. Knizhnik * GARRET *
|
||||
//-------------------------------------------------------------------*--------*
|
||||
// Cursor for navigation thru result of SELECT statement
|
||||
//-------------------------------------------------------------------*--------*
|
||||
|
||||
package com.samskivert.jdbc.jora;
|
||||
|
||||
import java.util.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.sql.*;
|
||||
|
||||
/** Cursor is used for successive access to records fetched by SELECT
|
||||
* statement. As far as records can be retrived from several derived tables
|
||||
* (polymorphic form of select), this class can issue several requests
|
||||
* to database. Cursor also provides methods for updating/deleting current
|
||||
* record.
|
||||
*/
|
||||
public class Cursor {
|
||||
/**
|
||||
* A cursor is initially positioned before its first row; the
|
||||
* first call to next makes the first row the current row; the
|
||||
* second call makes the second row the current row, etc.
|
||||
*
|
||||
* <P>If an input stream from the previous row is open, it is
|
||||
* implicitly closed. The ResultSet's warning chain is cleared
|
||||
* when a new row is read.
|
||||
*
|
||||
* @return object constructed from fetched record or null if there
|
||||
* are no more rows
|
||||
*/
|
||||
public Object next()
|
||||
throws SQLException
|
||||
{
|
||||
// try {
|
||||
do {
|
||||
if (result == null) {
|
||||
if (table.isAbstract) {
|
||||
table = table.derived;
|
||||
continue;
|
||||
}
|
||||
if (qbeObject != null) {
|
||||
String sql = "select " + table.listOfFields
|
||||
+ " from " + table.name + " " + query;
|
||||
PreparedStatement qbeStmt;
|
||||
synchronized(session.preparedStmtHash) {
|
||||
Object s = session.preparedStmtHash.get(sql);
|
||||
if (s == null) {
|
||||
qbeStmt=session.connection.prepareStatement(sql);
|
||||
session.preparedStmtHash.put(sql, qbeStmt);
|
||||
} else {
|
||||
qbeStmt = (PreparedStatement)s;
|
||||
}
|
||||
}
|
||||
synchronized(qbeStmt) {
|
||||
table.bindQueryVariables(qbeStmt, qbeObject);
|
||||
result = qbeStmt.executeQuery();
|
||||
qbeStmt.clearParameters();
|
||||
}
|
||||
} else {
|
||||
if (stmt == null) {
|
||||
stmt = session.connection.createStatement();
|
||||
}
|
||||
String sql = "select " + table.listOfFields
|
||||
+ " from " + table.name + " " + query;
|
||||
result = stmt.executeQuery(sql);
|
||||
}
|
||||
}
|
||||
if (result.next()) {
|
||||
return currObject = table.load(result);
|
||||
}
|
||||
result.close();
|
||||
result = null;
|
||||
currObject = null;
|
||||
table = table.derived;
|
||||
} while (--nTables != 0);
|
||||
|
||||
if (stmt != null) {
|
||||
stmt.close();
|
||||
}
|
||||
// }
|
||||
// catch (SQLException ex) { session.handleSQLException(ex); }
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Update current record pointed by cursor. This method can be called
|
||||
* only after next() method, which returns non-null object. This objects
|
||||
* is used to update current record fields.<P>
|
||||
*
|
||||
* If you are going to update or delete selected records, you should add
|
||||
* "for update" clause to select statement. So parameter of
|
||||
* <CODE>jora.Table.select()</CODE> statement should contain "for update"
|
||||
* clause:
|
||||
* <CODE>record.table.Select("where name='xyz' for update");</CODE><P>
|
||||
*
|
||||
* <I><B>Attention!</I></B>
|
||||
* Not all database drivers support update operation with
|
||||
* cursor. This method will not work with such database drivers.
|
||||
*/
|
||||
public void update()
|
||||
throws SQLException
|
||||
{
|
||||
if (currObject == null) {
|
||||
throw new NoCurrentObjectError();
|
||||
}
|
||||
// try {
|
||||
table.updateVariables(result, currObject);
|
||||
// }
|
||||
// catch (SQLException ex) { session.handleSQLException(ex); }
|
||||
}
|
||||
|
||||
/** Delete current record pointed by cursor. This method can be called
|
||||
* only after next() method, which returns non-null object.<P>
|
||||
*
|
||||
* If you are going to update or delete selected records, you should add
|
||||
* "for update" clause to select statement. So parameter of
|
||||
* <CODE>jora.Table.select()</CODE> statement should contain "for update"
|
||||
* clause:
|
||||
* <CODE>record.table.Select("where name='xyz' for update");</CODE><P>
|
||||
*
|
||||
* <I><B>Attention!</I></B>
|
||||
* Not all database drivers support delete operation with cursor.
|
||||
* This method will not work with such database drivers.
|
||||
*/
|
||||
public void delete()
|
||||
throws SQLException
|
||||
{
|
||||
if (currObject == null) {
|
||||
throw new NoCurrentObjectError();
|
||||
}
|
||||
// try {
|
||||
result.deleteRow();
|
||||
// }
|
||||
// catch (SQLException ex) { session.handleSQLException(ex); }
|
||||
}
|
||||
|
||||
/** Extracts no more than <I>maxElements</I> records from database and
|
||||
* store them into array. It is possible to extract rest records
|
||||
* by successive next() or toArray() calls. Selected objects should
|
||||
* have now components of InputStream, Blob or Clob type, because
|
||||
* their data will be not available after fetching next record.
|
||||
*
|
||||
* @param maxElements limitation for result array size (and also for number
|
||||
* of fetched records)
|
||||
* @return Array with objects constructed from fetched records.
|
||||
*/
|
||||
public Object[] toArray(int maxElements)
|
||||
throws SQLException
|
||||
{
|
||||
Vector v = new Vector(maxElements < 100 ? maxElements : 100);
|
||||
Object o;
|
||||
while (--maxElements >= 0 && (o = next()) != null) {
|
||||
v.addElement(o);
|
||||
}
|
||||
Object[] a = new Object[v.size()];
|
||||
v.copyInto(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
/** Store all objects returned by SELECT query into array of Object.
|
||||
* Selected objects should have now components of InputStream, Blob or
|
||||
* Clob type, because their data will be not available after fetching
|
||||
* next record.
|
||||
*
|
||||
* @return Array with objects constructed from fetched records.
|
||||
*/
|
||||
public Object[] toArray()
|
||||
throws SQLException
|
||||
{ return toArray(Integer.MAX_VALUE); }
|
||||
|
||||
/** Extracts no more than <I>maxElements</I> records from database and
|
||||
* store them into array. It is possible to extract rest records
|
||||
* by successive next() or toArray() calls. Selected objects should
|
||||
* have now components of InputStream, Blob or Clob type, because
|
||||
* their data will be not available after fetching next record.
|
||||
*
|
||||
* @param maxElements limitation for result array size (and also for number
|
||||
* of fetched records)
|
||||
* @return List with objects constructed from fetched records.
|
||||
*/
|
||||
public List toArrayList(int maxElements)
|
||||
throws SQLException
|
||||
{
|
||||
ArrayList al = new ArrayList(maxElements < 100 ? maxElements : 100);
|
||||
Object o;
|
||||
while (--maxElements >= 0 && (o = next()) != null) {
|
||||
al.add(o);
|
||||
}
|
||||
return al;
|
||||
}
|
||||
|
||||
/** Store all objects returned by SELECT query into a list of Object.
|
||||
* Selected objects should have now components of InputStream, Blob or
|
||||
* Clob type, because their data will be not available after fetching
|
||||
* next record.
|
||||
*
|
||||
* @return Array with objects constructed from fetched records.
|
||||
*/
|
||||
public List toArrayList()
|
||||
throws SQLException
|
||||
{ return toArrayList(Integer.MAX_VALUE); }
|
||||
|
||||
// Internals
|
||||
|
||||
protected Cursor(Table table, Session session, int nTables, String query) {
|
||||
if (session == null) {
|
||||
session = ((SessionThread)Thread.currentThread()).session;
|
||||
}
|
||||
this.table = table;
|
||||
this.session = session;
|
||||
this.nTables = nTables;
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
protected Cursor(Table table, Session session, int nTables, Object obj) {
|
||||
if (session == null) {
|
||||
session = ((SessionThread)Thread.currentThread()).session;
|
||||
}
|
||||
this.table = table;
|
||||
this.session = session;
|
||||
this.nTables = nTables;
|
||||
qbeObject = obj;
|
||||
query = table.buildQueryList(obj);
|
||||
stmt = null;
|
||||
}
|
||||
|
||||
private Table table;
|
||||
private Session session;
|
||||
private int nTables;
|
||||
private ResultSet result;
|
||||
private String query;
|
||||
private Statement stmt;
|
||||
private Object currObject;
|
||||
private Object qbeObject;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
//-< DataTransferError.java >----------------------------------------*--------*
|
||||
// JORA Version 2.0 (c) 1998 GARRET * ? *
|
||||
// (Java Object Relational Adapter) * /\| *
|
||||
// * / \ *
|
||||
// Created: 10-Jun-98 K.A. Knizhnik * / [] \ *
|
||||
// Last update: 19-Jun-98 K.A. Knizhnik * GARRET *
|
||||
//-------------------------------------------------------------------*--------*
|
||||
// Exception raised when error is happed during data transfer between
|
||||
// program and database server
|
||||
//-------------------------------------------------------------------*--------*
|
||||
|
||||
package com.samskivert.jdbc.jora;
|
||||
|
||||
/** This error is raised when error is happened during data transfer
|
||||
* between program and database server (for example IOException was thrown
|
||||
* while operation with InputStream field)
|
||||
*/
|
||||
public class DataTransferError extends java.lang.Error {
|
||||
DataTransferError() {
|
||||
super("Database data transfer error");
|
||||
}
|
||||
DataTransferError(Exception ex) {
|
||||
super(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,437 @@
|
||||
//-< FieldDescriptor.java >------------------------------------------*--------*
|
||||
// JORA Version 2.0 (c) 1998 GARRET * ? *
|
||||
// (Java Object Relational Adapter) * /\| *
|
||||
// * / \ *
|
||||
// Created: 10-Jun-98 K.A. Knizhnik * / [] \ *
|
||||
// Last update: 25-Jun-98 K.A. Knizhnik * GARRET *
|
||||
//-------------------------------------------------------------------*--------*
|
||||
// Table field descriptor
|
||||
//-------------------------------------------------------------------*--------*
|
||||
|
||||
package com.samskivert.jdbc.jora;
|
||||
|
||||
import java.sql.*;
|
||||
import java.math.*;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
class FieldDescriptor {
|
||||
protected int inType; // type tag for field input (see constants below)
|
||||
protected int outType; // type tag for field output
|
||||
protected int scale; // scale for tDecimal type,
|
||||
protected String name; // full (compound) name of component
|
||||
protected Field field; // field info from java.lang.reflect
|
||||
|
||||
protected Constructor constructor; // constructor of object component
|
||||
|
||||
protected static final int t_byte = 0;
|
||||
protected static final int t_short = 1;
|
||||
protected static final int t_int = 2;
|
||||
protected static final int t_long = 3;
|
||||
protected static final int t_float = 4;
|
||||
protected static final int t_double = 5;
|
||||
protected static final int t_boolean = 6;
|
||||
protected static final int tByte = 7;
|
||||
protected static final int tShort = 8;
|
||||
protected static final int tInteger = 9;
|
||||
protected static final int tLong = 10;
|
||||
protected static final int tFloat = 11;
|
||||
protected static final int tDouble = 12;
|
||||
protected static final int tBoolean = 13;
|
||||
protected static final int tDecimal = 14;
|
||||
protected static final int tString = 15;
|
||||
protected static final int tBytes = 16;
|
||||
protected static final int tDate = 17;
|
||||
protected static final int tTime = 18;
|
||||
protected static final int tTimestamp = 19;
|
||||
protected static final int tStream = 20;
|
||||
protected static final int tBlob = 21;
|
||||
protected static final int tClob = 22;
|
||||
protected static final int tAsString = 23;
|
||||
|
||||
protected static final int tClosure = 24;
|
||||
protected static final int tCompound = 25;
|
||||
|
||||
protected static final int[] sqlTypeMapping = {
|
||||
Types.INTEGER, // t_byte
|
||||
Types.INTEGER, // t_short
|
||||
Types.INTEGER, // t_int
|
||||
Types.BIGINT, // t_long
|
||||
Types.FLOAT, // t_float
|
||||
Types.DOUBLE, // t_double
|
||||
Types.BIT, // t_boolean
|
||||
Types.INTEGER, // tByte
|
||||
Types.INTEGER, // tShort
|
||||
Types.INTEGER, // tInteger
|
||||
Types.BIGINT, // tLong
|
||||
Types.FLOAT, // tFloat
|
||||
Types.DOUBLE, // tDouble
|
||||
Types.BIT, // tBoolean
|
||||
Types.NUMERIC, // tDecimal
|
||||
Types.VARCHAR, // tString
|
||||
Types.VARBINARY,// tBytes
|
||||
Types.DATE, // tDate
|
||||
Types.TIME, // tTime
|
||||
Types.TIMESTAMP, // tTimestamp
|
||||
Types.LONGVARBINARY, // tStream
|
||||
Types.LONGVARBINARY, // tBlob
|
||||
Types.LONGVARCHAR, // tClob
|
||||
Types.VARCHAR, // tAsString
|
||||
Types.LONGVARBINARY // tClosure
|
||||
};
|
||||
|
||||
protected FieldDescriptor(Field field, String name) {
|
||||
this.name = name;
|
||||
this.field = field;
|
||||
this.scale = -1;
|
||||
}
|
||||
|
||||
protected final boolean isAtomic() { return inType < tClosure; }
|
||||
|
||||
protected final boolean isCompound() { return inType >= tCompound; }
|
||||
|
||||
protected final boolean isBuiltin() { return inType <= t_boolean; }
|
||||
|
||||
|
||||
protected final boolean bindVariable(PreparedStatement pstmt,
|
||||
Object obj, int column)
|
||||
throws SQLException
|
||||
{
|
||||
try {
|
||||
switch (outType) {
|
||||
case t_byte:
|
||||
pstmt.setByte(column, field.getByte(obj));
|
||||
break;
|
||||
case t_short:
|
||||
pstmt.setShort(column, field.getShort(obj));
|
||||
break;
|
||||
case t_int:
|
||||
pstmt.setInt(column, field.getInt(obj));
|
||||
break;
|
||||
case t_long:
|
||||
pstmt.setLong(column, field.getLong(obj));
|
||||
break;
|
||||
case t_float:
|
||||
pstmt.setFloat(column, field.getFloat(obj));
|
||||
break;
|
||||
case t_double:
|
||||
pstmt.setDouble(column, field.getDouble(obj));
|
||||
break;
|
||||
case t_boolean:
|
||||
pstmt.setBoolean(column, field.getBoolean(obj));
|
||||
break;
|
||||
case tByte:
|
||||
pstmt.setByte(column, ((Byte)field.get(obj)).byteValue());
|
||||
break;
|
||||
case tShort:
|
||||
pstmt.setShort(column, ((Short)field.get(obj)).shortValue());
|
||||
break;
|
||||
case tInteger:
|
||||
pstmt.setInt(column, ((Integer)field.get(obj)).intValue());
|
||||
break;
|
||||
case tLong:
|
||||
pstmt.setLong(column, ((Long)field.get(obj)).longValue());
|
||||
break;
|
||||
case tFloat:
|
||||
pstmt.setFloat(column, ((Float)field.get(obj)).floatValue());
|
||||
break;
|
||||
case tDouble:
|
||||
pstmt.setDouble(column,((Double)field.get(obj)).doubleValue());
|
||||
break;
|
||||
case tBoolean:
|
||||
pstmt.setBoolean(column,
|
||||
((Boolean)field.get(obj)).booleanValue());
|
||||
break;
|
||||
|
||||
case tDecimal:
|
||||
pstmt.setBigDecimal(column, (BigDecimal)field.get(obj));
|
||||
break;
|
||||
case tString:
|
||||
pstmt.setString(column, (String)field.get(obj));
|
||||
break;
|
||||
case tBytes:
|
||||
pstmt.setBytes(column, (byte[])field.get(obj));
|
||||
break;
|
||||
case tDate:
|
||||
pstmt.setDate(column, (java.sql.Date)field.get(obj));
|
||||
break;
|
||||
case tTime:
|
||||
pstmt.setTime(column, (java.sql.Time)field.get(obj));
|
||||
break;
|
||||
case tTimestamp:
|
||||
pstmt.setTimestamp(column, (java.sql.Timestamp)field.get(obj));
|
||||
break;
|
||||
case tStream:
|
||||
java.io.InputStream in = (java.io.InputStream)field.get(obj);
|
||||
pstmt.setBinaryStream(column, in, in.available());
|
||||
break;
|
||||
case tBlob:
|
||||
pstmt.setBlob(column, (Blob)field.get(obj));
|
||||
break;
|
||||
case tClob:
|
||||
pstmt.setClob(column, (Clob)field.get(obj));
|
||||
break;
|
||||
case tAsString:
|
||||
pstmt.setString(column, field.get(obj).toString());
|
||||
break;
|
||||
case tClosure:
|
||||
// There is no reason to use piped streams because
|
||||
// we need to pass total number of bytes to JDBC driver
|
||||
java.io.ByteArrayOutputStream out =
|
||||
new java.io.ByteArrayOutputStream();
|
||||
java.io.ObjectOutputStream clu =
|
||||
new java.io.ObjectOutputStream(out);
|
||||
clu.writeObject(field.get(obj));
|
||||
clu.close();
|
||||
pstmt.setBytes(column, out.toByteArray());
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} catch(SQLException ex) {
|
||||
if (outType != tClosure && outType != tAsString) {
|
||||
outType = tAsString;
|
||||
return bindVariable(pstmt, obj, column);
|
||||
} else {
|
||||
throw ex;
|
||||
}
|
||||
} catch(IllegalAccessException ex) {
|
||||
ex.printStackTrace();
|
||||
throw new IllegalAccessError();
|
||||
} catch(java.io.IOException ex) {
|
||||
throw new DataTransferError(ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected final boolean updateVariable(ResultSet result,
|
||||
Object obj, int column)
|
||||
throws SQLException
|
||||
{
|
||||
try {
|
||||
switch (outType) {
|
||||
case t_byte:
|
||||
result.updateByte(column, field.getByte(obj));
|
||||
break;
|
||||
case t_short:
|
||||
result.updateShort(column, field.getShort(obj));
|
||||
break;
|
||||
case t_int:
|
||||
result.updateInt(column, field.getInt(obj));
|
||||
break;
|
||||
case t_long:
|
||||
result.updateLong(column, field.getLong(obj));
|
||||
break;
|
||||
case t_float:
|
||||
result.updateFloat(column, field.getFloat(obj));
|
||||
break;
|
||||
case t_double:
|
||||
result.updateDouble(column, field.getDouble(obj));
|
||||
break;
|
||||
case t_boolean:
|
||||
result.updateBoolean(column, field.getBoolean(obj));
|
||||
break;
|
||||
case tByte:
|
||||
result.updateByte(column, ((Byte)field.get(obj)).byteValue());
|
||||
break;
|
||||
case tShort:
|
||||
result.updateShort(column,
|
||||
((Short)field.get(obj)).shortValue());
|
||||
break;
|
||||
case tInteger:
|
||||
result.updateInt(column, ((Integer)field.get(obj)).intValue());
|
||||
break;
|
||||
case tLong:
|
||||
result.updateLong(column, ((Long)field.get(obj)).longValue());
|
||||
break;
|
||||
case tFloat:
|
||||
result.updateFloat(column,
|
||||
((Float)field.get(obj)).floatValue());
|
||||
break;
|
||||
case tDouble:
|
||||
result.updateDouble(column,
|
||||
((Double)field.get(obj)).doubleValue());
|
||||
break;
|
||||
case tBoolean:
|
||||
result.updateBoolean(column,
|
||||
((Boolean)field.get(obj)).booleanValue());
|
||||
break;
|
||||
|
||||
case tDecimal:
|
||||
result.updateBigDecimal(column, (BigDecimal)field.get(obj));
|
||||
break;
|
||||
case tString:
|
||||
result.updateString(column, (String)field.get(obj));
|
||||
break;
|
||||
case tBytes:
|
||||
result.updateBytes(column, (byte[])field.get(obj));
|
||||
break;
|
||||
case tDate:
|
||||
result.updateDate(column, (java.sql.Date)field.get(obj));
|
||||
break;
|
||||
case tTime:
|
||||
result.updateTime(column, (java.sql.Time)field.get(obj));
|
||||
break;
|
||||
case tTimestamp:
|
||||
result.updateTimestamp(column,
|
||||
(java.sql.Timestamp)field.get(obj));
|
||||
break;
|
||||
case tStream:
|
||||
java.io.InputStream in = (java.io.InputStream)field.get(obj);
|
||||
result.updateBinaryStream(column, in, in.available());
|
||||
break;
|
||||
case tBlob:
|
||||
Blob blob = (Blob)field.get(obj);
|
||||
result.updateBinaryStream(column,
|
||||
blob.getBinaryStream(),
|
||||
(int)blob.length());
|
||||
break;
|
||||
case tClob:
|
||||
Clob clob = (Clob)field.get(obj);
|
||||
result.updateCharacterStream(column,
|
||||
clob.getCharacterStream(),
|
||||
(int)clob.length());
|
||||
break;
|
||||
case tAsString:
|
||||
result.updateString(column, field.get(obj).toString());
|
||||
break;
|
||||
case tClosure:
|
||||
// There is no reason to use piped streams because
|
||||
// we need to pass total number of bytes to JDBC driver
|
||||
java.io.ByteArrayOutputStream out =
|
||||
new java.io.ByteArrayOutputStream();
|
||||
java.io.ObjectOutputStream clu =
|
||||
new java.io.ObjectOutputStream(out);
|
||||
clu.writeObject(field.get(obj));
|
||||
clu.close();
|
||||
result.updateBytes(column, out.toByteArray());
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} catch(SQLException ex) {
|
||||
if (outType != tClosure && outType != tAsString) {
|
||||
outType = tAsString;
|
||||
return updateVariable(result, obj, column);
|
||||
} else {
|
||||
throw ex;
|
||||
}
|
||||
} catch(IllegalAccessException ex) {
|
||||
ex.printStackTrace();
|
||||
throw new IllegalAccessError();
|
||||
} catch(java.io.IOException ex) {
|
||||
throw new DataTransferError(ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected final boolean loadVariable(ResultSet result,
|
||||
Object obj, int column)
|
||||
throws SQLException, IllegalAccessException
|
||||
{
|
||||
switch (inType) {
|
||||
case t_byte:
|
||||
field.setByte(obj, result.getByte(column));
|
||||
break;
|
||||
case t_short:
|
||||
field.setShort(obj, result.getShort(column));
|
||||
break;
|
||||
case t_int:
|
||||
field.setInt(obj, result.getInt(column));
|
||||
break;
|
||||
case t_long:
|
||||
field.setLong(obj, result.getLong(column));
|
||||
break;
|
||||
case t_float:
|
||||
field.setFloat(obj, result.getFloat(column));
|
||||
break;
|
||||
case t_double:
|
||||
field.setDouble(obj, result.getDouble(column));
|
||||
break;
|
||||
case t_boolean:
|
||||
field.setBoolean(obj, result.getBoolean(column));
|
||||
break;
|
||||
|
||||
case tByte:
|
||||
byte b = result.getByte(column);
|
||||
field.set(obj, result.wasNull() ? null : new Byte(b));
|
||||
break;
|
||||
case tShort:
|
||||
short s = result.getShort(column);
|
||||
field.set(obj, result.wasNull() ? null : new Short(s));
|
||||
break;
|
||||
case tInteger:
|
||||
int i = result.getInt(column);
|
||||
field.set(obj, result.wasNull() ? null : new Integer(i));
|
||||
break;
|
||||
case tLong:
|
||||
long l = result.getLong(column);
|
||||
field.set(obj, result.wasNull() ? null : new Long(l));
|
||||
break;
|
||||
case tFloat:
|
||||
float f = result.getFloat(column);
|
||||
field.set(obj, result.wasNull() ? null : new Float(f));
|
||||
field.setFloat(obj, result.getFloat(column));
|
||||
break;
|
||||
case tDouble:
|
||||
double d = result.getDouble(column);
|
||||
field.set(obj, result.wasNull() ? null : new Double(d));
|
||||
break;
|
||||
case tBoolean:
|
||||
boolean bl = result.getBoolean(column);
|
||||
field.set(obj, result.wasNull() ? null : new Boolean(bl));
|
||||
break;
|
||||
|
||||
case tDecimal:
|
||||
if (Table.useDepricatedGetBigDecimal) {
|
||||
if (scale < 0) {
|
||||
scale = result.getMetaData().getScale(column);
|
||||
}
|
||||
field.set(obj, result.getBigDecimal(column, scale));
|
||||
} else {
|
||||
field.set(obj, result.getBigDecimal(column));
|
||||
}
|
||||
break;
|
||||
case tString:
|
||||
field.set(obj, result.getString(column));
|
||||
break;
|
||||
case tBytes:
|
||||
field.set(obj, result.getBytes(column));
|
||||
break;
|
||||
case tDate:
|
||||
field.set(obj, result.getDate(column));
|
||||
break;
|
||||
case tTime:
|
||||
field.set(obj, result.getTime(column));
|
||||
break;
|
||||
case tTimestamp:
|
||||
field.set(obj, result.getTimestamp(column));
|
||||
break;
|
||||
case tStream:
|
||||
field.set(obj, result.getBinaryStream(column));
|
||||
break;
|
||||
case tBlob:
|
||||
field.set(obj, result.getBlob(column));
|
||||
break;
|
||||
case tClob:
|
||||
field.set(obj, result.getClob(column));
|
||||
break;
|
||||
case tClosure:
|
||||
try {
|
||||
java.io.InputStream input = result.getBinaryStream(column);
|
||||
java.io.ObjectInputStream in =
|
||||
new java.io.ObjectInputStream(input);
|
||||
field.set(obj, in.readObject());
|
||||
in.close();
|
||||
} catch(ClassNotFoundException ex) {
|
||||
throw new DataTransferError(ex);
|
||||
} catch(java.io.IOException ex) {
|
||||
throw new DataTransferError(ex);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# $Id: Makefile,v 1.1 2001/02/13 05:46:56 mdb Exp $
|
||||
|
||||
ROOT = ../../../..
|
||||
|
||||
SRCS = \
|
||||
Cursor.java \
|
||||
DataTransferError.java \
|
||||
FieldDescriptor.java \
|
||||
NoCurrentObjectError.java \
|
||||
NoPrimaryKeyError.java \
|
||||
SQLError.java \
|
||||
Session.java \
|
||||
SessionThread.java \
|
||||
Table.java \
|
||||
|
||||
include $(ROOT)/build/Makefile.java
|
||||
@@ -0,0 +1,23 @@
|
||||
//-< NoCurrentObjectError.java >-------------------------------------*--------*
|
||||
// JORA Version 2.0 (c) 1998 GARRET * ? *
|
||||
// (Java Object Relational Adapter) * /\| *
|
||||
// * / \ *
|
||||
// Created: 10-Jun-98 K.A. Knizhnik * / [] \ *
|
||||
// Last update: 16-Jun-98 K.A. Knizhnik * GARRET *
|
||||
//-------------------------------------------------------------------*--------*
|
||||
// Exception raised when UPDATE/REMOVE operation is applied to Cursor
|
||||
// with no current object
|
||||
//-------------------------------------------------------------------*--------*
|
||||
|
||||
package com.samskivert.jdbc.jora;
|
||||
|
||||
/** Error raised when update/remove operation is applied to
|
||||
* cursor with no current object (before first call of <TT>next()</TT>
|
||||
* method).
|
||||
*/
|
||||
public class NoCurrentObjectError extends java.lang.Error {
|
||||
NoCurrentObjectError() {
|
||||
super("Cursor doesn't specify current object");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
//-< NoPrimaryKeyError.java >----------------------------------------*--------*
|
||||
// JORA Version 2.0 (c) 1998 GARRET * ? *
|
||||
// (Java Object Relational Adapter) * /\| *
|
||||
// * / \ *
|
||||
// Created: 10-Jun-98 K.A. Knizhnik * / [] \ *
|
||||
// Last update: 16-Jun-98 K.A. Knizhnik * GARRET *
|
||||
//-------------------------------------------------------------------*--------*
|
||||
// Exception raised when UPDATE/REMOVE operation is appllied to Table with
|
||||
// no primary key
|
||||
//-------------------------------------------------------------------*--------*
|
||||
|
||||
package com.samskivert.jdbc.jora;
|
||||
|
||||
/** Error raised when unpdate/remove operation is invoked for the table
|
||||
* with no correct primary key defined (key was not specified or
|
||||
* type of the key component is not atomic).
|
||||
*/
|
||||
public class NoPrimaryKeyError extends java.lang.Error {
|
||||
NoPrimaryKeyError(Table table) {
|
||||
super("Table " + table.name + " has no atomic primary key");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
What have we here?
|
||||
------------------
|
||||
|
||||
This is a hacked version of JORA, a library for automatically mapping
|
||||
RDBMS database rows to Java objects and vice versa. It's simple, it uses
|
||||
reflection and doesn't require any classfile post-processing or external
|
||||
configuration information.
|
||||
|
||||
"That's all great but why is it hacked?" wonders the astute reader. Well,
|
||||
I couldn't quite cope with the error handling paradigm that it used (catch
|
||||
all SQL exceptions internally and pass them to an application-wide error
|
||||
handler method) and a few seconds thought on the matter led me to believe
|
||||
that there is not a simple way to allow a choice of error handling
|
||||
paradigms (the methods have to throw SQLException or not). So I took the
|
||||
easy way out and forked the codebase.
|
||||
|
||||
The code is pretty stable, so I don't expect to be merging in updates with
|
||||
any frequency. I promise to be a good monkey and submit any useful
|
||||
modifications that I make back to the original maintainer. It's a good
|
||||
thing that the license was unrestrictive enough to allow me to do this,
|
||||
otherwise I'd probably be stuck reinventing the wheel or using something
|
||||
that does less of what I want. Three cheers for free software.
|
||||
|
||||
The original version can be found here: http://www.ispras.ru/~knizhnik/
|
||||
(or at least it could when I wrote this README).
|
||||
|
||||
- mdb (2/12/2001)
|
||||
@@ -0,0 +1,21 @@
|
||||
//-< SQLError.java >-------------------------------------------------*--------*
|
||||
// JORA Version 2.0 (c) 1998 GARRET * ? *
|
||||
// (Java Object Relational Adapter) * /\| *
|
||||
// * / \ *
|
||||
// Created: 10-Jun-98 K.A. Knizhnik * / [] \ *
|
||||
// Last update: 16-Jun-98 K.A. Knizhnik * GARRET *
|
||||
//-------------------------------------------------------------------*--------*
|
||||
// Database error
|
||||
//-------------------------------------------------------------------*--------*
|
||||
|
||||
package com.samskivert.jdbc.jora;
|
||||
|
||||
/** Database error. Exception SQLException was catched by JORA.
|
||||
*/
|
||||
public class SQLError extends java.lang.RuntimeException {
|
||||
java.sql.SQLException ex;
|
||||
SQLError(java.sql.SQLException x) {
|
||||
super("Database session aborted due to critical error");
|
||||
ex = x;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
//-< Session.java >--------------------------------------------------*--------*
|
||||
// JORA Version 2.0 (c) 1998 GARRET * ? *
|
||||
// (Java Object Relational Adapter) * /\| *
|
||||
// * / \ *
|
||||
// Created: 10-Jun-98 K.A. Knizhnik * / [] \ *
|
||||
// Last update: 20-Jun-98 K.A. Knizhnik * GARRET *
|
||||
//-------------------------------------------------------------------*--------*
|
||||
// Database session abstraction
|
||||
//-------------------------------------------------------------------*--------*
|
||||
|
||||
package com.samskivert.jdbc.jora;
|
||||
|
||||
import java.util.*;
|
||||
import java.sql.*;
|
||||
|
||||
/**
|
||||
* This class is reposnsible for establishing connection with database
|
||||
* and handling database errors.
|
||||
*/
|
||||
public class Session {
|
||||
public Connection connection;
|
||||
|
||||
/** Session consructor
|
||||
*
|
||||
* @param driverClass class of database driver
|
||||
*/
|
||||
public Session(String driverClass)
|
||||
{
|
||||
driver = driverClass;
|
||||
preparedStmtHash = new Hashtable();
|
||||
connectionID = 0;
|
||||
}
|
||||
|
||||
/** Session consructor for ODBC bridge driver
|
||||
*/
|
||||
public Session() { this("sun.jdbc.odbc.JdbcOdbcDriver"); }
|
||||
|
||||
/** Handler of database session errors. Programmer should override
|
||||
* this method in derived class in order to provide application
|
||||
* dependent error handling.
|
||||
*
|
||||
* @param ex exception thrown by some of JDBC methods
|
||||
*/
|
||||
public void handleSQLException(SQLException ex) {
|
||||
// A SQLException was generated. Catch it and
|
||||
// display the error information. Note that there
|
||||
// could be multiple error objects chained
|
||||
// together
|
||||
System.out.println ("*** SQLException caught ***");
|
||||
SQLException x = ex;
|
||||
while (ex != null) {
|
||||
System.out.println("SQLState: " + ex.getSQLState ());
|
||||
System.out.println("Message: " + ex.getMessage ());
|
||||
System.out.println("Vendor: " + ex.getErrorCode ());
|
||||
ex = ex.getNextException();
|
||||
System.out.println ("");
|
||||
}
|
||||
throw new SQLError(x); // terminate program execution
|
||||
}
|
||||
|
||||
/** Open database session.
|
||||
* Attempt to establish a connection to the given database URL.
|
||||
* The DriverManager attempts to select an appropriate driver from
|
||||
* the set of registered JDBC drivers.
|
||||
*
|
||||
* @param url a database url of the form
|
||||
* jdbc:<em>subprotocol</em>:<em>subname</em>
|
||||
* @param user the database user on whose behalf the Connection is being made
|
||||
* @param password the user's password
|
||||
* @return true if session is succesfully openned, false otherwise
|
||||
*/
|
||||
public boolean open(String dataSource, String user, String password)
|
||||
throws SQLException
|
||||
{
|
||||
try {
|
||||
Class.forName(driver);
|
||||
|
||||
connection =
|
||||
DriverManager.getConnection(dataSource, user, password);
|
||||
connectionID += 1;
|
||||
}
|
||||
// catch(SQLException ex) {
|
||||
// handleSQLException(ex);
|
||||
// return false;
|
||||
// }
|
||||
catch(ClassNotFoundException ex) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Close database session and release all resources holded by session.
|
||||
*/
|
||||
public void close()
|
||||
throws SQLException
|
||||
{
|
||||
// try {
|
||||
Enumeration items = preparedStmtHash.elements();
|
||||
while (items.hasMoreElements()) {
|
||||
((PreparedStatement)items.nextElement()).close();
|
||||
}
|
||||
preparedStmtHash.clear();
|
||||
connection.close();
|
||||
// }
|
||||
// catch (SQLException ex) { handleSQLException(ex); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a SQL INSERT, UPDATE or DELETE statement. In addition,
|
||||
* SQL statements that return nothing such as SQL DDL statements
|
||||
* can be executed.
|
||||
*
|
||||
* @param sql a SQL INSERT, UPDATE or DELETE statement or a SQL
|
||||
* statement that returns nothing
|
||||
* @return either the row count for INSERT, UPDATE or DELETE or 0
|
||||
* for SQL statements that return nothing
|
||||
*/
|
||||
public int execute(String sql)
|
||||
throws SQLException
|
||||
{
|
||||
// try {
|
||||
Statement stmt = connection.createStatement();
|
||||
int result = stmt.executeUpdate(sql);
|
||||
stmt.close();
|
||||
return result;
|
||||
// } catch(SQLException ex) { handleSQLException(ex); }
|
||||
// return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit makes all changes made since the previous
|
||||
* commit/rollback permanent and releases any database locks
|
||||
* currently held by the Connection. This method should only be
|
||||
* used when auto commit has been disabled.
|
||||
*/
|
||||
public void commit()
|
||||
throws SQLException
|
||||
{
|
||||
// try {
|
||||
connection.commit();
|
||||
// } catch(SQLException ex) { handleSQLException(ex); }
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback drops all changes made since the previous
|
||||
* commit/rollback and releases any database locks currently held
|
||||
* by the Connection. This method should only be used when auto
|
||||
* commit has been disabled.
|
||||
*/
|
||||
public void rollback()
|
||||
throws SQLException
|
||||
{
|
||||
// try {
|
||||
connection.rollback();
|
||||
// } catch(SQLException ex) { handleSQLException(ex); }
|
||||
}
|
||||
|
||||
protected String driver; // driver class name
|
||||
protected Hashtable preparedStmtHash;
|
||||
protected int connectionID;
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
//-< SessionThread.java >--------------------------------------------*--------*
|
||||
// JORA Version 2.0 (c) 1998 GARRET * ? *
|
||||
// (Java Object Relational Adapter) * /\| *
|
||||
// * / \ *
|
||||
// Created: 18-Jun-99 K.A. Knizhnik * / [] \ *
|
||||
// Last update: 18-Jun-99 K.A. Knizhnik * GARRET *
|
||||
//-------------------------------------------------------------------*--------*
|
||||
// Thread associated with database session
|
||||
//-------------------------------------------------------------------*--------*
|
||||
|
||||
package com.samskivert.jdbc.jora;
|
||||
|
||||
/**
|
||||
* Class representing thread associated with users database session.
|
||||
* If there is single database session opened by application, that it is
|
||||
* possible to associate it with Table object statically. Otherwise it is
|
||||
* needed either to explicitly specify session object in each insert,select
|
||||
* or update statement or associate session with thread by means of
|
||||
* SessionThread class.
|
||||
*/
|
||||
public class SessionThread extends Thread {
|
||||
Session session;
|
||||
|
||||
/**
|
||||
* Allocates a new <code>SessionThread</code> object and associate it with
|
||||
* the specified session. This constructor has the same effect as
|
||||
* <code>SessionThread(session, null, null,</code>
|
||||
* <i>gname</i><code>)</code>, where <b><i>gname</i></b> is
|
||||
* a newly generated name. Automatically generated names are of the
|
||||
* form <code>"Thread-"+</code><i>n</i>, where <i>n</i> is an integer.
|
||||
* <p>
|
||||
* Threads created this way must have overridden their
|
||||
* <code>run()</code> method to actually do anything.
|
||||
*
|
||||
* @param session user database session associated with this thread
|
||||
* @see java.lang.Thread#Thread(java.lang.ThreadGroup,
|
||||
* java.lang.Runnable, java.lang.String)
|
||||
*/
|
||||
public SessionThread(Session session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a new <code>SessionThread</code> object and associate it with
|
||||
* the specified session. This constructor has the same effect as
|
||||
* <code>SessionThread(session, target, null,</code>
|
||||
* <i>gname</i><code>)</code>, where <b><i>gname</i></b> is
|
||||
* a newly generated name. Automatically generated names are of the
|
||||
* form <code>"Thread-"+</code><i>n</i>, where <i>n</i> is an integer.
|
||||
* <p>
|
||||
* Threads created this way must have overridden their
|
||||
* <code>run()</code> method to actually do anything.
|
||||
*
|
||||
* @param session user database session associated with this thread
|
||||
* @param target the object whose <code>run</code> method is called.
|
||||
* @see java.lang.Thread#Thread(java.lang.ThreadGroup,
|
||||
* java.lang.Runnable, java.lang.String)
|
||||
*/
|
||||
public SessionThread(Session session, Runnable target) {
|
||||
super(target);
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a new <code>SessionThread</code> object and associate it with
|
||||
* the specified session. This constructor has the same effect as
|
||||
* <code>SessionThread(session, target, group,</code>
|
||||
* <i>gname</i><code>)</code>, where <b><i>gname</i></b> is
|
||||
* a newly generated name. Automatically generated names are of the
|
||||
* form <code>"Thread-"+</code><i>n</i>, where <i>n</i> is an integer.
|
||||
* <p>
|
||||
* Threads created this way must have overridden their
|
||||
* <code>run()</code> method to actually do anything.
|
||||
*
|
||||
* @param session user database session associated with this thread
|
||||
* @param group the thread group.
|
||||
* @param target the object whose <code>run</code> method is called.
|
||||
* @see java.lang.Thread#Thread(java.lang.ThreadGroup,
|
||||
* java.lang.Runnable, java.lang.String)
|
||||
*/
|
||||
public SessionThread(Session session, ThreadGroup group, Runnable target) {
|
||||
super(target);
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a new <code>SessionThread</code> object. This constructor has
|
||||
* the same effect as <code>SessionThread(session, null, null, name)</code>.
|
||||
*
|
||||
* @param session user database session associated with this thread
|
||||
* @param name the name of the new thread.
|
||||
* @see java.lang.Thread#Thread(java.lang.ThreadGroup,
|
||||
* java.lang.Runnable, java.lang.String)
|
||||
*/
|
||||
public SessionThread(Session session, String name) {
|
||||
super(name);
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a new <code>SessionThread</code> object. This constructor has
|
||||
* the same effect as <code>SessionThread(session, group, null, name)</code>.
|
||||
*
|
||||
* @param session user database session associated with this thread
|
||||
* @param group the thread group.
|
||||
* @param name the name of the new thread.
|
||||
* @see java.lang.Thread#Thread(java.lang.ThreadGroup,
|
||||
* java.lang.Runnable, java.lang.String)
|
||||
*/
|
||||
public SessionThread(Session session, ThreadGroup group, String name) {
|
||||
super(group, name);
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a new <code>SessionThread</code> object. This constructor has
|
||||
* the same effect as <code>SessionThread(session, null, target, name)</code> *
|
||||
* @param session user database session associated with this thread
|
||||
* @param target the object whose <code>run</code> method is called.
|
||||
* @param name the name of the new thread.
|
||||
* @see java.lang.Thread#Thread(java.lang.ThreadGroup,
|
||||
* java.lang.Runnable, java.lang.String)
|
||||
*/
|
||||
public SessionThread(Session session, Runnable target, String name) {
|
||||
super(target, name);
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates a new <code>SessionThread</code> object so that it has
|
||||
* <code>target</code> as its run object, has the specified
|
||||
* <code>name</code> as its name, and belongs to the thread group
|
||||
* referred to by <code>group</code>.
|
||||
* <p>
|
||||
* @param session user database session associated with this thread
|
||||
* @param group the thread group.
|
||||
* @param target the object whose <code>run</code> method is called.
|
||||
* @param name the name of the new thread.
|
||||
* @see java.lang.Thread#Thread(java.lang.ThreadGroup,
|
||||
* java.lang.Runnable, java.lang.String)
|
||||
*/
|
||||
public SessionThread(Session session, ThreadGroup group, Runnable target,
|
||||
String name)
|
||||
{
|
||||
super(group, target, name);
|
||||
this.session = session;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,977 @@
|
||||
//-< Table.java >----------------------------------------------------*--------*
|
||||
// JORA Version 2.0 (c) 1998 GARRET * ? *
|
||||
// (Java Object Relational Adapter) * /\| *
|
||||
// * / \ *
|
||||
// Created: 10-Jun-98 K.A. Knizhnik * / [] \ *
|
||||
// Last update: 20-Jun-98 K.A. Knizhnik * GARRET *
|
||||
//-------------------------------------------------------------------*--------*
|
||||
// Class representing database table
|
||||
//-------------------------------------------------------------------*--------*
|
||||
|
||||
package com.samskivert.jdbc.jora;
|
||||
|
||||
import java.util.*;
|
||||
import java.sql.*;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
/** Table class is used to establish mapping between corteges of database
|
||||
* tables and Java classes. This class is responsible for constructing
|
||||
* SQL statements for extracting, updating and deleting records of the
|
||||
* database table.
|
||||
*/
|
||||
public class Table {
|
||||
/** Constructor for table object. Make association between Java class
|
||||
* and database table.
|
||||
*
|
||||
* @param tclassName name of Java class
|
||||
* @param tableName name of database table mapped on this Java class
|
||||
* @param key table's primary key. This parameter is used in UPDATE/DELETE
|
||||
* operations to locate record in the table.
|
||||
* @s session, which should be opened before first access to the table
|
||||
*/
|
||||
public Table(String className, String tableName, Session s, String key) {
|
||||
String[] keys = {key};
|
||||
init(className, tableName, s, keys);
|
||||
}
|
||||
|
||||
/** Constructor for table object. Make association between Java class
|
||||
* and database table.
|
||||
*
|
||||
* @param tclassName name of Java class
|
||||
* @param tableName name of database table mapped on this Java class
|
||||
* @param keys table primary keys. This parameter is used in UPDATE/DELETE
|
||||
* operations to locate record in the table.
|
||||
* @s session, which should be opened before first access to the table
|
||||
*/
|
||||
public Table(String className, String tableName, Session s, String[] keys)
|
||||
{
|
||||
init(className, tableName, s, keys);
|
||||
}
|
||||
|
||||
/** Constructor for table object. Make association between Java class
|
||||
* and database table. Name of Java class should be the same as name of
|
||||
* the database table
|
||||
*
|
||||
* @param className name of Java class, which should be (without
|
||||
* package prefix) be the same as the name of database table.
|
||||
* @param keys table primary keys. This parameter is used in UPDATE/DELETE
|
||||
* operations to locate record in the table.
|
||||
* @s session, which should be opened before first access to the table
|
||||
*/
|
||||
public Table(String className, Session s, String[] keys) {
|
||||
init(className, className.substring(className.lastIndexOf('.')+1),
|
||||
s, keys);
|
||||
}
|
||||
|
||||
/** Constructor for table object. Make association between Java class
|
||||
* and database table. Name of Java class should be the same as name of
|
||||
* the database table
|
||||
*
|
||||
* @param className name of Java class, which should be (without
|
||||
* package prefix) be the same as the name of database table.
|
||||
* @param key table primary key. This parameter is used in UPDATE/DELETE
|
||||
* operations to locate record in the table.
|
||||
* @s session, which should be opened before first access to the table
|
||||
*/
|
||||
public Table(String className, Session s, String key) {
|
||||
String[] keys = {key};
|
||||
init(className, className.substring(className.lastIndexOf('.')+1),
|
||||
s, keys);
|
||||
}
|
||||
|
||||
/** Constructor of table without explicit key specification.
|
||||
* Specification of key is necessary for update/remove operations.
|
||||
* If key is not specified, it is inherited from base table (if any).
|
||||
*/
|
||||
public Table(String className, Session s) {
|
||||
init(className, className.substring(className.lastIndexOf('.')+1),
|
||||
s, null);
|
||||
}
|
||||
|
||||
|
||||
/** Constructor of table with "key" and "session" parameters inherited
|
||||
* from base table.
|
||||
*/
|
||||
public Table(String className) {
|
||||
init(className, className.substring(className.lastIndexOf('.')+1),
|
||||
null, null);
|
||||
}
|
||||
|
||||
|
||||
/** Select records from database table according to search condition
|
||||
*
|
||||
* @param condition valid SQL condition expression started with WHERE
|
||||
* or empty string if all records should be fetched.
|
||||
*/
|
||||
public final Cursor select(String condition) {
|
||||
return new Cursor(this, session, 1, condition);
|
||||
}
|
||||
|
||||
/** Select records from database table according to search condition
|
||||
*
|
||||
* @param condition valid SQL condition expression started with WHERE
|
||||
* or empty string if all records should be fetched.
|
||||
* @param session user database session
|
||||
*/
|
||||
public final Cursor select(String condition, Session session) {
|
||||
return new Cursor(this, session, 1, condition);
|
||||
}
|
||||
|
||||
/** Select records from specified and derived database tables
|
||||
*
|
||||
* @param condition valid SQL condition expression started with WHERE
|
||||
* or empty string if all records should be fetched.
|
||||
*/
|
||||
public final Cursor selectAll(String condition) {
|
||||
return new Cursor(this, session, nDerived+1, condition);
|
||||
}
|
||||
|
||||
/** Select records from specified and derived database tables
|
||||
*
|
||||
* @param condition valid SQL condition expression started with WHERE
|
||||
* or empty string if all records should be fetched.
|
||||
* @param session user database session
|
||||
*/
|
||||
public final Cursor selectAll(String condition, Session session) {
|
||||
return new Cursor(this, session, nDerived+1, condition);
|
||||
}
|
||||
|
||||
|
||||
/** Select records from database table using <I>obj</I> object as
|
||||
* template for selection. All non-builtin fields of this object,
|
||||
* which are not null, are compared with correspondent table values.
|
||||
*
|
||||
* @param obj object for construction search condition: selected objects
|
||||
* should match all non-null fields of specified object.
|
||||
*/
|
||||
public final Cursor queryByExample(Object obj) {
|
||||
return new Cursor(this, session, 1, obj);
|
||||
}
|
||||
|
||||
/** Select records from database table using <I>obj</I> object as
|
||||
* template for selection. All non-builtin fields of this object,
|
||||
* which are not null, are compared with correspondent table values.
|
||||
*
|
||||
* @param obj object for construction search condition: selected objects
|
||||
* should match all non-null fields of specified object.
|
||||
* @param session user database session
|
||||
*/
|
||||
public final Cursor queryByExample(Object obj, Session session) {
|
||||
return new Cursor(this, session, 1, obj);
|
||||
}
|
||||
|
||||
/** Select records from specified and derived database tables using
|
||||
* <I>obj</I> object as template for selection.
|
||||
* All non-builtin fields of this object,
|
||||
* which are not null, are compared with correspondent table values.
|
||||
*
|
||||
* @param obj object for construction search condition: selected objects
|
||||
* should match all non-null fields of specified object.
|
||||
*/
|
||||
public final Cursor queryAllByExample(Object obj) {
|
||||
return new Cursor(this, session, nDerived+1, obj);
|
||||
}
|
||||
|
||||
/** Select records from specified and derived database tables using
|
||||
* <I>obj</I> object as template for selection.
|
||||
* All non-builtin fields of this object,
|
||||
* which are not null, are compared with correspondent table values.
|
||||
*
|
||||
* @param obj object for construction search condition: selected objects
|
||||
* should match all non-null fields of specified object.
|
||||
* @param session user database session
|
||||
*/
|
||||
public final Cursor queryAllByExample(Object obj, Session session) {
|
||||
return new Cursor(this, session, nDerived+1, obj);
|
||||
}
|
||||
|
||||
/** Insert new record in the table. Values of inserted record fields
|
||||
* are taken from specifed object.
|
||||
*
|
||||
* @param obj object specifing values of inserted record fields
|
||||
*/
|
||||
public void insert(Object obj)
|
||||
throws SQLException
|
||||
{
|
||||
insert(obj, session);
|
||||
}
|
||||
|
||||
/** Insert new record in the table using specified database session.
|
||||
* Values of inserted record fields
|
||||
* are taken from specifed object.
|
||||
*
|
||||
* @param obj object specifing values of inserted record fields
|
||||
* @param session user database session
|
||||
*/
|
||||
public synchronized void insert(Object obj, Session session)
|
||||
throws SQLException
|
||||
{
|
||||
if (session == null) {
|
||||
session = ((SessionThread)Thread.currentThread()).session;
|
||||
}
|
||||
// try {
|
||||
checkConnection(session);
|
||||
if (insertStmt == null) {
|
||||
String sql = "insert into " + name + " ("
|
||||
+ listOfFields + ") values (?";
|
||||
for (int i = 1; i < nColumns; i++) {
|
||||
sql += ",?";
|
||||
}
|
||||
sql += ")";
|
||||
insertStmt = session.connection.prepareStatement(sql);
|
||||
}
|
||||
bindUpdateVariables(insertStmt, obj);
|
||||
insertStmt.executeUpdate();
|
||||
insertStmt.clearParameters();
|
||||
// } catch(SQLException ex) { session.handleSQLException(ex); }
|
||||
}
|
||||
|
||||
/** Insert several new records in the table. Values of inserted records
|
||||
* fields are taken from objects of specified array.
|
||||
*
|
||||
* @param objects array with objects specifing values of inserted record
|
||||
* fields
|
||||
*/
|
||||
public void insert(Object[] objects)
|
||||
throws SQLException
|
||||
{
|
||||
insert(objects, session);
|
||||
}
|
||||
|
||||
/** Insert several new records in the table. Values of inserted records
|
||||
* fields are taken from objects of specified array.
|
||||
*
|
||||
* @param objects array with objects specifing values of inserted record
|
||||
* fields
|
||||
* @param session user database session
|
||||
*/
|
||||
public synchronized void insert(Object[] objects, Session session)
|
||||
throws SQLException
|
||||
{
|
||||
if (session == null) {
|
||||
session = ((SessionThread)Thread.currentThread()).session;
|
||||
}
|
||||
// try {
|
||||
checkConnection(session);
|
||||
if (insertStmt == null) {
|
||||
String sql = "insert into " + name + " ("
|
||||
+ listOfFields + ") values (?";
|
||||
for (int i = 1; i < nColumns; i++) {
|
||||
sql += ",?";
|
||||
}
|
||||
sql += ")";
|
||||
insertStmt = session.connection.prepareStatement(sql);
|
||||
}
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
bindUpdateVariables(insertStmt, objects[i]);
|
||||
insertStmt.addBatch();
|
||||
}
|
||||
insertStmt.executeBatch();
|
||||
insertStmt.clearParameters();
|
||||
// } catch(SQLException ex) { session.handleSQLException(ex); }
|
||||
}
|
||||
|
||||
/** Update record in the table using table's primary key to locate
|
||||
* record in the table and values of fields of specified object <I>obj</I>
|
||||
* to alter record fields.
|
||||
*
|
||||
* @param obj object specifing value of primary key and new values of
|
||||
* updated record fields
|
||||
*
|
||||
* @return number of objects actually updated
|
||||
*/
|
||||
public int update(Object obj)
|
||||
throws SQLException
|
||||
{
|
||||
return update(obj, session);
|
||||
}
|
||||
|
||||
/** Update record in the table using table's primary key to locate
|
||||
* record in the table and values of fields of specified object <I>obj</I>
|
||||
* to alter record fields.
|
||||
*
|
||||
* @param obj object specifing value of primary key and new values of
|
||||
* updated record fields
|
||||
* @param session user database session
|
||||
*
|
||||
* @return number of objects actually updated
|
||||
*/
|
||||
public synchronized int update(Object obj, Session session)
|
||||
throws SQLException
|
||||
{
|
||||
if (primaryKeys == null) {
|
||||
throw new NoPrimaryKeyError(this);
|
||||
}
|
||||
if (session == null) {
|
||||
session = ((SessionThread)Thread.currentThread()).session;
|
||||
}
|
||||
int nUpdated = 0;
|
||||
// try {
|
||||
checkConnection(session);
|
||||
if (updateStmt == null) {
|
||||
String sql = "update " + name + " set " + listOfAssignments
|
||||
+ " where " + primaryKeys[0] + " = ?";
|
||||
for (int i = 1; i < primaryKeys.length; i++) {
|
||||
sql += " and " + primaryKeys[i] + " = ?";
|
||||
}
|
||||
updateStmt = session.connection.prepareStatement(sql);
|
||||
}
|
||||
for (int i = 0; i < primaryKeys.length; i++) {
|
||||
fields[primaryKeyIndices[i]].bindVariable(updateStmt, obj,
|
||||
nColumns+i+1);
|
||||
}
|
||||
bindUpdateVariables(updateStmt, obj);
|
||||
nUpdated = updateStmt.executeUpdate();
|
||||
updateStmt.clearParameters();
|
||||
// } catch(SQLException ex) { session.handleSQLException(ex); }
|
||||
return nUpdated;
|
||||
}
|
||||
|
||||
/** Update set of records in the table using table's primary key to locate
|
||||
* record in the table and values of fields of objects from sepecifed
|
||||
* array <I>objects</I> to alter record fields.
|
||||
*
|
||||
* @param objects array of objects specifing primiray keys and and new
|
||||
* values of updated record fields
|
||||
*
|
||||
* @return number of objects actually updated
|
||||
*/
|
||||
public int update(Object[] objects)
|
||||
throws SQLException
|
||||
{
|
||||
return update(objects, session);
|
||||
}
|
||||
|
||||
/** Update set of records in the table using table's primary key to locate
|
||||
* record in the table and values of fields of objects from sepecifed
|
||||
* array <I>objects</I> to alter record fields.
|
||||
*
|
||||
* @param objects array of objects specifing primiray keys and and new
|
||||
* values of updated record fields
|
||||
* @param session user database session
|
||||
*
|
||||
* @return number of objects actually updated
|
||||
*/
|
||||
public synchronized int update(Object[] objects, Session session)
|
||||
throws SQLException
|
||||
{
|
||||
if (primaryKeys == null) {
|
||||
throw new NoPrimaryKeyError(this);
|
||||
}
|
||||
if (session == null) {
|
||||
session = ((SessionThread)Thread.currentThread()).session;
|
||||
}
|
||||
int nUpdated = 0;
|
||||
// try {
|
||||
checkConnection(session);
|
||||
if (updateStmt == null) {
|
||||
String sql = "update " + name + " set " + listOfAssignments
|
||||
+ " where " + primaryKeys[0] + " = ?";
|
||||
for (int i = 1; i < primaryKeys.length; i++) {
|
||||
sql += " and " + primaryKeys[i] + " = ?";
|
||||
}
|
||||
updateStmt = session.connection.prepareStatement(sql);
|
||||
}
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
for (int j = 0; j < primaryKeys.length; j++) {
|
||||
fields[primaryKeyIndices[j]].bindVariable(updateStmt,
|
||||
objects[i],
|
||||
nColumns+1+j);
|
||||
}
|
||||
bindUpdateVariables(updateStmt, objects[i]);
|
||||
updateStmt.addBatch();
|
||||
}
|
||||
int rc[] = updateStmt.executeBatch();
|
||||
for (int k = 0; k < rc.length; k++) {
|
||||
nUpdated += rc[k];
|
||||
}
|
||||
updateStmt.clearParameters();
|
||||
// } catch(SQLException ex) { session.handleSQLException(ex); }
|
||||
return nUpdated;
|
||||
}
|
||||
|
||||
/** Delete record with specified value of primary key from the table.
|
||||
*
|
||||
* @param obj object containing value of primary key.
|
||||
*
|
||||
* @return number of objects actually deleted
|
||||
*/
|
||||
public int delete(Object obj)
|
||||
throws SQLException
|
||||
{
|
||||
return delete(obj, session);
|
||||
}
|
||||
|
||||
/** Delete record with specified value of primary key from the table.
|
||||
*
|
||||
* @param obj object containing value of primary key.
|
||||
* @param session user database session
|
||||
*/
|
||||
public synchronized int delete(Object obj, Session session)
|
||||
throws SQLException
|
||||
{
|
||||
if (primaryKeys == null) {
|
||||
throw new NoPrimaryKeyError(this);
|
||||
}
|
||||
if (session == null) {
|
||||
session = ((SessionThread)Thread.currentThread()).session;
|
||||
}
|
||||
int nDeleted = 0;
|
||||
// try {
|
||||
checkConnection(session);
|
||||
if (deleteStmt == null) {
|
||||
String sql = "delete from " + name +
|
||||
" where " + primaryKeys[0] + " = ?";
|
||||
for (int i = 1; i < primaryKeys.length; i++) {
|
||||
sql += " and " + primaryKeys[i] + " = ?";
|
||||
}
|
||||
deleteStmt = session.connection.prepareStatement(sql);
|
||||
}
|
||||
for (int i = 0; i < primaryKeys.length; i++) {
|
||||
fields[primaryKeyIndices[i]].bindVariable(deleteStmt, obj,i+1);
|
||||
}
|
||||
nDeleted = deleteStmt.executeUpdate();
|
||||
deleteStmt.clearParameters();
|
||||
// } catch(SQLException ex) { session.handleSQLException(ex); }
|
||||
return nDeleted;
|
||||
}
|
||||
|
||||
|
||||
/** Delete records with specified primary keys from the table.
|
||||
*
|
||||
* @param objects array of objects containing values of primary key.
|
||||
*
|
||||
* @return number of objects actually deleted
|
||||
*/
|
||||
public int delete(Object[] objects)
|
||||
throws SQLException
|
||||
{
|
||||
return delete(objects, session);
|
||||
}
|
||||
|
||||
/** Delete records with specified primary keys from the table.
|
||||
*
|
||||
* @param objects array of objects containing values of primary key.
|
||||
*
|
||||
* @return number of objects actually deleted
|
||||
*/
|
||||
public synchronized int delete(Object[] objects, Session session)
|
||||
throws SQLException
|
||||
{
|
||||
if (primaryKeys == null) {
|
||||
throw new NoPrimaryKeyError(this);
|
||||
}
|
||||
if (session == null) {
|
||||
session = ((SessionThread)Thread.currentThread()).session;
|
||||
}
|
||||
int nDeleted = 0;
|
||||
// try {
|
||||
checkConnection(session);
|
||||
if (deleteStmt == null) {
|
||||
String sql = "delete from " + name +
|
||||
" where " + primaryKeys[0] + " = ?";
|
||||
for (int i = 1; i < primaryKeys.length; i++) {
|
||||
sql += " and " + primaryKeys[i] + " = ?";
|
||||
}
|
||||
deleteStmt = session.connection.prepareStatement(sql);
|
||||
}
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
for (int j = 0; j < primaryKeys.length; j++) {
|
||||
fields[primaryKeyIndices[j]].bindVariable(deleteStmt,
|
||||
objects[i], j+1);
|
||||
}
|
||||
deleteStmt.addBatch();
|
||||
}
|
||||
int rc[] = deleteStmt.executeBatch();
|
||||
for (int k = 0; k < rc.length; k++) {
|
||||
nDeleted += rc[k];
|
||||
}
|
||||
deleteStmt.clearParameters();
|
||||
// } catch(SQLException ex) { session.handleSQLException(ex); }
|
||||
return nDeleted;
|
||||
}
|
||||
|
||||
/** Spearator of name components of compound field. For example, if Java
|
||||
* class constains component "location" of Point class, which
|
||||
* has two components "x" and "y", then database table should
|
||||
* have columns "location_x" and "location_y" (if '_' is used
|
||||
* as separator)
|
||||
*/
|
||||
public static String fieldSeparator = "_";
|
||||
|
||||
|
||||
/** Some versions of JDBC driver doesn't support
|
||||
* <code>getBigDecimal(int columnIndex)</code>. Setting this variable to
|
||||
* <code>true</code> makes JORA to explicitly request scale from result
|
||||
* set metadata and use deprecated version of <code>getBigDecimal</code>
|
||||
* with extra <code>scale</code> parameter.
|
||||
*/
|
||||
public static boolean useDepricatedGetBigDecimal = true;
|
||||
|
||||
|
||||
// --- Implementation -----------------------------------------
|
||||
|
||||
/** Is table abstract - not present in database.
|
||||
*/
|
||||
protected boolean isAbstract;
|
||||
protected Table derived;
|
||||
protected int nDerived;
|
||||
|
||||
protected String name;
|
||||
protected String listOfFields;
|
||||
protected String listOfAssignments;
|
||||
protected Class cls;
|
||||
protected Session session;
|
||||
|
||||
static private Class serializableClass;
|
||||
private FieldDescriptor[] fields;
|
||||
|
||||
private int nFields; // length of "fields" array
|
||||
private int nColumns; // number of atomic fields in "fields" array
|
||||
|
||||
private String primaryKeys[];
|
||||
private int primaryKeyIndices[];
|
||||
|
||||
protected int connectionID;
|
||||
|
||||
private PreparedStatement updateStmt;
|
||||
private PreparedStatement deleteStmt;
|
||||
private PreparedStatement insertStmt;
|
||||
|
||||
private static Table allTables;
|
||||
private Constructor constructor;
|
||||
private static Method setBypass;
|
||||
|
||||
private static final Object[] bypassFlag = { new Boolean(true) };
|
||||
private static final Object[] constructorArgs = {};
|
||||
|
||||
static {
|
||||
try {
|
||||
serializableClass = Class.forName("java.io.Serializable");
|
||||
Class c = Class.forName("java.lang.reflect.AccessibleObject");
|
||||
Class[] param = { Boolean.TYPE };
|
||||
setBypass = c.getMethod("setAccessible", param);
|
||||
} catch(Exception ex) {}
|
||||
}
|
||||
|
||||
|
||||
private final void init(String className, String tableName, Session s,
|
||||
String[] keys)
|
||||
{
|
||||
name = tableName;
|
||||
try {
|
||||
cls = Class.forName(className);
|
||||
} catch(ClassNotFoundException ex) {throw new NoClassDefFoundError();}
|
||||
isAbstract = tableName == null;
|
||||
session = s;
|
||||
primaryKeys = keys;
|
||||
listOfFields = "";
|
||||
listOfAssignments = "";
|
||||
connectionID = 0;
|
||||
Vector fieldsVector = new Vector();
|
||||
nFields = buildFieldsList(fieldsVector, cls, "");
|
||||
fields = new FieldDescriptor[nFields];
|
||||
fieldsVector.copyInto(fields);
|
||||
|
||||
try {
|
||||
constructor = cls.getDeclaredConstructor(new Class[0]);
|
||||
setBypass.invoke(constructor, bypassFlag);
|
||||
} catch(Exception ex) {}
|
||||
|
||||
if (keys != null) {
|
||||
if (keys.length == 0) {
|
||||
throw new NoPrimaryKeyError(this);
|
||||
}
|
||||
primaryKeyIndices = new int[keys.length];
|
||||
for (int j = keys.length; --j >= 0;) {
|
||||
int i = nFields;
|
||||
while (--i >= 0) {
|
||||
if (fields[i].name.equals(keys[j])) {
|
||||
if (!fields[i].isAtomic()) {
|
||||
throw new NoPrimaryKeyError(this);
|
||||
}
|
||||
primaryKeyIndices[j] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < 0) {
|
||||
throw new NoSuchFieldError("No such field '" + keys[j]
|
||||
+ "' in table " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
insertIntoTableHierarchy();
|
||||
}
|
||||
|
||||
|
||||
private final void insertIntoTableHierarchy()
|
||||
{
|
||||
Table t, prev = null;
|
||||
Table after = null;
|
||||
int nChilds = 0;
|
||||
for (t = allTables; t != null; prev = t, t = t.derived) {
|
||||
if (t.cls.isAssignableFrom(cls)) {
|
||||
if (primaryKeys == null && t.primaryKeys != null) {
|
||||
primaryKeys = t.primaryKeys;
|
||||
primaryKeyIndices = t.primaryKeyIndices;
|
||||
}
|
||||
if (session == null) {
|
||||
session = t.session;
|
||||
}
|
||||
t.nDerived += 1;
|
||||
after = t;
|
||||
} else if (cls.isAssignableFrom(t.cls)) {
|
||||
after = prev;
|
||||
do {
|
||||
if (cls.isAssignableFrom(t.cls)) {
|
||||
if (primaryKeys != null && t.primaryKeys == null) {
|
||||
t.primaryKeys = primaryKeys;
|
||||
t.primaryKeyIndices = primaryKeyIndices;
|
||||
}
|
||||
if (t.session == null) {
|
||||
t.session = session;
|
||||
}
|
||||
nChilds += 1;
|
||||
}
|
||||
} while ((t = t.derived) != null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (after == null) {
|
||||
derived = allTables;
|
||||
allTables = this;
|
||||
} else {
|
||||
derived = after.derived;
|
||||
after.derived = this;
|
||||
}
|
||||
nDerived = nChilds;
|
||||
}
|
||||
|
||||
private final void checkConnection(Session s) throws SQLException {
|
||||
if (connectionID != s.connectionID) {
|
||||
if (insertStmt != null) {
|
||||
insertStmt.close();
|
||||
insertStmt = null;
|
||||
}
|
||||
if (updateStmt != null) {
|
||||
updateStmt.close();
|
||||
updateStmt = null;
|
||||
}
|
||||
if (deleteStmt != null) {
|
||||
deleteStmt.close();
|
||||
deleteStmt = null;
|
||||
}
|
||||
connectionID = s.connectionID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final int buildFieldsList(Vector buf, Class cls, String prefix)
|
||||
{
|
||||
Field[] f = cls.getDeclaredFields();
|
||||
|
||||
Class superclass = cls;
|
||||
while ((superclass = superclass.getSuperclass()) != null) {
|
||||
Field[] inheritedFields = superclass.getDeclaredFields();
|
||||
Field[] allFields = new Field[inheritedFields.length + f.length];
|
||||
System.arraycopy(inheritedFields, 0, allFields, 0,
|
||||
inheritedFields.length);
|
||||
System.arraycopy(f,0, allFields, inheritedFields.length, f.length);
|
||||
f = allFields;
|
||||
}
|
||||
|
||||
try {
|
||||
for (int i = f.length; --i>= 0;) {
|
||||
setBypass.invoke(f[i], bypassFlag);
|
||||
}
|
||||
} catch(Exception ex) {
|
||||
System.err.println("Failed to set bypass attribute");
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
for (int i = 0; i < f.length; i++) {
|
||||
if ((f[i].getModifiers()&(Modifier.TRANSIENT|Modifier.STATIC))==0)
|
||||
{
|
||||
String name = f[i].getName();
|
||||
Class fieldClass = f[i].getType();
|
||||
String fullName = prefix + name;
|
||||
FieldDescriptor fd = new FieldDescriptor(f[i], fullName);
|
||||
int type;
|
||||
|
||||
buf.addElement(fd);
|
||||
n += 1;
|
||||
|
||||
String c = fieldClass.getName();
|
||||
if (c.equals("byte")) type = FieldDescriptor.t_byte;
|
||||
else if (c.equals("short")) type = FieldDescriptor.t_short;
|
||||
else if (c.equals("int")) type = FieldDescriptor.t_int;
|
||||
else if (c.equals("long")) type = FieldDescriptor.t_long;
|
||||
else if (c.equals("float")) type = FieldDescriptor.t_float;
|
||||
else if (c.equals("double")) type = FieldDescriptor.t_double;
|
||||
else if (c.equals("boolean")) type = FieldDescriptor.t_boolean;
|
||||
else if (c.equals("java.lang.Byte"))
|
||||
type = FieldDescriptor.tByte;
|
||||
else if (c.equals("java.lang.Short"))
|
||||
type = FieldDescriptor.tShort;
|
||||
else if (c.equals("java.lang.Integer"))
|
||||
type = FieldDescriptor.tInteger;
|
||||
else if (c.equals("java.lang.Long"))
|
||||
type = FieldDescriptor.tLong;
|
||||
else if (c.equals("java.lang.Float"))
|
||||
type = FieldDescriptor.tFloat;
|
||||
else if (c.equals("java.lang.Double"))
|
||||
type = FieldDescriptor.tDouble;
|
||||
else if (c.equals("java.lang.Boolean"))
|
||||
type = FieldDescriptor.tBoolean;
|
||||
else if (c.equals("java.math.BigDecimal"))
|
||||
type = FieldDescriptor.tDecimal;
|
||||
else if (c.equals("java.lang.String"))
|
||||
type = FieldDescriptor.tString;
|
||||
else if (c.equals("java.lang.[B"))
|
||||
type = FieldDescriptor.tBytes;
|
||||
else if (c.equals("java.sql.Date"))
|
||||
type = FieldDescriptor.tDate;
|
||||
else if (c.equals("java.sql.Time"))
|
||||
type = FieldDescriptor.tTime;
|
||||
else if (c.equals("java.sql.Timestamp"))
|
||||
type = FieldDescriptor.tTimestamp;
|
||||
else if (c.equals("java.lang.InputStream"))
|
||||
type = FieldDescriptor.tStream;
|
||||
else if (c.equals("java.sql.BlobLocator"))
|
||||
type = FieldDescriptor.tBlob;
|
||||
else if (c.equals("java.sql.ClobLocator"))
|
||||
type = FieldDescriptor.tClob;
|
||||
else if (serializableClass.isAssignableFrom(fieldClass))
|
||||
type = FieldDescriptor.tClosure;
|
||||
else {
|
||||
int nComponents = buildFieldsList(buf, fieldClass,
|
||||
fd.name+fieldSeparator);
|
||||
fd.inType = fd.outType =
|
||||
FieldDescriptor.tCompound + nComponents;
|
||||
|
||||
try {
|
||||
fd.constructor =
|
||||
fieldClass.getDeclaredConstructor(new Class[0]);
|
||||
setBypass.invoke(fd.constructor, bypassFlag);
|
||||
} catch(Exception ex) {}
|
||||
|
||||
n += nComponents;
|
||||
continue;
|
||||
}
|
||||
if (listOfFields.length() != 0) {
|
||||
listOfFields += ",";
|
||||
listOfAssignments += ",";
|
||||
}
|
||||
listOfFields += fullName;
|
||||
listOfAssignments += fullName + "=?";
|
||||
|
||||
fd.inType = fd.outType = type;
|
||||
nColumns += 1;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
protected final Object load(ResultSet result) throws SQLException {
|
||||
Object obj;
|
||||
try {
|
||||
obj = constructor.newInstance(constructorArgs);
|
||||
}
|
||||
catch(IllegalAccessException ex) { throw new IllegalAccessError(); }
|
||||
catch(InstantiationException ex) { throw new InstantiationError(); }
|
||||
catch(Exception ex) {
|
||||
throw new InstantiationError("Exception was thrown by constructor");
|
||||
}
|
||||
load(obj, 0, nFields, 0, result);
|
||||
return obj;
|
||||
}
|
||||
|
||||
private final int load(Object obj, int i, int end, int column,
|
||||
ResultSet result)
|
||||
throws SQLException
|
||||
{
|
||||
try {
|
||||
while (i < end) {
|
||||
FieldDescriptor fd = fields[i++];
|
||||
if (!fd.loadVariable(result, obj, ++column)) {
|
||||
Object component =
|
||||
fd.constructor.newInstance(constructorArgs);
|
||||
fd.field.set(obj, component);
|
||||
int nComponents = fd.inType - FieldDescriptor.tCompound;
|
||||
column = load(component, i, i + nComponents,
|
||||
column-1, result);
|
||||
i += nComponents;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(IllegalAccessException ex) { throw new IllegalAccessError(); }
|
||||
catch(InstantiationException ex) { throw new InstantiationError(); }
|
||||
catch(InvocationTargetException ex) {
|
||||
throw new InstantiationError("Exception was thrown by constructor");
|
||||
}
|
||||
return column;
|
||||
}
|
||||
|
||||
protected final void bindUpdateVariables(PreparedStatement pstmt,
|
||||
Object obj)
|
||||
throws SQLException
|
||||
{
|
||||
bindUpdateVariables(pstmt, obj, 0, nFields, 0);
|
||||
}
|
||||
|
||||
protected final void bindQueryVariables(PreparedStatement pstmt,
|
||||
Object obj)
|
||||
throws SQLException
|
||||
{
|
||||
bindQueryVariables(pstmt, obj, 0, nFields, 0);
|
||||
}
|
||||
|
||||
|
||||
protected final void updateVariables(ResultSet result, Object obj)
|
||||
throws SQLException
|
||||
{
|
||||
updateVariables(result, obj, 0, nFields, 0);
|
||||
result.updateRow();
|
||||
}
|
||||
|
||||
|
||||
protected final String buildQueryList(Object qbe)
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buildQueryList(buf, qbe, 0, nFields);
|
||||
String condition = buf.toString();
|
||||
return condition.length() != 0 ? " where " + condition : "";
|
||||
}
|
||||
|
||||
|
||||
private final int bindUpdateVariables(PreparedStatement pstmt, Object obj,
|
||||
int i, int end, int column)
|
||||
throws SQLException
|
||||
{
|
||||
try {
|
||||
while (i < end) {
|
||||
FieldDescriptor fd = fields[i++];
|
||||
Object comp = null;
|
||||
if (!fd.isBuiltin() && (comp = fd.field.get(obj)) == null) {
|
||||
if (fd.isCompound()) {
|
||||
int nComponents = fd.outType-FieldDescriptor.tCompound;
|
||||
while (--nComponents >= 0) {
|
||||
fd = fields[i++];
|
||||
if (!fd.isCompound()) {
|
||||
pstmt.setNull(++column,
|
||||
FieldDescriptor.sqlTypeMapping[fd.outType]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pstmt.setNull(++column,
|
||||
FieldDescriptor.sqlTypeMapping[fd.outType]);
|
||||
}
|
||||
} else {
|
||||
if (!fd.bindVariable(pstmt, obj, ++column)) {
|
||||
int nComponents = fd.outType-FieldDescriptor.tCompound;
|
||||
column = bindUpdateVariables(pstmt, comp,
|
||||
i,i+nComponents,column-1);
|
||||
i += nComponents;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(IllegalAccessException ex) { throw new IllegalAccessError(); }
|
||||
return column;
|
||||
}
|
||||
|
||||
private final int bindQueryVariables(PreparedStatement pstmt, Object obj,
|
||||
int i, int end, int column)
|
||||
throws SQLException
|
||||
{
|
||||
try {
|
||||
while (i < end) {
|
||||
Object comp;
|
||||
FieldDescriptor fd = fields[i++];
|
||||
if (!fd.field.getDeclaringClass().isInstance(obj)) {
|
||||
return column;
|
||||
}
|
||||
int nComponents =
|
||||
fd.isCompound() ? fd.outType-FieldDescriptor.tCompound : 0;
|
||||
if (!fd.isBuiltin()
|
||||
&& fd.outType != FieldDescriptor.tClosure
|
||||
&& (comp = fd.field.get(obj)) != null)
|
||||
{
|
||||
if (!fd.bindVariable(pstmt, obj, ++column)) {
|
||||
column = bindQueryVariables(pstmt, comp,
|
||||
i,i+nComponents,column-1);
|
||||
}
|
||||
}
|
||||
i += nComponents;
|
||||
}
|
||||
} catch(IllegalAccessException ex) { throw new IllegalAccessError(); }
|
||||
return column;
|
||||
}
|
||||
|
||||
private final void buildQueryList(StringBuffer buf, Object qbe,
|
||||
int i, int end)
|
||||
{
|
||||
try {
|
||||
while (i < end) {
|
||||
Object comp;
|
||||
FieldDescriptor fd = fields[i++];
|
||||
int nComponents =
|
||||
fd.isCompound() ? fd.outType-FieldDescriptor.tCompound : 0;
|
||||
if (!fd.isBuiltin()
|
||||
&& fd.outType != FieldDescriptor.tClosure
|
||||
&& (comp = fd.field.get(qbe)) != null)
|
||||
{
|
||||
if (nComponents != 0) {
|
||||
buildQueryList(buf, comp, i, i+nComponents);
|
||||
} else {
|
||||
if (buf.length() != 0) {
|
||||
buf.append(",");
|
||||
}
|
||||
buf.append(fd.name);
|
||||
buf.append("=?");
|
||||
}
|
||||
}
|
||||
i += nComponents;
|
||||
}
|
||||
} catch(IllegalAccessException ex) { throw new IllegalAccessError(); }
|
||||
}
|
||||
|
||||
protected final int updateVariables(ResultSet result, Object obj,
|
||||
int i, int end, int column)
|
||||
throws SQLException
|
||||
{
|
||||
try {
|
||||
while (i < end) {
|
||||
FieldDescriptor fd = fields[i++];
|
||||
Object comp = null;
|
||||
if (!fd.isBuiltin() && (comp = fd.field.get(obj)) == null) {
|
||||
if (fd.isCompound()) {
|
||||
int nComponents = fd.outType-FieldDescriptor.tCompound;
|
||||
while (--nComponents >= 0) {
|
||||
fd = fields[i++];
|
||||
if (!fd.isCompound()) {
|
||||
result.updateNull(++column);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result.updateNull(++column);
|
||||
}
|
||||
} else {
|
||||
if (!fd.updateVariable(result, obj, ++column)) {
|
||||
int nComponents = fd.outType-FieldDescriptor.tCompound;
|
||||
column = updateVariables(result, comp,
|
||||
i, i+nComponents, column-1);
|
||||
i += nComponents;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(IllegalAccessException ex) { throw new IllegalAccessError(); }
|
||||
return column;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user