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