Support for query clauses, joins, field overriding and a bunch of
other useful stuff from Zell. Adjusted formatting to 100 columns.
This commit is contained in:
@@ -41,6 +41,7 @@ import javax.persistence.TableGenerator;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import com.samskivert.jdbc.JDBCUtil;
|
||||
import com.samskivert.jdbc.depot.expression.ColumnExpression;
|
||||
import com.samskivert.util.ArrayUtil;
|
||||
import com.samskivert.util.ListUtil;
|
||||
import com.samskivert.util.StringUtil;
|
||||
@@ -48,15 +49,14 @@ import com.samskivert.util.StringUtil;
|
||||
import static com.samskivert.jdbc.depot.Log.log;
|
||||
|
||||
/**
|
||||
* Handles the marshalling and unmarshalling of persistent instances to JDBC
|
||||
* primitives ({@link PreparedStatement} and {@link ResultSet}).
|
||||
* Handles the marshalling and unmarshalling of persistent instances to JDBC primitives ({@link
|
||||
* PreparedStatement} and {@link ResultSet}).
|
||||
*/
|
||||
public class DepotMarshaller<T>
|
||||
{
|
||||
/** The name of the private static field that must be defined for all
|
||||
* persistent object classes which is used to handle schema migration. If
|
||||
* automatic schema migration is not desired, define this field and set its
|
||||
* value to -1. */
|
||||
/** The name of a private static field that must be defined for all persistent object classes.
|
||||
* It is used to handle schema migration. If automatic schema migration is not desired, define
|
||||
* this field and set its value to -1. */
|
||||
public static final String SCHEMA_VERSION_FIELD = "SCHEMA_VERSION";
|
||||
|
||||
/**
|
||||
@@ -70,8 +70,8 @@ public class DepotMarshaller<T>
|
||||
_tableName = _pclass.getName();
|
||||
_tableName = _tableName.substring(_tableName.lastIndexOf(".")+1);
|
||||
|
||||
// if the entity defines a new TableGenerator, map that in our static
|
||||
// table as those are shared across all entities
|
||||
// if the entity defines a new TableGenerator, map that in our static table as those are
|
||||
// shared across all entities
|
||||
TableGenerator generator = pclass.getAnnotation(TableGenerator.class);
|
||||
if (generator != null) {
|
||||
context.tableGenerators.put(generator.name(), generator);
|
||||
@@ -83,8 +83,7 @@ public class DepotMarshaller<T>
|
||||
int mods = field.getModifiers();
|
||||
|
||||
// check for a static constant schema version
|
||||
if ((mods & Modifier.STATIC) != 0 &&
|
||||
field.getName().equals(SCHEMA_VERSION_FIELD)) {
|
||||
if ((mods & Modifier.STATIC) != 0 && field.getName().equals(SCHEMA_VERSION_FIELD)) {
|
||||
try {
|
||||
_schemaVersion = (Integer)field.get(null);
|
||||
} catch (Exception e) {
|
||||
@@ -94,8 +93,7 @@ public class DepotMarshaller<T>
|
||||
}
|
||||
|
||||
// the field must be public, non-static and non-transient
|
||||
if (((mods & Modifier.PUBLIC) == 0) ||
|
||||
((mods & Modifier.STATIC) != 0) ||
|
||||
if (((mods & Modifier.PUBLIC) == 0) || ((mods & Modifier.STATIC) != 0) ||
|
||||
field.getAnnotation(Transient.class) != null) {
|
||||
continue;
|
||||
}
|
||||
@@ -119,8 +117,8 @@ public class DepotMarshaller<T>
|
||||
}
|
||||
}
|
||||
|
||||
// if the entity defines a single-columnar primary key, figure out if
|
||||
// we will be generating values for it
|
||||
// if the entity defines a single-columnar primary key, figure out if we will be generating
|
||||
// values for it
|
||||
if (_pkColumns != null) {
|
||||
GeneratedValue gv = null;
|
||||
FieldMarshaller keyField = null;
|
||||
@@ -142,11 +140,11 @@ public class DepotMarshaller<T>
|
||||
|
||||
// the primary key must be numeric if we are to auto-assign it
|
||||
Class<?> ftype = keyField.getField().getType();
|
||||
boolean isNumeric = (ftype.equals(Byte.TYPE) ||
|
||||
ftype.equals(Byte.class) || ftype.equals(Short.TYPE) ||
|
||||
ftype.equals(Short.class) || ftype.equals(Integer.TYPE) ||
|
||||
ftype.equals(Integer.class) || ftype.equals(Long.TYPE) ||
|
||||
ftype.equals(Long.class));
|
||||
boolean isNumeric = (
|
||||
ftype.equals(Byte.TYPE) || ftype.equals(Byte.class) ||
|
||||
ftype.equals(Short.TYPE) || ftype.equals(Short.class) ||
|
||||
ftype.equals(Integer.TYPE) || ftype.equals(Integer.class) ||
|
||||
ftype.equals(Long.TYPE) || ftype.equals(Long.class));
|
||||
if (!isNumeric) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot use @GeneratedValue on non-numeric column");
|
||||
@@ -173,13 +171,11 @@ public class DepotMarshaller<T>
|
||||
|
||||
// generate our full list of fields/columns for use in queries
|
||||
_allFields = fields.toArray(new String[fields.size()]);
|
||||
_fullColumnList = StringUtil.join(_allFields, ",");
|
||||
|
||||
// create the SQL used to create and migrate our table
|
||||
_columnDefinitions = new String[_allFields.length];
|
||||
for (int ii = 0; ii < _allFields.length; ii++) {
|
||||
_columnDefinitions[ii] =
|
||||
_fields.get(_allFields[ii]).getColumnDefinition();
|
||||
_columnDefinitions[ii] = _fields.get(_allFields[ii]).getColumnDefinition();
|
||||
}
|
||||
// add the primary key, if we have one
|
||||
if (hasPrimaryKey()) {
|
||||
@@ -188,22 +184,20 @@ public class DepotMarshaller<T>
|
||||
indices[ii] = _pkColumns.get(ii).getColumnName();
|
||||
}
|
||||
_columnDefinitions = ArrayUtil.append(
|
||||
_columnDefinitions,
|
||||
"PRIMARY KEY (" + StringUtil.join(indices, ", ") + ")");
|
||||
_columnDefinitions, "PRIMARY KEY (" + StringUtil.join(indices, ", ") + ")");
|
||||
}
|
||||
_postamble = ""; // TODO: add annotations for the postamble
|
||||
|
||||
// if we did not find a schema version field, complain
|
||||
if (_schemaVersion < 0) {
|
||||
log.warning("Unable to read " + _pclass.getName() + "." +
|
||||
SCHEMA_VERSION_FIELD + ". Schema migration disabled.");
|
||||
log.warning("Unable to read " + _pclass.getName() + "." + SCHEMA_VERSION_FIELD +
|
||||
". Schema migration disabled.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the table in which persistence instances of this
|
||||
* class are stored. By default this is the classname of the persistent
|
||||
* object without the package.
|
||||
* Returns the name of the table in which persistence instances of this class are stored. By
|
||||
* default this is the classname of the persistent object without the package.
|
||||
*/
|
||||
public String getTableName ()
|
||||
{
|
||||
@@ -219,9 +213,8 @@ public class DepotMarshaller<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a key configured with the primary key of the supplied object.
|
||||
* Throws an exception if the persistent object did not declare a primary
|
||||
* key.
|
||||
* Returns a key configured with the primary key of the supplied object. Throws an exception
|
||||
* if the persistent object did not declare a primary key.
|
||||
*/
|
||||
public Key getPrimaryKey (Object object)
|
||||
{
|
||||
@@ -242,8 +235,8 @@ public class DepotMarshaller<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a primary key record for the type of object handled by this
|
||||
* marshaller, using the supplied primary key vlaue.
|
||||
* Creates a primary key record for the type of object handled by this marshaller, using the
|
||||
* supplied primary key value.
|
||||
*/
|
||||
public Key makePrimaryKey (Comparable... values)
|
||||
{
|
||||
@@ -253,39 +246,35 @@ public class DepotMarshaller<T>
|
||||
}
|
||||
if (values.length != _pkColumns.size()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Argument count (" + values.length + ") must match " +
|
||||
"primary key size (" + _pkColumns.size() + ")");
|
||||
"Argument count (" + values.length + ") must match primary key size (" +
|
||||
_pkColumns.size() + ")");
|
||||
}
|
||||
String[] indices = new String[_pkColumns.size()];
|
||||
ColumnExpression[] columns = new ColumnExpression[_pkColumns.size()];
|
||||
for (int ii = 0; ii < _pkColumns.size(); ii++) {
|
||||
FieldMarshaller field = _pkColumns.get(ii);
|
||||
indices[ii] = field.getColumnName();
|
||||
columns[ii] = new ColumnExpression(_pclass, field.getColumnName());
|
||||
}
|
||||
return new Key(indices, values);
|
||||
return new Key(columns, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the table used by this marshaller. If the table does not
|
||||
* exist, it will be created. If the schema version specified by the
|
||||
* persistent object is newer than the database schema, it will be
|
||||
* migrated.
|
||||
* Initializes the table used by this marshaller. If the table does not exist, it will be
|
||||
* created. If the schema version specified by the persistent object is newer than the database
|
||||
* schema, it will be migrated.
|
||||
*/
|
||||
public void init (Connection conn)
|
||||
throws SQLException
|
||||
{
|
||||
// check to see if our schema version table exists, create it if not
|
||||
JDBCUtil.createTableIfMissing(conn, SCHEMA_VERSION_TABLE,
|
||||
new String[] { "persistentClass VARCHAR(255) NOT NULL",
|
||||
"version INTEGER NOT NULL" },
|
||||
"");
|
||||
new String[] { "persistentClass VARCHAR(255) NOT NULL",
|
||||
"version INTEGER NOT NULL" }, "");
|
||||
|
||||
// now create the table for our persistent class if it does not exist
|
||||
if (!JDBCUtil.tableExists(conn, getTableName())) {
|
||||
log.fine("Creating table " + getTableName() +
|
||||
" (" + StringUtil.join(_columnDefinitions, ", ") + ") " +
|
||||
_postamble);
|
||||
JDBCUtil.createTableIfMissing(
|
||||
conn, getTableName(), _columnDefinitions, _postamble);
|
||||
log.fine("Creating table " + getTableName() + " (" +
|
||||
StringUtil.join(_columnDefinitions, ", ") + ") " + _postamble);
|
||||
JDBCUtil.createTableIfMissing(conn, getTableName(), _columnDefinitions, _postamble);
|
||||
updateVersion(conn, 1);
|
||||
}
|
||||
|
||||
@@ -305,11 +294,11 @@ public class DepotMarshaller<T>
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("Migrating " + getTableName() + " from " + currentVersion +
|
||||
" to " + _schemaVersion + "...");
|
||||
log.info("Migrating " + getTableName() + " from " +
|
||||
currentVersion + " to " + _schemaVersion + "...");
|
||||
|
||||
// otherwise try to migrate the schema; doing column additions
|
||||
// magically and running any registered hand-migrations
|
||||
// otherwise try to migrate the schema; doing column additions magically and running any
|
||||
// registered hand-migrations
|
||||
DatabaseMetaData meta = conn.getMetaData();
|
||||
ResultSet rs = meta.getColumns(null, null, getTableName(), "%");
|
||||
HashSet<String> columns = new HashSet<String>();
|
||||
@@ -325,8 +314,7 @@ public class DepotMarshaller<T>
|
||||
|
||||
// otherwise add the column
|
||||
String coldef = fmarsh.getColumnDefinition();
|
||||
String query = "alter table " + getTableName() +
|
||||
" add column " + coldef;
|
||||
String query = "alter table " + getTableName() + " add column " + coldef;
|
||||
|
||||
// try to add it to the appropriate spot
|
||||
int fidx = ListUtil.indexOf(_allFields, fmarsh.getColumnName());
|
||||
@@ -351,26 +339,8 @@ public class DepotMarshaller<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a query for instances of this persistent object type using the
|
||||
* supplied key. If null is supplied all instances will be loaded.
|
||||
*/
|
||||
public PreparedStatement createQuery (Connection conn, Key key)
|
||||
throws SQLException
|
||||
{
|
||||
String query = "select " + _fullColumnList + " from " + getTableName();
|
||||
if (key != null) {
|
||||
query += " where " + key.toWhereClause();
|
||||
}
|
||||
PreparedStatement pstmt = conn.prepareStatement(query);
|
||||
if (key != null) {
|
||||
key.bindArguments(pstmt, 1);
|
||||
}
|
||||
return pstmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a persistent object from the supplied result set. The result set
|
||||
* must have come from a query provided by {@link #createQuery}.
|
||||
* Creates a persistent object from the supplied result set. The result set must have come from
|
||||
* a query provided by {@link #createQuery}.
|
||||
*/
|
||||
public T createObject (ResultSet rs)
|
||||
throws SQLException
|
||||
@@ -387,15 +357,14 @@ public class DepotMarshaller<T>
|
||||
throw sqe;
|
||||
|
||||
} catch (Exception e) {
|
||||
String errmsg = "Failed to unmarshall persistent object " +
|
||||
"[pclass=" + _pclass.getName() + "]";
|
||||
String errmsg = "Failed to unmarshall persistent object [pclass=" +
|
||||
_pclass.getName() + "]";
|
||||
throw (SQLException)new SQLException(errmsg).initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a statement that will insert the supplied persistent object into
|
||||
* the database.
|
||||
* Creates a statement that will insert the supplied persistent object into the database.
|
||||
*/
|
||||
public PreparedStatement createInsert (Connection conn, Object po)
|
||||
throws SQLException
|
||||
@@ -403,8 +372,8 @@ public class DepotMarshaller<T>
|
||||
try {
|
||||
StringBuilder insert = new StringBuilder();
|
||||
insert.append("insert into ").append(getTableName());
|
||||
insert.append(" (").append(_fullColumnList).append(")");
|
||||
insert.append(" values(");
|
||||
insert.append(" (").append(StringUtil.join(_allFields, ","));
|
||||
insert.append(")").append(" values(");
|
||||
for (int ii = 0; ii < _allFields.length; ii++) {
|
||||
if (ii > 0) {
|
||||
insert.append(", ");
|
||||
@@ -426,18 +395,18 @@ public class DepotMarshaller<T>
|
||||
throw sqe;
|
||||
|
||||
} catch (Exception e) {
|
||||
String errmsg = "Failed to marshall persistent object " +
|
||||
"[pclass=" + _pclass.getName() + "]";
|
||||
String errmsg = "Failed to marshall persistent object [pclass=" +
|
||||
_pclass.getName() + "]";
|
||||
throw (SQLException)new SQLException(errmsg).initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills in the primary key just assigned to the supplied persistence
|
||||
* object by the execution of the results of {@link #createInsert}.
|
||||
* Fills in the primary key just assigned to the supplied persistence object by the execution
|
||||
* of the results of {@link #createInsert}.
|
||||
*
|
||||
* @return the newly assigned primary key or null if the object does not
|
||||
* use primary keys or this is not the right time to assign the key.
|
||||
* @return the newly assigned primary key or null if the object does not use primary keys or
|
||||
* this is not the right time to assign the key.
|
||||
*/
|
||||
public Key assignPrimaryKey (Connection conn, Object po, boolean postFactum)
|
||||
throws SQLException
|
||||
@@ -457,15 +426,13 @@ public class DepotMarshaller<T>
|
||||
_pkColumns.get(0).getField().set(po, nextValue);
|
||||
return makePrimaryKey(nextValue);
|
||||
} catch (Exception e) {
|
||||
String errmsg = "Failed to assign primary key " +
|
||||
"[type=" + _pclass + "]";
|
||||
String errmsg = "Failed to assign primary key [type=" + _pclass + "]";
|
||||
throw (SQLException) new SQLException(errmsg).initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a statement that will update the supplied persistent object
|
||||
* using the supplied key.
|
||||
* Creates a statement that will update the supplied persistent object using the supplied key.
|
||||
*/
|
||||
public PreparedStatement createUpdate (Connection conn, Object po, Key key)
|
||||
throws SQLException
|
||||
@@ -490,7 +457,7 @@ public class DepotMarshaller<T>
|
||||
}
|
||||
update.append(field).append(" = ?");
|
||||
}
|
||||
update.append(" where ").append(key.toWhereClause());
|
||||
update.append(" where "); key.appendClause(null, update);
|
||||
|
||||
try {
|
||||
PreparedStatement pstmt = conn.prepareStatement(update.toString());
|
||||
@@ -515,12 +482,11 @@ public class DepotMarshaller<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a statement that will update the specified set of fields for all
|
||||
* persistent objects that match the supplied key.
|
||||
* Creates a statement that will update the specified set of fields for all persistent objects
|
||||
* that match the supplied key.
|
||||
*/
|
||||
public PreparedStatement createPartialUpdate (
|
||||
Connection conn, Key key,
|
||||
String[] modifiedFields, Object[] modifiedValues)
|
||||
Connection conn, Key key, String[] modifiedFields, Object[] modifiedValues)
|
||||
throws SQLException
|
||||
{
|
||||
StringBuilder update = new StringBuilder();
|
||||
@@ -532,7 +498,7 @@ public class DepotMarshaller<T>
|
||||
}
|
||||
update.append(field).append(" = ?");
|
||||
}
|
||||
update.append(" where ").append(key.toWhereClause());
|
||||
update.append(" where "); key.appendClause(null, update);
|
||||
|
||||
PreparedStatement pstmt = conn.prepareStatement(update.toString());
|
||||
idx = 0;
|
||||
@@ -552,21 +518,19 @@ public class DepotMarshaller<T>
|
||||
public PreparedStatement createDelete (Connection conn, Key key)
|
||||
throws SQLException
|
||||
{
|
||||
String query = "delete from " + getTableName() +
|
||||
" where " + key.toWhereClause();
|
||||
PreparedStatement pstmt = conn.prepareStatement(query);
|
||||
StringBuilder query = new StringBuilder("delete from " + getTableName() + " where ");
|
||||
key.appendClause(null, query);
|
||||
PreparedStatement pstmt = conn.prepareStatement(query.toString());
|
||||
key.bindArguments(pstmt, 1);
|
||||
return pstmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a statement that will update the specified set of fields, using
|
||||
* the supplied literal SQL values, for all persistent objects that match
|
||||
* the supplied key.
|
||||
* Creates a statement that will update the specified set of fields, using the supplied literal
|
||||
* SQL values, for all persistent objects that match the supplied key.
|
||||
*/
|
||||
public PreparedStatement createLiteralUpdate (
|
||||
Connection conn, Key key,
|
||||
String[] modifiedFields, Object[] modifiedValues)
|
||||
Connection conn, Key key, String[] modifiedFields, Object[] modifiedValues)
|
||||
throws SQLException
|
||||
{
|
||||
StringBuilder update = new StringBuilder();
|
||||
@@ -578,7 +542,7 @@ public class DepotMarshaller<T>
|
||||
update.append(modifiedFields[ii]).append(" = ");
|
||||
update.append(modifiedValues[ii]);
|
||||
}
|
||||
update.append(" where ").append(key.toWhereClause());
|
||||
update.append(" where "); key.appendClause(null, update);
|
||||
|
||||
PreparedStatement pstmt = conn.prepareStatement(update.toString());
|
||||
key.bindArguments(pstmt, 1);
|
||||
@@ -589,8 +553,7 @@ public class DepotMarshaller<T>
|
||||
throws SQLException
|
||||
{
|
||||
String update = "update " + SCHEMA_VERSION_TABLE +
|
||||
" set version = " + version +
|
||||
" where persistentClass = '" + getTableName() + "'";
|
||||
" set version = " + version + " where persistentClass = '" + getTableName() + "'";
|
||||
String insert = "insert into " + SCHEMA_VERSION_TABLE +
|
||||
" values('" + getTableName() + "', " + version + ")";
|
||||
Statement stmt = conn.createStatement();
|
||||
@@ -624,8 +587,7 @@ public class DepotMarshaller<T>
|
||||
protected String _tableName;
|
||||
|
||||
/** A field marshaller for each persistent field in our object. */
|
||||
protected HashMap<String, FieldMarshaller> _fields =
|
||||
new HashMap<String, FieldMarshaller>();
|
||||
protected HashMap<String, FieldMarshaller> _fields = new HashMap<String, FieldMarshaller>();
|
||||
|
||||
/** The field marshallers for our persistent object's primary key columns
|
||||
* or null if it did not define a primary key. */
|
||||
@@ -634,10 +596,6 @@ public class DepotMarshaller<T>
|
||||
/** The generator to use for auto-generating primary key values, or null. */
|
||||
protected KeyGenerator _keyGenerator;
|
||||
|
||||
/** The persisent fields of our object, in definition order, separated by
|
||||
* commas for easy use in a select statement. */
|
||||
protected String _fullColumnList;
|
||||
|
||||
/** The persisent fields of our object, in definition order. */
|
||||
protected String[] _allFields;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006 Michael Bayne, Pär Winzell
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -27,21 +27,20 @@ import java.sql.SQLException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.samskivert.io.PersistenceException;
|
||||
import com.samskivert.jdbc.ConnectionProvider;
|
||||
import com.samskivert.jdbc.depot.clause.QueryClause;
|
||||
|
||||
/**
|
||||
* Provides a base for classes that provide access to persistent objects. Also
|
||||
* defines the mechanism by which all persistent queries and updates are routed
|
||||
* through the distributed cache.
|
||||
* Provides a base for classes that provide access to persistent objects. Also defines the
|
||||
* mechanism by which all persistent queries and updates are routed through the distributed cache.
|
||||
*/
|
||||
public class DepotRepository
|
||||
{
|
||||
/**
|
||||
* Creates a repository with the supplied connection provider and its own
|
||||
* private persistence context.
|
||||
* Creates a repository with the supplied connection provider and its own private persistence
|
||||
* context.
|
||||
*/
|
||||
protected DepotRepository (ConnectionProvider conprov)
|
||||
{
|
||||
@@ -72,9 +71,9 @@ public class DepotRepository
|
||||
throws PersistenceException
|
||||
{
|
||||
final DepotMarshaller<T> marsh = _ctx.getMarshaller(type);
|
||||
return _ctx.invoke(new Query<T>(key) {
|
||||
return _ctx.invoke(new Query<T>(_ctx, type, key) {
|
||||
public T invoke (Connection conn) throws SQLException {
|
||||
PreparedStatement stmt = marsh.createQuery(conn, _key);
|
||||
PreparedStatement stmt = createQuery(conn);
|
||||
try {
|
||||
T result = null;
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
@@ -105,13 +104,13 @@ public class DepotRepository
|
||||
* Loads all persistent objects that match the specified key.
|
||||
*/
|
||||
protected <T,C extends Collection<T>> Collection<T> findAll (
|
||||
Class<T> type, Key key)
|
||||
Class<T> type, Key key, QueryClause... clauses)
|
||||
throws PersistenceException
|
||||
{
|
||||
final DepotMarshaller<T> marsh = _ctx.getMarshaller(type);
|
||||
return _ctx.invoke(new Query<ArrayList<T>>(key) {
|
||||
return _ctx.invoke(new Query<ArrayList<T>>(_ctx, type, key, clauses) {
|
||||
public ArrayList<T> invoke (Connection conn) throws SQLException {
|
||||
PreparedStatement stmt = marsh.createQuery(conn, _key);
|
||||
PreparedStatement stmt = createQuery(conn);
|
||||
try {
|
||||
ArrayList<T> results = new ArrayList<T>();
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
@@ -128,8 +127,8 @@ public class DepotRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the supplied persistent object into the database, assigning its
|
||||
* primary key (if it has one) in the process.
|
||||
* Inserts the supplied persistent object into the database, assigning its primary key (if it
|
||||
* has one) in the process.
|
||||
*
|
||||
* @return the number of rows modified by this action, this should always
|
||||
* be one.
|
||||
@@ -156,8 +155,8 @@ public class DepotRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all fields of the supplied persistent object, using its primary
|
||||
* key to identify the row to be updated.
|
||||
* Updates all fields of the supplied persistent object, using its primary key to identify the
|
||||
* row to be updated.
|
||||
*
|
||||
* @return the number of rows modified by this action.
|
||||
*/
|
||||
@@ -178,8 +177,8 @@ public class DepotRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates just the specified fields of the supplied persistent object,
|
||||
* using its primary key to identify the row to be updated.
|
||||
* Updates just the specified fields of the supplied persistent object, using its primary key
|
||||
* to identify the row to be updated.
|
||||
*
|
||||
* @return the number of rows modified by this action.
|
||||
*/
|
||||
@@ -189,8 +188,7 @@ public class DepotRepository
|
||||
final DepotMarshaller marsh = _ctx.getMarshaller(record.getClass());
|
||||
return _ctx.invoke(new Modifier(marsh.getPrimaryKey(record)) {
|
||||
public int invoke (Connection conn) throws SQLException {
|
||||
PreparedStatement stmt = marsh.createUpdate(
|
||||
conn, record, _key, modifiedFields);
|
||||
PreparedStatement stmt = marsh.createUpdate(conn, record, _key, modifiedFields);
|
||||
try {
|
||||
return stmt.executeUpdate();
|
||||
} finally {
|
||||
@@ -201,38 +199,33 @@ public class DepotRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the specified columns for all persistent objects matching the
|
||||
* supplied primary key.
|
||||
* Updates the specified columns for all persistent objects matching the supplied primary key.
|
||||
*
|
||||
* @param type the type of the persistent object to be modified.
|
||||
* @param primaryKey the primary key to match in the update.
|
||||
* @param fieldsValues an array containing the names of the fields/columns
|
||||
* and the values to be assigned, in key, value, key, value, etc. order.
|
||||
* @param fieldsValues an array containing the names of the fields/columns and the values to be
|
||||
* assigned, in key, value, key, value, etc. order.
|
||||
*
|
||||
* @return the number of rows modified by this action.
|
||||
*/
|
||||
protected <T> int updatePartial (
|
||||
Class<T> type, Comparable primaryKey, Object ... fieldsValues)
|
||||
protected <T> int updatePartial (Class<T> type, Comparable primaryKey, Object ... fieldsValues)
|
||||
throws PersistenceException
|
||||
{
|
||||
return updatePartial(
|
||||
type, _ctx.getMarshaller(type).makePrimaryKey(primaryKey),
|
||||
fieldsValues);
|
||||
type, _ctx.getMarshaller(type).makePrimaryKey(primaryKey), fieldsValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the specified columns for all persistent objects matching the
|
||||
* supplied key.
|
||||
* Updates the specified columns for all persistent objects matching the supplied key.
|
||||
*
|
||||
* @param type the type of the persistent object to be modified.
|
||||
* @param key the key to match in the update.
|
||||
* @param fieldsValues an array containing the names of the fields/columns
|
||||
* and the values to be assigned, in key, value, key, value, etc. order.
|
||||
* @param fieldsValues an array containing the names of the fields/columns and the values to be
|
||||
* assigned, in key, value, key, value, etc. order.
|
||||
*
|
||||
* @return the number of rows modified by this action.
|
||||
*/
|
||||
protected <T> int updatePartial (
|
||||
Class<T> type, Key key, Object ... fieldsValues)
|
||||
protected <T> int updatePartial (Class<T> type, Key key, Object ... fieldsValues)
|
||||
throws PersistenceException
|
||||
{
|
||||
// separate the arguments into keys and values
|
||||
@@ -246,8 +239,7 @@ public class DepotRepository
|
||||
final DepotMarshaller marsh = _ctx.getMarshaller(type);
|
||||
return _ctx.invoke(new Modifier(key) {
|
||||
public int invoke (Connection conn) throws SQLException {
|
||||
PreparedStatement stmt = marsh.createPartialUpdate(
|
||||
conn, _key, fields, values);
|
||||
PreparedStatement stmt = marsh.createPartialUpdate(conn, _key, fields, values);
|
||||
try {
|
||||
return stmt.executeUpdate();
|
||||
} finally {
|
||||
@@ -258,10 +250,9 @@ public class DepotRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the specified columns for all persistent objects matching the
|
||||
* supplied primary key. The values in this case must be literal SQL to be
|
||||
* inserted into the update statement. In general this is used when you
|
||||
* want to do something like the following:
|
||||
* Updates the specified columns for all persistent objects matching the supplied primary
|
||||
* key. The values in this case must be literal SQL to be inserted into the update
|
||||
* statement. In general this is used when you want to do something like the following:
|
||||
*
|
||||
* <pre>
|
||||
* update FOO set BAR = BAR + 1;
|
||||
@@ -270,26 +261,22 @@ public class DepotRepository
|
||||
*
|
||||
* @param type the type of the persistent object to be modified.
|
||||
* @param primaryKey the key to match in the update.
|
||||
* @param fieldsValues an array containing the names of the fields/columns
|
||||
* and the values to be assigned, in key, literal value, key, literal
|
||||
* value, etc. order.
|
||||
* @param fieldsValues an array containing the names of the fields/columns and the values to be
|
||||
* assigned, in key, literal value, key, literal value, etc. order.
|
||||
*
|
||||
* @return the number of rows modified by this action.
|
||||
*/
|
||||
protected <T> int updateLiteral (
|
||||
Class<T> type, Comparable primaryKey, String ... fieldsValues)
|
||||
protected <T> int updateLiteral (Class<T> type, Comparable primaryKey, String ... fieldsValues)
|
||||
throws PersistenceException
|
||||
{
|
||||
return updateLiteral(
|
||||
type, _ctx.getMarshaller(type).makePrimaryKey(primaryKey),
|
||||
fieldsValues);
|
||||
type, _ctx.getMarshaller(type).makePrimaryKey(primaryKey), fieldsValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the specified columns for all persistent objects matching the
|
||||
* supplied primary key. The values in this case must be literal SQL to be
|
||||
* inserted into the update statement. In general this is used when you
|
||||
* want to do something like the following:
|
||||
* Updates the specified columns for all persistent objects matching the supplied primary
|
||||
* key. The values in this case must be literal SQL to be inserted into the update
|
||||
* statement. In general this is used when you want to do something like the following:
|
||||
*
|
||||
* <pre>
|
||||
* update FOO set BAR = BAR + 1;
|
||||
@@ -298,14 +285,12 @@ public class DepotRepository
|
||||
*
|
||||
* @param type the type of the persistent object to be modified.
|
||||
* @param key the key to match in the update.
|
||||
* @param fieldsValues an array containing the names of the fields/columns
|
||||
* and the values to be assigned, in key, literal value, key, literal
|
||||
* value, etc. order.
|
||||
* @param fieldsValues an array containing the names of the fields/columns and the values to be
|
||||
* assigned, in key, literal value, key, literal value, etc. order.
|
||||
*
|
||||
* @return the number of rows modified by this action.
|
||||
*/
|
||||
protected <T> int updateLiteral (
|
||||
Class<T> type, Key key, String ... fieldsValues)
|
||||
protected <T> int updateLiteral (Class<T> type, Key key, String ... fieldsValues)
|
||||
throws PersistenceException
|
||||
{
|
||||
// separate the arguments into keys and values
|
||||
@@ -319,8 +304,7 @@ public class DepotRepository
|
||||
final DepotMarshaller marsh = _ctx.getMarshaller(type);
|
||||
return _ctx.invoke(new Modifier(key) {
|
||||
public int invoke (Connection conn) throws SQLException {
|
||||
PreparedStatement stmt = marsh.createLiteralUpdate(
|
||||
conn, _key, fields, values);
|
||||
PreparedStatement stmt = marsh.createLiteralUpdate(conn, _key, fields, values);
|
||||
try {
|
||||
return stmt.executeUpdate();
|
||||
} finally {
|
||||
@@ -331,13 +315,11 @@ public class DepotRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the supplied persisent object in the database. If it has no
|
||||
* primary key assigned (it is null or zero), it will be inserted
|
||||
* directly. Otherwise an update will first be attempted and if that
|
||||
* matches zero rows, the object will be inserted.
|
||||
* Stores the supplied persisent object in the database. If it has no primary key assigned (it
|
||||
* is null or zero), it will be inserted directly. Otherwise an update will first be attempted
|
||||
* and if that matches zero rows, the object will be inserted.
|
||||
*
|
||||
* @return the number of rows modified by this action, this should always
|
||||
* be one.
|
||||
* @return the number of rows modified by this action, this should always be one.
|
||||
*/
|
||||
protected int store (final Object record)
|
||||
throws PersistenceException
|
||||
@@ -348,8 +330,8 @@ public class DepotRepository
|
||||
public int invoke (Connection conn) throws SQLException {
|
||||
PreparedStatement stmt = null;
|
||||
try {
|
||||
// if our primary key is null or is the integer 0, assume
|
||||
// the record has never before been persisted and insert
|
||||
// if our primary key is null or is the integer 0, assume the record has never
|
||||
// before been persisted and insert
|
||||
if (_key != null && !Integer.valueOf(0).equals(_key)) {
|
||||
stmt = marsh.createUpdate(conn, record, _key);
|
||||
int mods = stmt.executeUpdate();
|
||||
@@ -359,8 +341,8 @@ public class DepotRepository
|
||||
stmt.close();
|
||||
}
|
||||
|
||||
// if the update modified zero rows or the primary key was
|
||||
// obviously unset, do an insertion
|
||||
// if the update modified zero rows or the primary key was obviously unset, do
|
||||
// an insertion
|
||||
updateKey(marsh.assignPrimaryKey(conn, record, false));
|
||||
stmt = marsh.createInsert(conn, record);
|
||||
int mods = stmt.executeUpdate();
|
||||
@@ -375,36 +357,33 @@ public class DepotRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all persistent objects from the database with a primary key
|
||||
* matching the primary key of the supplied object.
|
||||
* Deletes all persistent objects from the database with a primary key matching the primary key
|
||||
* of the supplied object.
|
||||
*
|
||||
* @return the number of rows deleted by this action.
|
||||
*/
|
||||
protected <T> int delete (T record)
|
||||
throws PersistenceException
|
||||
{
|
||||
@SuppressWarnings("unchecked") Class<T> type =
|
||||
(Class<T>)record.getClass();
|
||||
@SuppressWarnings("unchecked") Class<T> type = (Class<T>)record.getClass();
|
||||
DepotMarshaller<T> marsh = _ctx.getMarshaller(type);
|
||||
return deleteAll(type, marsh.getPrimaryKey(record));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all persistent objects from the database with a primary key
|
||||
* matching the supplied primary key.
|
||||
* Deletes all persistent objects from the database with a primary key matching the supplied
|
||||
* primary key.
|
||||
*
|
||||
* @return the number of rows deleted by this action.
|
||||
*/
|
||||
protected <T> int delete (Class<T> type, Comparable primaryKey)
|
||||
throws PersistenceException
|
||||
{
|
||||
return deleteAll(
|
||||
type, _ctx.getMarshaller(type).makePrimaryKey(primaryKey));
|
||||
return deleteAll(type, _ctx.getMarshaller(type).makePrimaryKey(primaryKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all persistent objects from the database that match the supplied
|
||||
* key.
|
||||
* Deletes all persistent objects from the database that match the supplied key.
|
||||
*
|
||||
* @return the number of rows deleted by this action.
|
||||
*/
|
||||
@@ -424,11 +403,12 @@ public class DepotRepository
|
||||
});
|
||||
}
|
||||
|
||||
protected static abstract class CollectionQuery<T extends Collection>
|
||||
extends Query<T>
|
||||
protected static abstract class CollectionQuery<T extends Collection> extends Query<T>
|
||||
{
|
||||
public CollectionQuery (Key key) {
|
||||
super(key);
|
||||
public CollectionQuery (PersistenceContext ctx, Class type, Key key)
|
||||
throws PersistenceException
|
||||
{
|
||||
super(ctx, type, key);
|
||||
}
|
||||
|
||||
public abstract T invoke (Connection conn) throws SQLException;
|
||||
|
||||
@@ -39,16 +39,15 @@ import javax.persistence.Id;
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
/**
|
||||
* Handles the marshalling and unmarshalling of a particular field of a
|
||||
* persistent object.
|
||||
* Handles the marshalling and unmarshalling of a particular field of a persistent object.
|
||||
*
|
||||
* @see DepotMarshaller
|
||||
*/
|
||||
public abstract class FieldMarshaller
|
||||
{
|
||||
/**
|
||||
* Creates and returns a field marshaller for the specified field. Throws
|
||||
* an exception if the field in question cannot be marshalled.
|
||||
* Creates and returns a field marshaller for the specified field. Throws an exception if the
|
||||
* field in question cannot be marshalled.
|
||||
*/
|
||||
public static FieldMarshaller createMarshaller (Field field)
|
||||
{
|
||||
@@ -158,9 +157,8 @@ public abstract class FieldMarshaller
|
||||
_field = field;
|
||||
_columnName = field.getName();
|
||||
|
||||
// read our column metadata from the annotation (if it exists);
|
||||
// annoyingly we can't create a Column instance to read the defaults so
|
||||
// we have to duplicate them here
|
||||
// read our column metadata from the annotation (if it exists); annoyingly we can't create
|
||||
// a Column instance to read the defaults so we have to duplicate them here
|
||||
int length = 255;
|
||||
boolean nullable = true;
|
||||
boolean unique = false;
|
||||
|
||||
@@ -22,50 +22,69 @@ package com.samskivert.jdbc.depot;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.samskivert.jdbc.depot.clause.QueryClause;
|
||||
import com.samskivert.jdbc.depot.expression.ColumnExpression;
|
||||
|
||||
|
||||
/**
|
||||
* Encapsulates a key used to match persistent objects in a query.
|
||||
*
|
||||
* TODO: Is it useful for this to implement QueryClause? Can it be meaningfully put on a peer level
|
||||
* with the other clauses?
|
||||
*/
|
||||
public class Key
|
||||
implements QueryClause
|
||||
{
|
||||
public String[] indices;
|
||||
public ColumnExpression[] columns;
|
||||
public Comparable[] values;
|
||||
|
||||
public Key (String index, Comparable value)
|
||||
{
|
||||
this(new String[] { index }, new Comparable[] { value });
|
||||
this(new ColumnExpression(null, index), value);
|
||||
}
|
||||
|
||||
public Key (String index1, Comparable value1,
|
||||
String index2, Comparable value2)
|
||||
public Key (ColumnExpression column, Comparable value)
|
||||
{
|
||||
this(new String[] { index1, index2 },
|
||||
this(new ColumnExpression[] { column }, new Comparable[] { value });
|
||||
}
|
||||
|
||||
public Key (String index1, Comparable value1, String index2, Comparable value2)
|
||||
{
|
||||
this(new ColumnExpression[] { new ColumnExpression(null, index1),
|
||||
new ColumnExpression(null, index2) },
|
||||
new Comparable[] { value1, value2 });
|
||||
}
|
||||
|
||||
public Key (String[] indices, Comparable[] values)
|
||||
public Key (ColumnExpression[] columns, Comparable[] values)
|
||||
{
|
||||
this.indices = indices;
|
||||
this.columns = columns;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public String toWhereClause ()
|
||||
{
|
||||
StringBuilder where = new StringBuilder();
|
||||
for (int ii = 0; ii < indices.length; ii++) {
|
||||
if (ii > 0) {
|
||||
where.append(" and ");
|
||||
}
|
||||
where.append(indices[ii]).append(" = ?");
|
||||
}
|
||||
return where.toString();
|
||||
|
||||
public List<Class> getClassSet() {
|
||||
return Arrays.asList(new Class[] { });
|
||||
}
|
||||
|
||||
public void bindArguments (PreparedStatement stmt, int startIdx)
|
||||
public void appendClause (Query query, StringBuilder builder)
|
||||
{
|
||||
for (int ii = 0; ii < columns.length; ii++) {
|
||||
if (ii > 0) {
|
||||
builder.append(" and ");
|
||||
}
|
||||
columns[ii].appendExpression(query, builder);
|
||||
builder.append(" = ?");
|
||||
}
|
||||
}
|
||||
|
||||
public int bindArguments (PreparedStatement stmt, int startIdx)
|
||||
throws SQLException
|
||||
{
|
||||
for (int ii = 0; ii < indices.length; ii++) {
|
||||
for (int ii = 0; ii < values.length; ii++) {
|
||||
stmt.setObject(startIdx++, values[ii]);
|
||||
}
|
||||
return startIdx;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ import java.sql.SQLException;
|
||||
*/
|
||||
public interface KeyGenerator
|
||||
{
|
||||
/** If true, this key generator will be run after the insert statement, if
|
||||
* false, it will be run before. */
|
||||
/** If true, this key generator will be run after the insert statement, if false, it will be
|
||||
* run before. */
|
||||
public boolean isPostFactum ();
|
||||
|
||||
/** Prepares the generator for operation. */
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
package com.samskivert.jdbc.depot;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.persistence.TableGenerator;
|
||||
|
||||
import java.sql.Connection;
|
||||
@@ -36,8 +37,7 @@ import com.samskivert.jdbc.DuplicateKeyException;
|
||||
public class PersistenceContext
|
||||
{
|
||||
/** Map {@link TableGenerator} instances by name. */
|
||||
public HashMap<String, TableGenerator> tableGenerators =
|
||||
new HashMap<String, TableGenerator>();
|
||||
public HashMap<String, TableGenerator> tableGenerators = new HashMap<String, TableGenerator>();
|
||||
|
||||
/**
|
||||
* Creates a persistence context that will use the supplied provider to
|
||||
@@ -80,6 +80,7 @@ public class PersistenceContext
|
||||
/**
|
||||
* Invokes a non-modifying query and returns its result.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T invoke (Query<T> query)
|
||||
throws PersistenceException
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006 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
|
||||
@@ -21,24 +21,212 @@
|
||||
package com.samskivert.jdbc.depot;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.samskivert.io.PersistenceException;
|
||||
import com.samskivert.jdbc.depot.clause.FieldOverrideClause;
|
||||
import com.samskivert.jdbc.depot.clause.GroupByClause;
|
||||
import com.samskivert.jdbc.depot.clause.JoinClause;
|
||||
import com.samskivert.jdbc.depot.clause.LimitClause;
|
||||
import com.samskivert.jdbc.depot.clause.OrderByClause;
|
||||
import com.samskivert.jdbc.depot.clause.QueryClause;
|
||||
|
||||
/**
|
||||
* Encapsulates a non-modifying query of persistent objects.
|
||||
*/
|
||||
public abstract class Query<T>
|
||||
{
|
||||
public Key getKey ()
|
||||
{
|
||||
return _key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual JDBC operations associated with this query.
|
||||
*/
|
||||
public abstract T invoke (Connection conn) throws SQLException;
|
||||
|
||||
protected Query (Key key)
|
||||
/**
|
||||
* Maps a class referenced by this query to its associated table.
|
||||
*
|
||||
* This method is called by individual clauses.
|
||||
*/
|
||||
public String getTableName (Class cl)
|
||||
{
|
||||
_key = key;
|
||||
return _classMap.get(cl).getTableName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a class referenced by this query to the abbreviation used for its associated table. The
|
||||
* abbreviation is transientand only has meaning within the scope of this particular query.
|
||||
*
|
||||
* This method is called by individual clauses.
|
||||
*/
|
||||
public String getTableAbbreviation (Class cl)
|
||||
{
|
||||
if (cl.equals(_mainType)) {
|
||||
return "T";
|
||||
}
|
||||
int ix = _classList.indexOf(cl);
|
||||
if (ix < 0) {
|
||||
throw new IllegalArgumentException("Unknown persistence class: " + cl);
|
||||
}
|
||||
return "T" + (ix+1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the data in this Query object into a SQL query suited to instantiate a persistent
|
||||
* object given the supplied key and clauses. These clauses are assumed to contain no
|
||||
* conflicts.
|
||||
*
|
||||
* If no key is supplied all instances will be loaded.
|
||||
*/
|
||||
public <T> PreparedStatement createQuery (Connection conn)
|
||||
throws SQLException
|
||||
{
|
||||
if (_mainType == null) { // internal error
|
||||
throw new RuntimeException("createQuery() called with _mainClass == null");
|
||||
}
|
||||
|
||||
DepotMarshaller mainMarshaller = _classMap.get(_mainType);
|
||||
String[] fields = mainMarshaller._allFields;
|
||||
StringBuilder query = new StringBuilder("select ");
|
||||
for (int ii = 0; ii < fields.length; ii ++) {
|
||||
if (ii > 0) {
|
||||
query.append(", ");
|
||||
}
|
||||
FieldOverrideClause clause = _disMap.get(fields[ii]);
|
||||
if (clause != null) {
|
||||
clause.appendClause(this, query);
|
||||
} else {
|
||||
query.append("T.").append(fields[ii]);
|
||||
}
|
||||
}
|
||||
query.append(" from " + mainMarshaller.getTableName() + " as T ");
|
||||
|
||||
for (JoinClause clause : _joinClauses) {
|
||||
query.append(" inner join " );
|
||||
clause.appendClause(this, query);
|
||||
}
|
||||
if (_key != null) {
|
||||
query.append(" where ");
|
||||
_key.appendClause(this, query);
|
||||
}
|
||||
if (_groupBy != null) {
|
||||
query.append(" group by ");
|
||||
_groupBy.appendClause(this, query);
|
||||
}
|
||||
if (_orderBy != null) {
|
||||
query.append(" order by ");
|
||||
_orderBy.appendClause(this, query);
|
||||
}
|
||||
if (_limit != null) {
|
||||
query.append(" limit ");
|
||||
_limit.appendClause(this, query);
|
||||
}
|
||||
|
||||
PreparedStatement pstmt = conn.prepareStatement(query.toString());
|
||||
int argIdx = 1;
|
||||
if (_key != null) {
|
||||
argIdx = _key.bindArguments(pstmt, argIdx);
|
||||
}
|
||||
if (_groupBy != null) {
|
||||
argIdx = _groupBy.bindArguments(pstmt, argIdx);
|
||||
}
|
||||
if (_orderBy != null) {
|
||||
argIdx = _orderBy.bindArguments(pstmt, argIdx);
|
||||
}
|
||||
if (_limit != null) {
|
||||
argIdx = _limit.bindArguments(pstmt, argIdx);
|
||||
}
|
||||
|
||||
return pstmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Query object to generate one or more instances of the specified persistent
|
||||
* class, as dictated by the key and query clauses. A persistence context is supplied for
|
||||
* instantiation of marshallers, which may trigger table creations and schema migrations.
|
||||
*/
|
||||
protected Query (PersistenceContext ctx, Class type, Key key, QueryClause... clauses)
|
||||
throws PersistenceException
|
||||
{
|
||||
_key = key;
|
||||
_mainType = type;
|
||||
Set<Class> classSet = new HashSet<Class>();
|
||||
if (type != null) {
|
||||
classSet.add(type);
|
||||
}
|
||||
if (_key != null) {
|
||||
classSet.addAll(_key.getClassSet());
|
||||
}
|
||||
|
||||
for (QueryClause clause : clauses) {
|
||||
if (clause instanceof JoinClause) {
|
||||
_joinClauses.add((JoinClause) clause);
|
||||
classSet.addAll(((JoinClause) clause).getClassSet());
|
||||
|
||||
} else if (clause instanceof FieldOverrideClause) {
|
||||
_disMap.put(((FieldOverrideClause) clause).getField(),
|
||||
((FieldOverrideClause) clause));
|
||||
|
||||
} else if (clause instanceof OrderByClause) {
|
||||
if (_orderBy != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Query can't contain multiple OrderBy clauses.");
|
||||
}
|
||||
_orderBy = (OrderByClause) clause;
|
||||
|
||||
} else if (clause instanceof GroupByClause) {
|
||||
if (_groupBy != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Query can't contain multiple GroupBy clauses.");
|
||||
}
|
||||
_groupBy = (GroupByClause) clause;
|
||||
|
||||
} else if (clause instanceof LimitClause) {
|
||||
if (_limit != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Query can't contain multiple Limit clauses.");
|
||||
}
|
||||
_limit = (LimitClause) clause;
|
||||
}
|
||||
}
|
||||
_classMap = new HashMap<Class, DepotMarshaller>();
|
||||
|
||||
for (Class<?> c : classSet) {
|
||||
_classMap.put(c, ctx.getMarshaller(c));
|
||||
}
|
||||
_classList = new ArrayList<Class>(classSet);
|
||||
}
|
||||
|
||||
/** The key to this query, or null. Translated into a WHERE clause. */
|
||||
protected Key _key;
|
||||
|
||||
/** The persistent class to instantiate for the results. */
|
||||
protected Class _mainType;
|
||||
|
||||
/** A list of referenced classes, used to generate table abbreviations. */
|
||||
protected List<Class> _classList;
|
||||
|
||||
/** Classes mapped to marshallers, used for table names and field lists. */
|
||||
protected Map<Class, DepotMarshaller> _classMap;
|
||||
|
||||
/** Persistent class fields mapped to field override clauses. */
|
||||
protected Map<String, FieldOverrideClause> _disMap = new HashMap<String, FieldOverrideClause>();
|
||||
|
||||
/** A list of join clauses, each potentially referencing a new class. */
|
||||
protected List<JoinClause> _joinClauses = new ArrayList<JoinClause>();
|
||||
|
||||
/** The order by clause, if any. */
|
||||
protected OrderByClause _orderBy;
|
||||
|
||||
/** The group by clause, if any. */
|
||||
protected GroupByClause _groupBy;
|
||||
|
||||
/** The limit clause, if any. */
|
||||
protected LimitClause _limit;
|
||||
}
|
||||
|
||||
@@ -97,17 +97,15 @@ public class TableKeyGenerator implements KeyGenerator
|
||||
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
if (!rs.next()) {
|
||||
throw new SQLException(
|
||||
"Failed to find next primary key value [table=" + _table +
|
||||
", column=" + _valueColumnName +
|
||||
", where=" + _pkColumnName + "=" + _pkColumnValue + "]");
|
||||
throw new SQLException("Failed to find next primary key value [table=" + _table +
|
||||
", column=" + _valueColumnName +
|
||||
", where=" + _pkColumnName + "=" + _pkColumnValue + "]");
|
||||
}
|
||||
int val = rs.getInt(1);
|
||||
JDBCUtil.close(stmt);
|
||||
|
||||
stmt = conn.prepareStatement(
|
||||
"UPDATE " + _table + " SET " + _valueColumnName + " = ? " +
|
||||
"WHERE " + _pkColumnName + " = ?");
|
||||
stmt = conn.prepareStatement("UPDATE " + _table + " SET " + _valueColumnName + " = ? " +
|
||||
"WHERE " + _pkColumnName + " = ?");
|
||||
stmt.setInt(1, val + _allocationSize);
|
||||
stmt.setString(2, _pkColumnValue);
|
||||
stmt.executeUpdate();
|
||||
@@ -118,8 +116,11 @@ public class TableKeyGenerator implements KeyGenerator
|
||||
}
|
||||
}
|
||||
|
||||
/** Convenience function to return a value or a default fallback. */
|
||||
protected static String defStr (String value, String def) {
|
||||
/**
|
||||
* Convenience function to return a value or a default fallback.
|
||||
*/
|
||||
protected static String defStr (String value, String def)
|
||||
{
|
||||
if (value == null || value.trim().length() == 0) {
|
||||
return def;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006 Michael Bayne, Pär Winzell
|
||||
//
|
||||
// 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.depot.clause;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.samskivert.io.PersistenceException;
|
||||
import com.samskivert.jdbc.depot.Query;
|
||||
import com.samskivert.jdbc.depot.expression.SQLExpression;
|
||||
|
||||
/**
|
||||
* Redirects one field of the persistent object we're creating from its default associated column
|
||||
* to a general {@link SQLExpression}.
|
||||
*
|
||||
* Thus the select portion of a query can include a reference to a different column in a different
|
||||
* table through a {@link ColumnExpression}, or a literal expression such as COUNT(*) through a
|
||||
* {@link LiteralExpression}.
|
||||
*/
|
||||
public class FieldOverrideClause
|
||||
implements QueryClause
|
||||
{
|
||||
public FieldOverrideClause (String field, SQLExpression override)
|
||||
throws PersistenceException
|
||||
{
|
||||
super();
|
||||
_field = field;
|
||||
_override = override;
|
||||
}
|
||||
|
||||
/** The field we're overriding. The Query object uses this for indexing. */
|
||||
public String getField ()
|
||||
{
|
||||
return _field;
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public Collection<Class> getClassSet ()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public void appendClause (Query query, StringBuilder builder)
|
||||
{
|
||||
_override.appendExpression(query, builder);
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public int bindArguments (PreparedStatement pstmt, int argIdx)
|
||||
throws SQLException
|
||||
{
|
||||
return argIdx;
|
||||
}
|
||||
|
||||
/** The name of the field on the persistent object to override. */
|
||||
protected String _field;
|
||||
|
||||
/** The overriding expression. */
|
||||
protected SQLExpression _override;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006 Michael Bayne, Pär Winzell
|
||||
//
|
||||
// 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.depot.clause;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.samskivert.jdbc.depot.Query;
|
||||
import com.samskivert.jdbc.depot.expression.SQLExpression;
|
||||
|
||||
/**
|
||||
* Represents a GROUP BY clause.
|
||||
*/
|
||||
public class GroupByClause
|
||||
implements QueryClause
|
||||
{
|
||||
public GroupByClause (SQLExpression... values)
|
||||
{
|
||||
super();
|
||||
_values = values;
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public Collection<Class> getClassSet ()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public void appendClause (Query query, StringBuilder builder)
|
||||
{
|
||||
for (int ii = 0; ii < _values.length; ii++) {
|
||||
if (ii > 0) {
|
||||
builder.append(", ");
|
||||
}
|
||||
_values[ii].appendExpression(query, builder);
|
||||
}
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public int bindArguments (PreparedStatement pstmt, int argIdx)
|
||||
throws SQLException
|
||||
{
|
||||
for (int ii = 0; ii < _values.length; ii++) {
|
||||
argIdx = _values[ii].bindArguments(pstmt, argIdx);
|
||||
}
|
||||
return argIdx;
|
||||
}
|
||||
|
||||
/** The expressions that are generated for the clause. */
|
||||
protected SQLExpression[] _values;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006 Michael Bayne, Pär Winzell
|
||||
//
|
||||
// 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.depot.clause;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.samskivert.io.PersistenceException;
|
||||
import com.samskivert.jdbc.depot.Query;
|
||||
|
||||
/**
|
||||
* Represents a JOIN -- currently just an INNER one.
|
||||
*/
|
||||
public class JoinClause
|
||||
implements QueryClause
|
||||
{
|
||||
public JoinClause (String pCol, Class joinClass, String jCol)
|
||||
throws PersistenceException
|
||||
{
|
||||
super();
|
||||
_primaryColumn = pCol;
|
||||
_joinClass = joinClass;
|
||||
_joinColumn = jCol;
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public Collection<Class> getClassSet () {
|
||||
return Arrays.asList(new Class[] { _joinClass });
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public void appendClause (Query query, StringBuilder builder)
|
||||
{
|
||||
String jAbbrev = query.getTableAbbreviation(_joinClass);
|
||||
builder.append(query.getTableName(_joinClass) + " as " + jAbbrev + " on T." +
|
||||
_primaryColumn + " = " + jAbbrev + "." + _joinColumn);
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public int bindArguments (PreparedStatement pstmt, int argIdx)
|
||||
throws SQLException
|
||||
{
|
||||
return argIdx;
|
||||
}
|
||||
|
||||
/** The column on which to join. */
|
||||
protected String _primaryColumn;
|
||||
|
||||
/** The class of the table we're to join against. */
|
||||
protected Class _joinClass;
|
||||
|
||||
/** The column we're joining against. */
|
||||
protected String _joinColumn;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006 Michael Bayne, Pär Winzell
|
||||
//
|
||||
// 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.depot.clause;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.samskivert.jdbc.depot.Query;
|
||||
|
||||
/**
|
||||
* Represents a LIMIT/OFFSET clause, for pagination.
|
||||
*/
|
||||
public class LimitClause
|
||||
implements QueryClause
|
||||
{
|
||||
public LimitClause (int offset, int count)
|
||||
{
|
||||
super();
|
||||
_offset = offset;
|
||||
_count = count;
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public Collection<Class> getClassSet ()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public void appendClause (Query query, StringBuilder builder)
|
||||
{
|
||||
builder.append("? offset ?");
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public int bindArguments (PreparedStatement pstmt, int argIdx)
|
||||
throws SQLException
|
||||
{
|
||||
pstmt.setObject(argIdx++, _count);
|
||||
pstmt.setObject(argIdx++, _offset);
|
||||
return argIdx;
|
||||
}
|
||||
|
||||
/** The first row of the result set to return. */
|
||||
protected int _offset;
|
||||
|
||||
/** The number of rows, at most, to return. */
|
||||
protected int _count;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006 Michael Bayne, Pär Winzell
|
||||
//
|
||||
// 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.depot.clause;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.samskivert.jdbc.depot.Query;
|
||||
import com.samskivert.jdbc.depot.expression.SQLExpression;
|
||||
|
||||
/**
|
||||
* Represents an ORDER BY clause.
|
||||
*/
|
||||
public class OrderByClause
|
||||
implements QueryClause
|
||||
{
|
||||
public OrderByClause (SQLExpression... values)
|
||||
{
|
||||
super();
|
||||
_values = values;
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public Collection<Class> getClassSet ()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public void appendClause (Query query, StringBuilder builder)
|
||||
{
|
||||
for (int ii = 0; ii < _values.length; ii++) {
|
||||
if (ii > 0) {
|
||||
builder.append(", ");
|
||||
}
|
||||
_values[ii].appendExpression(query, builder);
|
||||
}
|
||||
builder.append(_ascending ? " ASC" : " DESC");
|
||||
}
|
||||
|
||||
// from QueryClause
|
||||
public int bindArguments (PreparedStatement pstmt, int argIdx)
|
||||
throws SQLException
|
||||
{
|
||||
for (int ii = 0; ii < _values.length; ii++) {
|
||||
argIdx = _values[ii].bindArguments(pstmt, argIdx);
|
||||
}
|
||||
return argIdx;
|
||||
}
|
||||
|
||||
/** The expressions that are generated for the clause. */
|
||||
protected SQLExpression[] _values;
|
||||
|
||||
/** Whether the ordering is to be ascending rather than descending. */
|
||||
protected boolean _ascending;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006 Michael Bayne, Pär Winzell
|
||||
//
|
||||
// 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.depot.clause;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.samskivert.jdbc.depot.Query;
|
||||
|
||||
/**
|
||||
* Represents a piece or modifier of an SQL query.
|
||||
*/
|
||||
public interface QueryClause
|
||||
{
|
||||
/**
|
||||
* Return a set of all persistent classes referenced by this clause. Null may be returned if
|
||||
* no classes are rererenced.
|
||||
*/
|
||||
public Collection<Class> getClassSet ();
|
||||
|
||||
/**
|
||||
* Construct the SQL form of this query clause The implementor is invited to call methods on
|
||||
* the Query object to e.g. resolve the current table abbreviations associated with classes.
|
||||
*/
|
||||
public void appendClause (Query query, StringBuilder builder);
|
||||
|
||||
/**
|
||||
* Bind any objects that were referenced in the generated SQL. For each ? that appears in the
|
||||
* SQL, precisely one parameter must be claimed and bound in this method, and argIdx
|
||||
* incremented and returned.
|
||||
*/
|
||||
public int bindArguments (PreparedStatement pstmt, int argIdx)
|
||||
throws SQLException;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006 Michael Bayne, Pär Winzell
|
||||
//
|
||||
// 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.depot.expression;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.samskivert.jdbc.depot.Query;
|
||||
|
||||
/**
|
||||
* An expression identifying a column of a class, e.g. GameRecord.itemId. If no class is given, no
|
||||
* disambiguation occurs in the generated SQL.
|
||||
*/
|
||||
public class ColumnExpression
|
||||
implements SQLExpression
|
||||
{
|
||||
public ColumnExpression (String column)
|
||||
{
|
||||
this(null, column);
|
||||
}
|
||||
|
||||
public ColumnExpression (Class c, String column)
|
||||
{
|
||||
super();
|
||||
_class = c;
|
||||
_column = column;
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void appendExpression (Query query, StringBuilder builder)
|
||||
{
|
||||
if (_class == null || query == null) {
|
||||
builder.append(_column);
|
||||
} else {
|
||||
String tRef = query.getTableAbbreviation(_class);
|
||||
builder.append(tRef).append(".").append(_column);
|
||||
}
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public int bindArguments (PreparedStatement pstmt, int argIdx)
|
||||
throws SQLException
|
||||
{
|
||||
return argIdx;
|
||||
}
|
||||
|
||||
/** The table that hosts the column we reference, or null. */
|
||||
protected Class _class;
|
||||
|
||||
/** The name of the column we reference. */
|
||||
protected String _column;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006 Michael Bayne, Pär Winzell
|
||||
//
|
||||
// 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.depot.expression;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.samskivert.jdbc.depot.Query;
|
||||
|
||||
/**
|
||||
* An expression for things we don't support natively, e.g. COUNT(*).
|
||||
*/
|
||||
public class LiteralExpression
|
||||
implements SQLExpression
|
||||
{
|
||||
public LiteralExpression (String text)
|
||||
{
|
||||
super();
|
||||
_text = text;
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void appendExpression (Query query, StringBuilder builder)
|
||||
{
|
||||
builder.append(_text);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public int bindArguments (PreparedStatement pstmt, int argIdx)
|
||||
throws SQLException
|
||||
{
|
||||
return argIdx;
|
||||
}
|
||||
|
||||
/** The literal text of this expression, e.g. COUNT(*) */
|
||||
protected String _text;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006 Michael Bayne, Pär Winzell
|
||||
//
|
||||
// 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.depot.expression;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.samskivert.jdbc.depot.Query;
|
||||
|
||||
/**
|
||||
* Represents an SQL expression, e.g. column name, function, or constant.
|
||||
*/
|
||||
public interface SQLExpression
|
||||
{
|
||||
/**
|
||||
* Construct the SQL form of this expression. The implementor is invited to call methods on the
|
||||
* Query object to e.g. resolve the current table abbreviations associated with classes.
|
||||
*/
|
||||
public void appendExpression (Query query, StringBuilder builder);
|
||||
|
||||
/**
|
||||
* Bind any objects that were referenced in the generated SQL. For each ? that appears in the
|
||||
* SQL, precisely one parameter must be claimed and bound in this method, and argIdx
|
||||
* incremented and returned.
|
||||
*/
|
||||
public int bindArguments (PreparedStatement pstmt, int argIdx)
|
||||
throws SQLException;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006 Michael Bayne, Pär Winzell
|
||||
//
|
||||
// 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.depot.expression;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import com.samskivert.jdbc.depot.Query;
|
||||
|
||||
/**
|
||||
* A Java value that is bound as a parameter to the query, e.g. 1 or 'abc'.
|
||||
*/
|
||||
public class ValueExpression
|
||||
implements SQLExpression
|
||||
{
|
||||
public ValueExpression (Comparable _value)
|
||||
{
|
||||
super();
|
||||
this._value = _value;
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void appendExpression (Query query, StringBuilder builder)
|
||||
{
|
||||
builder.append("?");
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public int bindArguments (PreparedStatement pstmt, int argIdx)
|
||||
throws SQLException
|
||||
{
|
||||
pstmt.setObject(argIdx ++, _value);
|
||||
return argIdx;
|
||||
}
|
||||
|
||||
/** The value to be bound to the SQL parameters. */
|
||||
protected Comparable _value;
|
||||
}
|
||||
Reference in New Issue
Block a user