Revamped JORA to avoid keeping connection objects around which is not thread
safe and particularly not so in the webapp where one thread might come slip a read-only connection into the session before an update was about to happen. This ends up being a giant refactor, but it's much cleaner this way (to pass a connection into the Table whenever it is doing anything), so I've taken the pain. Fortuanately, code that uses the convenience methods doesn't need to change, so as a part of this refactor I've taken the opportunity to switch a bunch of old stuff to the new, concise, future proof hotness. git-svn-id: https://samskivert.googlecode.com/svn/trunk@1830 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -30,7 +30,7 @@ import com.samskivert.jdbc.jora.*;
|
||||
* The JORA repository simplifies the process of building persistence
|
||||
* services that make use of the JORA object relational mapping package.
|
||||
*
|
||||
* @see com.samskivert.jdbc.jora.Session
|
||||
* @see com.samskivert.jdbc.jora.Table
|
||||
*/
|
||||
public abstract class JORARepository extends SimpleRepository
|
||||
{
|
||||
@@ -47,17 +47,12 @@ public abstract class JORARepository extends SimpleRepository
|
||||
{
|
||||
super(provider, dbident);
|
||||
|
||||
// our parent class will have already obtained a database connection
|
||||
// and therefore ended up calling getConnection() which will create our
|
||||
// session, so we can make use of it straight away
|
||||
|
||||
// create our tables
|
||||
createTables(_session);
|
||||
createTables();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the supplied object into the specified table. The table must be
|
||||
* configured to store items of the supplied type.
|
||||
* Inserts the supplied object into the specified table.
|
||||
*
|
||||
* @return a call to {@link DatabaseLiaison#lastInsertedId} made
|
||||
* immediately following the insert.
|
||||
@@ -69,15 +64,14 @@ public abstract class JORARepository extends SimpleRepository
|
||||
public Integer invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
table.insert(object);
|
||||
table.insert(conn, object);
|
||||
return liaison.lastInsertedId(conn);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the supplied object in the specified table. The table must
|
||||
* be configured to store items of the supplied type.
|
||||
* Updates the supplied object in the specified table.
|
||||
*
|
||||
* @return the number of rows modified by the update.
|
||||
*/
|
||||
@@ -88,7 +82,26 @@ public abstract class JORARepository extends SimpleRepository
|
||||
public Integer invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.update(object);
|
||||
return table.update(conn, object);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates fields specified by the supplied field mask in the supplied
|
||||
* object in the specified table.
|
||||
*
|
||||
* @return the number of rows modified by the update.
|
||||
*/
|
||||
protected <T> int update (final Table<T> table, final T object,
|
||||
final FieldMask mask)
|
||||
throws PersistenceException
|
||||
{
|
||||
return executeUpdate(new Operation<Integer>() {
|
||||
public Integer invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.update(conn, object, mask);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -106,7 +119,7 @@ public abstract class JORARepository extends SimpleRepository
|
||||
Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.select(query).toArrayList();
|
||||
return table.select(conn, query).toArrayList();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -124,7 +137,43 @@ public abstract class JORARepository extends SimpleRepository
|
||||
Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.select(auxtable, query).toArrayList();
|
||||
return table.select(conn, auxtable, query).toArrayList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all objects from the specified table that match the supplied
|
||||
* example.
|
||||
*/
|
||||
protected <T> ArrayList<T> loadAllByExample (
|
||||
final Table<T> table, final T example)
|
||||
throws PersistenceException
|
||||
{
|
||||
return execute(new Operation<ArrayList<T>>() {
|
||||
public ArrayList<T> invoke (
|
||||
Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.queryByExample(conn, example).toArrayList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all objects from the specified table that match the supplied
|
||||
* example.
|
||||
*/
|
||||
protected <T> ArrayList<T> loadAllByExample (
|
||||
final Table<T> table, final T example, final FieldMask mask)
|
||||
throws PersistenceException
|
||||
{
|
||||
return execute(new Operation<ArrayList<T>>() {
|
||||
public ArrayList<T> invoke (
|
||||
Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.queryByExample(conn, example, mask).toArrayList();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -141,7 +190,25 @@ public abstract class JORARepository extends SimpleRepository
|
||||
public T invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.select(query).get();
|
||||
return table.select(conn, query).get();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a single object from the specified table that matches the supplied
|
||||
* query, joining with the supplied auxiliary table(s). <em>Note:</em> the
|
||||
* query should match one or zero records, not more.
|
||||
*/
|
||||
protected <T> T load (
|
||||
final Table<T> table, final String auxtable, final String query)
|
||||
throws PersistenceException
|
||||
{
|
||||
return execute(new Operation<T>() {
|
||||
public T invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.select(conn, auxtable, query).get();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -158,7 +225,7 @@ public abstract class JORARepository extends SimpleRepository
|
||||
public T invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.queryByExample(example).get();
|
||||
return table.queryByExample(conn, example).get();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -169,14 +236,14 @@ public abstract class JORARepository extends SimpleRepository
|
||||
* records, not more.
|
||||
*/
|
||||
protected <T> T loadByExample (
|
||||
final Table<T> table, final FieldMask mask, final T example)
|
||||
final Table<T> table, final T example, final FieldMask mask)
|
||||
throws PersistenceException
|
||||
{
|
||||
return execute(new Operation<T>() {
|
||||
public T invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.queryByExample(example, mask).get();
|
||||
return table.queryByExample(conn, example, mask).get();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -196,8 +263,8 @@ public abstract class JORARepository extends SimpleRepository
|
||||
public Integer invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
if (table.update(object) == 0) {
|
||||
table.insert(object);
|
||||
if (table.update(conn, object) == 0) {
|
||||
table.insert(conn, object);
|
||||
return liaison.lastInsertedId(conn);
|
||||
}
|
||||
return -1;
|
||||
@@ -221,7 +288,7 @@ public abstract class JORARepository extends SimpleRepository
|
||||
public Integer invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.update(object, mask);
|
||||
return table.update(conn, object, mask);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -244,7 +311,7 @@ public abstract class JORARepository extends SimpleRepository
|
||||
public Integer invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.update(object, mask);
|
||||
return table.update(conn, object, mask);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -261,30 +328,14 @@ public abstract class JORARepository extends SimpleRepository
|
||||
public Integer invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws SQLException, PersistenceException
|
||||
{
|
||||
return table.delete(object);
|
||||
return table.delete(conn, object);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* After the database session is begun, this function will be called
|
||||
* to give the repository implementation the opportunity to create its
|
||||
* table objects.
|
||||
*
|
||||
* @param session the session instance to use when creating your table
|
||||
* instances.
|
||||
* During construction, this function will be called to give the repository
|
||||
* implementation the opportunity to create its table objects.
|
||||
*/
|
||||
protected abstract void createTables (Session session);
|
||||
|
||||
protected void gotConnection (Connection conn)
|
||||
{
|
||||
// create or update our JORA session
|
||||
if (_session == null) {
|
||||
_session = new Session(conn);
|
||||
} else {
|
||||
_session.setConnection(conn);
|
||||
}
|
||||
}
|
||||
|
||||
protected Session _session;
|
||||
protected abstract void createTables ();
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class MySQLLiaison implements DatabaseLiaison
|
||||
String msg = sqe.getMessage();
|
||||
return (msg != null &&
|
||||
(msg.indexOf("Lost connection") != -1 ||
|
||||
msg.indexOf("Communication link failure") != -1 ||
|
||||
msg.indexOf("link failure") != -1 ||
|
||||
msg.indexOf("Broken pipe") != -1));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
//-< 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
|
||||
//-------------------------------------------------------------------*--------*
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2001-6 Konstantin Knizhnik, Michael Bayne
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.samskivert.jdbc.jora;
|
||||
|
||||
@@ -15,81 +25,67 @@ import java.sql.*;
|
||||
|
||||
import com.samskivert.Log;
|
||||
|
||||
/** 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.
|
||||
/**
|
||||
* 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<V>
|
||||
{
|
||||
/**
|
||||
* 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.
|
||||
* 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.
|
||||
* <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
|
||||
* @return object constructed from fetched record or null if there are no
|
||||
* more rows
|
||||
*/
|
||||
public V next ()
|
||||
throws SQLException
|
||||
{
|
||||
// // if we closed everything up after the last call to next(),
|
||||
// // table will be null here and we should bail immediately
|
||||
if (table == null) {
|
||||
{
|
||||
// if we closed everything up after the last call to next(),
|
||||
// table will be null here and we should bail immediately
|
||||
if (_table == null) {
|
||||
return null;
|
||||
}
|
||||
// if (nTables == 0) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
// do {
|
||||
if (result == null) {
|
||||
// if (table.isAbstract) {
|
||||
// table = table.derived;
|
||||
// continue;
|
||||
// }
|
||||
if (qbeObject != null) {
|
||||
PreparedStatement qbeStmt;
|
||||
synchronized(session.preparedStmtHash) {
|
||||
Object s = session.preparedStmtHash.get(query);
|
||||
if (s == null) {
|
||||
qbeStmt=
|
||||
session.connection.prepareStatement(query);
|
||||
session.preparedStmtHash.put(query, qbeStmt);
|
||||
} else {
|
||||
qbeStmt = (PreparedStatement)s;
|
||||
}
|
||||
if (_result == null) {
|
||||
if (_qbeObject != null) {
|
||||
PreparedStatement qbeStmt;
|
||||
synchronized (_table.preparedStmtHash) {
|
||||
qbeStmt = _table.preparedStmtHash.get(_query);
|
||||
if (qbeStmt == null) {
|
||||
qbeStmt = _conn.prepareStatement(_query);
|
||||
_table.preparedStmtHash.put(_query, qbeStmt);
|
||||
}
|
||||
synchronized(qbeStmt) {
|
||||
table.bindQueryVariables(
|
||||
qbeStmt, qbeObject, qbeMask);
|
||||
result = qbeStmt.executeQuery();
|
||||
qbeStmt.clearParameters();
|
||||
}
|
||||
} else {
|
||||
if (stmt == null) {
|
||||
stmt = session.connection.createStatement();
|
||||
}
|
||||
result = stmt.executeQuery(query);
|
||||
}
|
||||
}
|
||||
synchronized (qbeStmt) {
|
||||
_table.bindQueryVariables(qbeStmt, _qbeObject, _qbeMask);
|
||||
_result = qbeStmt.executeQuery();
|
||||
qbeStmt.clearParameters();
|
||||
}
|
||||
} else {
|
||||
if (_stmt == null) {
|
||||
_stmt = _conn.createStatement();
|
||||
}
|
||||
_result = _stmt.executeQuery(_query);
|
||||
}
|
||||
if (result.next()) {
|
||||
return currObject = table.load(result);
|
||||
}
|
||||
result.close();
|
||||
result = null;
|
||||
currObject = null;
|
||||
table = null;
|
||||
// table = table.derived;
|
||||
// } while (--nTables != 0);
|
||||
}
|
||||
if (_result.next()) {
|
||||
return _currObject = _table.load(_result);
|
||||
}
|
||||
|
||||
if (stmt != null) {
|
||||
stmt.close();
|
||||
_result.close();
|
||||
_result = null;
|
||||
_currObject = null;
|
||||
_table = null;
|
||||
|
||||
if (_stmt != null) {
|
||||
_stmt.close();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -111,77 +107,81 @@ public class Cursor<V>
|
||||
if (spurious > 0) {
|
||||
Log.warning("Cursor.get() quietly tossed " + spurious +
|
||||
" spurious additional records. " +
|
||||
"[query=" + query + "].");
|
||||
"[query=" + _query + "].");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** 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>
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* <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();
|
||||
if (_currObject == null) {
|
||||
throw new IllegalStateException("No current object");
|
||||
}
|
||||
table.updateVariables(result, currObject);
|
||||
_table.updateVariables(_result, _currObject);
|
||||
}
|
||||
|
||||
/** Delete current record pointed by cursor. This method can be called
|
||||
* only after next() method, which returns non-null object.<P>
|
||||
/**
|
||||
* Delete current record pointed by cursor. This method can be called only
|
||||
* after next() method, which returns non-null object.
|
||||
*
|
||||
* 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.
|
||||
* <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();
|
||||
if (_currObject == null) {
|
||||
throw new IllegalStateException("No current object");
|
||||
}
|
||||
result.deleteRow();
|
||||
_result.deleteRow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the Cursor, even if we haven't read all the possible
|
||||
* objects.
|
||||
* Close the Cursor, even if we haven't read all the possible objects.
|
||||
*/
|
||||
public void close ()
|
||||
throws SQLException
|
||||
{
|
||||
if (stmt != null) {
|
||||
stmt.close(); // also automatically closes result
|
||||
result = null;
|
||||
stmt = null;
|
||||
if (_result != null) {
|
||||
_result.close();
|
||||
_result = null;
|
||||
}
|
||||
if (_stmt != null) {
|
||||
_stmt.close();
|
||||
_stmt = null;
|
||||
}
|
||||
// nTables = 0;
|
||||
}
|
||||
|
||||
/** 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.
|
||||
/**
|
||||
* 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)
|
||||
@@ -198,58 +198,46 @@ public class Cursor<V>
|
||||
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.
|
||||
/**
|
||||
* 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 ArrayList<V> toArrayList()
|
||||
public ArrayList<V> toArrayList ()
|
||||
throws SQLException
|
||||
{
|
||||
return toArrayList(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
// Internals
|
||||
|
||||
protected Cursor (
|
||||
Table<V> table, Session session, int nTables, String query)
|
||||
protected Cursor (Table<V> table, Connection conn, String query)
|
||||
{
|
||||
if (session == null) {
|
||||
session = ((SessionThread)Thread.currentThread()).session;
|
||||
}
|
||||
this.table = table;
|
||||
this.session = session;
|
||||
// this.nTables = nTables;
|
||||
this.query = query;
|
||||
_table = table;
|
||||
_conn = conn;
|
||||
_query = query;
|
||||
}
|
||||
|
||||
protected Cursor (Table<V> table, Session session, int nTables, V obj,
|
||||
protected Cursor (Table<V> table, Connection conn, V obj,
|
||||
FieldMask mask, boolean like)
|
||||
{
|
||||
if (session == null) {
|
||||
session = ((SessionThread)Thread.currentThread()).session;
|
||||
}
|
||||
this.table = table;
|
||||
this.session = session;
|
||||
// this.nTables = nTables;
|
||||
this.like = like;
|
||||
qbeObject = obj;
|
||||
qbeMask = mask;
|
||||
query = table.buildQueryList(obj, mask, like);
|
||||
stmt = null;
|
||||
{
|
||||
_table = table;
|
||||
_conn = conn;
|
||||
_like = like;
|
||||
_qbeObject = obj;
|
||||
_qbeMask = mask;
|
||||
_query = table.buildQueryList(obj, mask, like);
|
||||
_stmt = null;
|
||||
}
|
||||
|
||||
private Table<V> table;
|
||||
private Session session;
|
||||
// private int nTables;
|
||||
private ResultSet result;
|
||||
private String query;
|
||||
private Statement stmt;
|
||||
private V currObject;
|
||||
private V qbeObject;
|
||||
private FieldMask qbeMask;
|
||||
private boolean like;
|
||||
|
||||
protected Table<V> _table;
|
||||
protected Connection _conn;
|
||||
protected ResultSet _result;
|
||||
protected String _query;
|
||||
protected Statement _stmt;
|
||||
protected V _currObject, _qbeObject;
|
||||
protected FieldMask _qbeMask;
|
||||
protected boolean _like;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
//-< 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
|
||||
//-------------------------------------------------------------------*--------*
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2001-6 Konstantin Knizhnik, Michael Bayne
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.samskivert.jdbc.jora;
|
||||
|
||||
@@ -14,10 +24,370 @@ import java.sql.*;
|
||||
import java.math.*;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
class FieldDescriptor {
|
||||
class FieldDescriptor
|
||||
{
|
||||
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:
|
||||
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;
|
||||
}
|
||||
|
||||
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 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
|
||||
|
||||
@@ -52,379 +422,30 @@ class FieldDescriptor {
|
||||
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
|
||||
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:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
//-< 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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
//-< 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");
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
//-< 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;
|
||||
}
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
//-< 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.*;
|
||||
|
||||
import com.samskivert.Log;
|
||||
|
||||
/**
|
||||
* 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<String,PreparedStatement>();
|
||||
connectionID = 0;
|
||||
}
|
||||
|
||||
/** Construct a session with a pre-existing connection instance. In
|
||||
* this case, {@link #open} should not be called on this session.
|
||||
*
|
||||
* @param connection the connection to use.
|
||||
*/
|
||||
public Session(Connection connection)
|
||||
{
|
||||
connectionID = 0;
|
||||
preparedStmtHash = new Hashtable<String,PreparedStatement>();
|
||||
setConnection(connection);
|
||||
}
|
||||
|
||||
/** Session consructor for ODBC bridge driver
|
||||
*/
|
||||
public Session() { this("sun.jdbc.odbc.JdbcOdbcDriver"); }
|
||||
|
||||
/** Sets the connection that should be used by this session.
|
||||
*/
|
||||
public void setConnection(Connection conn)
|
||||
{
|
||||
// only up the connection id if this is a new connection
|
||||
if (connection != conn) {
|
||||
// clear out our prepared statement hash because we've got a
|
||||
// new connection
|
||||
for (PreparedStatement pstmt : preparedStmtHash.values()) {
|
||||
try {
|
||||
pstmt.close();
|
||||
} catch (SQLException sqe) {
|
||||
Log.warning("Error closing cached prepared statement " +
|
||||
"[error=" + sqe + "].");
|
||||
}
|
||||
}
|
||||
preparedStmtHash.clear();
|
||||
|
||||
// switch to our new connection
|
||||
connection = conn;
|
||||
connectionID += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/** 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 dataSource 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
|
||||
{
|
||||
for (PreparedStatement pstmt : preparedStmtHash.values()) {
|
||||
pstmt.close();
|
||||
}
|
||||
preparedStmtHash.clear();
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<String,PreparedStatement> preparedStmtHash;
|
||||
protected int connectionID;
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
//-< 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;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -39,7 +39,6 @@ import com.samskivert.jdbc.JORARepository;
|
||||
import com.samskivert.jdbc.StaticConnectionProvider;
|
||||
import com.samskivert.jdbc.jora.Cursor;
|
||||
import com.samskivert.jdbc.jora.FieldMask;
|
||||
import com.samskivert.jdbc.jora.Session;
|
||||
import com.samskivert.jdbc.jora.Table;
|
||||
import com.samskivert.util.HashIntMap;
|
||||
import com.samskivert.util.StringUtil;
|
||||
@@ -134,30 +133,15 @@ public class UserRepository extends JORARepository
|
||||
* @return the user associated with the specified session or null of
|
||||
* no session exists with the supplied identifier.
|
||||
*/
|
||||
public User loadUserBySession (final String sessionKey)
|
||||
public User loadUserBySession (String sessionKey)
|
||||
throws PersistenceException
|
||||
{
|
||||
return execute(new Operation<User>() {
|
||||
public User invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws PersistenceException, SQLException
|
||||
{
|
||||
String query = "where authcode = '" + sessionKey +
|
||||
"' AND sessions.userId = users.userId";
|
||||
// look up the user
|
||||
Cursor<User> ec = _utable.select("sessions", query);
|
||||
|
||||
// fetch the user from the cursor
|
||||
User user = ec.next();
|
||||
if (user != null) {
|
||||
// call next() again to cause the cursor to close itself
|
||||
ec.next();
|
||||
// configure the user record with its field mask
|
||||
user.setDirtyMask(_utable.getFieldMask());
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
});
|
||||
User user = load(_utable, "where authcode = '" + sessionKey + "' AND " +
|
||||
"sessions.userId = users.userId");
|
||||
if (user != null) {
|
||||
user.setDirtyMask(_utable.getFieldMask());
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,29 +152,15 @@ public class UserRepository extends JORARepository
|
||||
public HashIntMap<User> loadUsersFromId (int[] userIds)
|
||||
throws PersistenceException
|
||||
{
|
||||
// make sure we actually have something to do
|
||||
if (userIds.length == 0) {
|
||||
return new HashIntMap<User>();
|
||||
}
|
||||
|
||||
final String ids = genIdString(userIds);
|
||||
|
||||
return execute(new Operation<HashIntMap<User>>() {
|
||||
public HashIntMap<User> invoke (Connection conn,
|
||||
DatabaseLiaison liaison)
|
||||
throws PersistenceException, SQLException
|
||||
{
|
||||
Cursor<User> ec = _utable.select(
|
||||
"where userid in (" + ids + ")");
|
||||
User user;
|
||||
HashIntMap<User> data = new HashIntMap<User>();
|
||||
while ((user = ec.next()) != null) {
|
||||
user.setDirtyMask(_utable.getFieldMask());
|
||||
data.put(user.userId, user);
|
||||
}
|
||||
return data;
|
||||
HashIntMap<User> data = new HashIntMap<User>();
|
||||
if (userIds.length > 0) {
|
||||
String query = "where userid in (" + genIdString(userIds) + ")";
|
||||
for (User user : loadAll(_utable, query)) {
|
||||
user.setDirtyMask(_utable.getFieldMask());
|
||||
data.put(user.userId, user);
|
||||
}
|
||||
});
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,16 +174,7 @@ public class UserRepository extends JORARepository
|
||||
public ArrayList<User> lookupUsersByEmail (String email)
|
||||
throws PersistenceException
|
||||
{
|
||||
final String where = "where email = " +
|
||||
JDBCUtil.escape(email);
|
||||
return execute(new Operation<ArrayList<User>>() {
|
||||
public ArrayList<User> invoke (Connection conn,
|
||||
DatabaseLiaison liaison)
|
||||
throws PersistenceException, SQLException
|
||||
{
|
||||
return _utable.select(where).toArrayList();
|
||||
}
|
||||
});
|
||||
return loadAll(_utable, "where email = " + JDBCUtil.escape(email));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,20 +188,12 @@ public class UserRepository extends JORARepository
|
||||
public ArrayList<User> lookupUsersWhere (final String where)
|
||||
throws PersistenceException
|
||||
{
|
||||
return execute(new Operation<ArrayList<User>>() {
|
||||
public ArrayList<User> invoke (
|
||||
Connection conn, DatabaseLiaison liaison)
|
||||
throws PersistenceException, SQLException
|
||||
{
|
||||
ArrayList<User> users =
|
||||
_utable.select("where " + where).toArrayList();
|
||||
for (User user : users) {
|
||||
// configure the user record with its field mask
|
||||
user.setDirtyMask(_utable.getFieldMask());
|
||||
}
|
||||
return users;
|
||||
}
|
||||
});
|
||||
ArrayList<User> users = loadAll(_utable, where);
|
||||
for (User user : users) {
|
||||
// configure the user record with its field mask
|
||||
user.setDirtyMask(_utable.getFieldMask());
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -259,17 +212,7 @@ public class UserRepository extends JORARepository
|
||||
// nothing doing!
|
||||
return false;
|
||||
}
|
||||
|
||||
executeUpdate(new Operation<Object>() {
|
||||
public Object invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws PersistenceException, SQLException
|
||||
{
|
||||
_utable.update(user, user.getDirtyMask());
|
||||
// nothing to return
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
update(_utable, user, user.getDirtyMask());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -317,7 +260,7 @@ public class UserRepository extends JORARepository
|
||||
try {
|
||||
user.username = StringUtil.truncate(
|
||||
ii + "=" + oldName, 24);
|
||||
_utable.update(user, mask);
|
||||
_utable.update(conn, user, mask);
|
||||
return null; // nothing to return
|
||||
} catch (SQLException se) {
|
||||
if (!liaison.isDuplicateRowException(se)) {
|
||||
@@ -350,18 +293,8 @@ public class UserRepository extends JORARepository
|
||||
final Date expires = new Date(cal.getTime().getTime());
|
||||
|
||||
// insert the session into the database
|
||||
executeUpdate(new Operation<Object>() {
|
||||
public Object invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws PersistenceException, SQLException
|
||||
{
|
||||
_session.execute("insert into sessions " +
|
||||
"(authcode, userId, expires) values('" +
|
||||
authcode + "', " + user.userId + ", '" +
|
||||
expires + "')");
|
||||
// nothing to return
|
||||
return null;
|
||||
}
|
||||
});
|
||||
update("insert into sessions (authcode, userId, expires) values('" +
|
||||
authcode + "', " + user.userId + ", '" + expires + "')");
|
||||
|
||||
// and let the user know what the session identifier is
|
||||
return authcode;
|
||||
@@ -373,16 +306,7 @@ public class UserRepository extends JORARepository
|
||||
public void pruneSessions ()
|
||||
throws PersistenceException
|
||||
{
|
||||
executeUpdate(new Operation<Object>() {
|
||||
public Object invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws PersistenceException, SQLException
|
||||
{
|
||||
_session.execute("delete from sessions where " +
|
||||
"expires <= CURRENT_DATE()");
|
||||
// nothing to return
|
||||
return null;
|
||||
}
|
||||
});
|
||||
update("delete from sessions where expires <= CURRENT_DATE()");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -420,7 +344,7 @@ public class UserRepository extends JORARepository
|
||||
public Object invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws PersistenceException, SQLException
|
||||
{
|
||||
Statement stmt = _session.connection.createStatement();
|
||||
Statement stmt = conn.createStatement();
|
||||
try {
|
||||
String query = "select realname from users";
|
||||
ResultSet rs = stmt.executeQuery(query);
|
||||
@@ -469,7 +393,7 @@ public class UserRepository extends JORARepository
|
||||
throws PersistenceException, SQLException
|
||||
{
|
||||
try {
|
||||
_utable.insert(user);
|
||||
_utable.insert(conn, user);
|
||||
// update the userid now that it's known
|
||||
user.userId = liaison.lastInsertedId(conn);
|
||||
// nothing to return
|
||||
@@ -489,31 +413,17 @@ public class UserRepository extends JORARepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads up a user record that matches the specified where clause.
|
||||
* Returns null if no record matches.
|
||||
* Loads up a user record that matches the specified where clause. Returns
|
||||
* null if no record matches.
|
||||
*/
|
||||
protected User loadUserWhere (final String whereClause)
|
||||
protected User loadUserWhere (String where)
|
||||
throws PersistenceException
|
||||
{
|
||||
return execute(new Operation<User>() {
|
||||
public User invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws PersistenceException, SQLException
|
||||
{
|
||||
// look up the user
|
||||
Cursor<User> ec = _utable.select(whereClause);
|
||||
|
||||
// fetch the user from the cursor
|
||||
User user = ec.next();
|
||||
if (user != null) {
|
||||
// call next() again to cause the cursor to close itself
|
||||
ec.next();
|
||||
// configure the user record with its field mask
|
||||
user.setDirtyMask(_utable.getFieldMask());
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
});
|
||||
User user = load(_utable, where);
|
||||
if (user != null) {
|
||||
user.setDirtyMask(_utable.getFieldMask());
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
protected String[] loadNames (int[] userIds, final String column)
|
||||
@@ -524,16 +434,14 @@ public class UserRepository extends JORARepository
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
final String ids = genIdString(userIds);
|
||||
|
||||
final HashIntMap<String> map = new HashIntMap<String>();
|
||||
|
||||
// do the query
|
||||
final String ids = genIdString(userIds);
|
||||
final HashIntMap<String> map = new HashIntMap<String>();
|
||||
execute(new Operation<Object>() {
|
||||
public Object invoke (Connection conn, DatabaseLiaison liaison)
|
||||
throws PersistenceException, SQLException
|
||||
{
|
||||
Statement stmt = _session.connection.createStatement();
|
||||
Statement stmt = conn.createStatement();
|
||||
try {
|
||||
String query = "select userId, " + column +
|
||||
" from users " +
|
||||
@@ -559,14 +467,13 @@ public class UserRepository extends JORARepository
|
||||
for (int i = 0; i < userIds.length; i++) {
|
||||
result[i] = map.get(userIds[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the passed in int array and create the a string suitable for
|
||||
* using in a SQL set query (I.e., "select foo, from bar where userid
|
||||
* in (genIdString(userIds))"; )
|
||||
* Take the passed in int array and create the a string suitable for using
|
||||
* in a SQL set query (I.e., "select foo, from bar where userid in
|
||||
* (genIdString(userIds))"; )
|
||||
*/
|
||||
protected String genIdString (int[] userIds)
|
||||
{
|
||||
@@ -583,10 +490,10 @@ public class UserRepository extends JORARepository
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void createTables (Session session)
|
||||
protected void createTables ()
|
||||
{
|
||||
// create our table object
|
||||
_utable = new Table<User>(User.class, "users", session, "userId");
|
||||
_utable = new Table<User>(User.class, "users", "userId");
|
||||
}
|
||||
|
||||
/** A wrapper that provides access to the userstable. */
|
||||
|
||||
Reference in New Issue
Block a user