Index: org/exolab/castor/jdo/drivers/MultiRSCallQuery.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/jdo/drivers/MultiRSCallQuery.java,v
retrieving revision 1.4
diff -u -r1.4 MultiRSCallQuery.java
--- org/exolab/castor/jdo/drivers/MultiRSCallQuery.java 25 Mar 2004 12:31:06 -0000 1.4
+++ org/exolab/castor/jdo/drivers/MultiRSCallQuery.java 15 Mar 2005 13:35:51 -0000
@@ -59,6 +59,7 @@
import org.exolab.castor.jdo.QueryException;
import org.exolab.castor.jdo.engine.SQLTypes;
import org.exolab.castor.mapping.AccessMode;
+import org.exolab.castor.persist.ProposedObject;
import org.exolab.castor.persist.spi.Complex;
import org.exolab.castor.persist.spi.PersistenceQuery;
import org.exolab.castor.util.Messages;
@@ -235,10 +236,12 @@
}
- public Object fetch(Object[] fields,Object identity) throws ObjectNotFoundException, PersistenceException
+ public Object fetch(ProposedObject proposedObject, Object identity) throws ObjectNotFoundException, PersistenceException
{
Object stamp = null;
+ Object[] fields = proposedObject.getFields();
+
try {
// Load all the fields of the object including one-one relations
// index 0 belongs to the identity
Index: org/exolab/castor/jdo/drivers/PostgreSQLCallQuery.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/jdo/drivers/PostgreSQLCallQuery.java,v
retrieving revision 1.4
diff -u -r1.4 PostgreSQLCallQuery.java
--- org/exolab/castor/jdo/drivers/PostgreSQLCallQuery.java 25 Mar 2004 12:32:01 -0000 1.4
+++ org/exolab/castor/jdo/drivers/PostgreSQLCallQuery.java 15 Mar 2005 13:35:51 -0000
@@ -60,6 +60,7 @@
import org.exolab.castor.jdo.engine.JDBCSyntax;
import org.exolab.castor.jdo.engine.SQLTypes;
import org.exolab.castor.mapping.AccessMode;
+import org.exolab.castor.persist.ProposedObject;
import org.exolab.castor.persist.spi.Complex;
import org.exolab.castor.persist.spi.PersistenceQuery;
import org.exolab.castor.util.Messages;
@@ -248,10 +249,10 @@
}
- public Object fetch(Object[] fields,Object identity) throws ObjectNotFoundException, PersistenceException
+ public Object fetch(ProposedObject proposedObject, Object identity) throws ObjectNotFoundException, PersistenceException
{
Object stamp = null;
-
+ Object[] fields = proposedObject.getFields();
try {
// Load all the fields of the object including one-one relations
Index: org/exolab/castor/jdo/drivers/ReturnedRSCallQuery.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/jdo/drivers/ReturnedRSCallQuery.java,v
retrieving revision 1.3
diff -u -r1.3 ReturnedRSCallQuery.java
--- org/exolab/castor/jdo/drivers/ReturnedRSCallQuery.java 25 Mar 2004 12:24:22 -0000 1.3
+++ org/exolab/castor/jdo/drivers/ReturnedRSCallQuery.java 15 Mar 2005 13:35:51 -0000
@@ -59,6 +59,7 @@
import org.exolab.castor.jdo.QueryException;
import org.exolab.castor.jdo.engine.SQLTypes;
import org.exolab.castor.mapping.AccessMode;
+import org.exolab.castor.persist.ProposedObject;
import org.exolab.castor.persist.spi.Complex;
import org.exolab.castor.persist.spi.PersistenceQuery;
import org.exolab.castor.util.Messages;
@@ -228,10 +229,10 @@
}
- public Object fetch(Object[] fields,Object identity) throws ObjectNotFoundException, PersistenceException
+ public Object fetch(ProposedObject proposedObject, Object identity) throws ObjectNotFoundException, PersistenceException
{
Object stamp = null;
-
+ Object[] fields = proposedObject.getFields();
try {
// Load all the fields of the object including one-one relations
Index: org/exolab/castor/jdo/engine/DatabaseImpl.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/jdo/engine/DatabaseImpl.java,v
retrieving revision 1.17
diff -u -r1.17 DatabaseImpl.java
--- org/exolab/castor/jdo/engine/DatabaseImpl.java 10 Jan 2005 21:22:46 -0000 1.17
+++ org/exolab/castor/jdo/engine/DatabaseImpl.java 15 Mar 2005 13:35:52 -0000
@@ -313,7 +313,15 @@
if ( info == null )
throw new ClassNotPersistenceCapableException( Messages.format( "persist.classNotPersistenceCapable", type.getName() ) );
- return tx.load( info.engine, info.molder, identity, object, null );
+ ProposedObject proposedObject = new ProposedObject();
+ proposedObject.setObject(object);
+ if (object != null) {
+ proposedObject.setProposedClass(object.getClass());
+ }
+
+ Object loaded = tx.load( info.engine, info.molder, identity, proposedObject, null );
+ object = proposedObject.getObject();
+ return loaded;
}
public Object load( Class type, Complex identity )
throws TransactionNotInProgressException, ObjectNotFoundException,
@@ -363,7 +371,11 @@
if ( info == null )
throw new ClassNotPersistenceCapableException( Messages.format("persist.classNotPersistenceCapable", type.getName()) );
- return tx.load( info.engine, info.molder, identity, null, mode );
+ ProposedObject proposedObject = new ProposedObject();
+ proposedObject.setObject(null);
+ proposedObject.setProposedClass(null);
+
+ return tx.load( info.engine, info.molder, identity, proposedObject, mode );
}
public void create( Object object )
Index: org/exolab/castor/jdo/engine/OQLQueryImpl.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/jdo/engine/OQLQueryImpl.java,v
retrieving revision 1.13
diff -u -r1.13 OQLQueryImpl.java
--- org/exolab/castor/jdo/engine/OQLQueryImpl.java 13 Dec 2004 10:29:19 -0000 1.13
+++ org/exolab/castor/jdo/engine/OQLQueryImpl.java 15 Mar 2005 13:35:52 -0000
@@ -47,6 +47,8 @@
package org.exolab.castor.jdo.engine;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.exolab.castor.jdo.*;
import org.exolab.castor.jdo.oql.*;
import org.exolab.castor.mapping.AccessMode;
@@ -75,6 +77,7 @@
implements Query, OQLQuery
{
+ private final static Log log = LogFactory.getLog (OQLQueryImpl.class);
private LockEngine _dbEngine;
@@ -249,7 +252,9 @@
_objClass = walker.getObjClass();
_clsDesc = walker.getClassDescriptor();
+ log.debug ("class descriptor = " + _clsDesc);
_expr = walker.getQueryExpression();
+ log.debug ("sql expression = " + _expr);
_paramInfo = walker.getParamInfo();
_projectionType = walker.getProjectionType();
_pathInfo = walker.getPathInfo();
Index: org/exolab/castor/jdo/engine/SQLEngine.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/jdo/engine/SQLEngine.java,v
retrieving revision 1.26
diff -u -r1.26 SQLEngine.java
--- org/exolab/castor/jdo/engine/SQLEngine.java 29 Oct 2004 14:40:05 -0000 1.26
+++ org/exolab/castor/jdo/engine/SQLEngine.java 15 Mar 2005 13:35:54 -0000
@@ -52,6 +52,7 @@
import org.exolab.castor.jdo.*;
import org.exolab.castor.mapping.*;
import org.exolab.castor.mapping.loader.FieldHandlerImpl;
+import org.exolab.castor.persist.ProposedObject;
import org.exolab.castor.persist.spi.*;
import org.exolab.castor.util.Messages;
import org.exolab.castor.util.SqlBindParser;
@@ -116,7 +117,7 @@
private ColumnInfo[] _ids;
private SQLEngine _extends;
-
+
private QueryExpression _sqlFinder;
private PersistenceFactory _factory;
@@ -319,6 +320,10 @@
}
}
+ public Persistence.ColumnInfo[] getColumnInfoForIdentities() {
+ return _ids;
+ }
+
public Persistence.FieldInfo[] getInfo() {
return _fields;
}
@@ -1058,23 +1063,46 @@
}
- public Object load( Object conn, Object[] fields, Object identity, AccessMode accessMode )
- throws ObjectNotFoundException, PersistenceException {
+ /**
+ * Loads the object from persistence storage. This method will load
+ * the object fields from persistence storage based on the object's
+ * identity. This method may return a stamp which can be used at a
+ * later point to determine whether the copy of the object in
+ * persistence storage is newer than the cached copy (see {@link
+ * #store}). If lock is true the object must be
+ * locked in persistence storage to prevent concurrent updates.
+ *
+ * @param conn An open connection
+ * @param fields An Object[] to load field values into
+ * @param identity Identity of the object to load.
+ * @param accessMode The access mode (null equals shared)
+ * @return The object's stamp, or null
+ * @throws ObjectNotFoundException The object was not found in persistent storage
+ * @throws PersistenceException A persistence error occured
+ */
+ public Object load( Object conn, ProposedObject proposedObject, Object identity, AccessMode accessMode )
+ throws ObjectNotFoundException, PersistenceException
+ {
PreparedStatement stmt = null;
ResultSet rs = null;
Object stamp = null;
boolean notNull;
+
+ Object[] fields = proposedObject.getFields();
+ int originalNumberOfFields = fields.length;
+
+ _log.debug ("number of fields to load from persistence store: " + fields.length);
try {
- stmt = ( (Connection) conn ).prepareStatement( ( accessMode == AccessMode.DbLocked ) ? _sqlLoadLock : _sqlLoad );
+ String sqlString = ( accessMode == AccessMode.DbLocked ) ? _sqlLoadLock : _sqlLoad;
+ stmt = ( (Connection) conn ).prepareStatement(sqlString);
if (_log.isDebugEnabled()) {
- String generatedSQL = ( accessMode == AccessMode.DbLocked ) ? _sqlLoadLock : _sqlLoad;
- _log.debug( Messages.format( "jdo.loading", _clsDesc.getJavaClass().getName(), generatedSQL ) );
+ _log.debug( Messages.format("jdo.loading", _clsDesc.getJavaClass().getName(), sqlString));
}
- int count = 1;
+ int fieldIndex = 1;
// bind the identity of the preparedStatement
if ( identity instanceof Complex ) {
Complex id = (Complex) identity;
@@ -1082,33 +1110,72 @@
throw new PersistenceException( "Size of complex field mismatched! expected: "+_ids.length+" found: "+id.size() );
for ( int i=0; i<_ids.length; i++ )
- stmt.setObject( count++, idToSQL( i, id.get(i) ) );
+ stmt.setObject( fieldIndex++, idToSQL( i, id.get(i) ) );
} else {
if ( _ids.length != 1 )
throw new PersistenceException( "Complex field expected!" );
- stmt.setObject( count++, idToSQL( 0, identity ) );
+ stmt.setObject( fieldIndex++, idToSQL( 0, identity ) );
}
- // query the object
+ // execute the SQL query
rs = stmt.executeQuery();
if ( ! rs.next() )
throw new ObjectNotFoundException( Messages.format("persist.objectNotFound", _clsDesc.getJavaClass().getName(), identity) );
+ int numberOfFields = _fields.length;
+ int numberOfIdentityColumns = _ids.length;
+
+ int numberOfExtendLevels = numberOfExtendingClassDescriptors (getDescriptor());
+
+ Collection extendingClassDescriptors = this.getDescriptor().getExtendedBy();
+
+ if (extendingClassDescriptors.size() > 0) {
+ Object[] returnValues =
+ calculateNumberOfFields(extendingClassDescriptors,
+ _ids.length, _fields.length, numberOfExtendLevels, rs);
+ JDOClassDescriptor potentialLeafDescriptor = (JDOClassDescriptor) returnValues[0];
+
+
+ if (!potentialLeafDescriptor.getJavaClass().getName().equals (getDescriptor().getJavaClass().getName())) {
+ Object[] expandedFields = new Object[potentialLeafDescriptor.getFields().length];
+
+ fields = expandedFields;
+ proposedObject.setFields (expandedFields);
+ proposedObject.setActualClass (potentialLeafDescriptor.getJavaClass());
+ proposedObject.setExpanded(true);
+ }
+
+ return null;
+ }
+
// Load all the fields of the object including one-one relations
- count = 1;
+ int columnIndex = 1; // index to use during ResultSet.getXXX()
+ fieldIndex = 1; // index in fields[] for storing result of SQLTypes.getObject()
+ String tableName = null;
+ String tableNameOld = tableName;
Object[] temp = new Object[10]; // assume complex field max at 10
for ( int i = 0 ; i < _fields.length ; ++i ) {
+
+ tableName = _fields[i].tableName;
+ if (!tableName.equals (tableNameOld) && !_fields[i].joined) {
+ for (int j = 0; j < _ids.length; j++) {
+ columnIndex = columnIndex + 1;
+ }
+ }
+
if ( !_fields[i].load )
continue;
if ( !_fields[i].multi ) {
notNull = false;
if ( _fields[i].columns.length == 1 ) {
- fields[i] = toJava( i, 0, SQLTypes.getObject( rs, count++, _fields[i].columns[0].sqlType ) );
+ fields[i] = toJava( i, 0, SQLTypes.getObject( rs, columnIndex++, _fields[i].columns[0].sqlType ) );
+ fieldIndex += 1;
} else {
for ( int j=0; j<_fields[i].columns.length; j++ ) {
- temp[j] = toJava( i, j, SQLTypes.getObject( rs, count++, _fields[i].columns[j].sqlType ) );
+ temp[j] = toJava( i, j, SQLTypes.getObject( rs, columnIndex++, _fields[i].columns[j].sqlType ) );
+ fieldIndex += 1;
if ( temp[j] != null ) {
notNull = true;
}
@@ -1122,11 +1189,12 @@
ArrayList res = new ArrayList();
notNull = false;
for ( int j=0; j<_fields[i].columns.length; j++ ) {
- temp[j] = toJava( i, j, SQLTypes.getObject( rs, count, _fields[i].columns[j].sqlType ) );
+ temp[j] = toJava( i, j, SQLTypes.getObject( rs, columnIndex, _fields[i].columns[j].sqlType ) );
if ( temp[j] != null ) {
notNull = true;
}
- count++;
+ fieldIndex++;
+ columnIndex += 1;
}
if ( notNull ) {
if ( _fields[i].columns.length == 1 )
@@ -1136,23 +1204,39 @@
}
fields[i] = res;
}
+
+ tableNameOld = tableName;
}
while ( rs.next() ) {
- count = 1;
+ fieldIndex = 1;
+ columnIndex = 1;
+
+ tableName = null;
+ tableNameOld = tableName;
+
for ( int i = 0; i < _fields.length ; ++i ) {
- if ( !_fields[i].load )
+
+ tableName = _fields[i].tableName;
+ if (!tableName.equals (tableNameOld) && !_fields[i].joined) {
+ for (int j = 0; j < _ids.length; j++) {
+ columnIndex = columnIndex + 1;
+ }
+ }
+
+ if ( !_fields[i].load )
continue;
if ( _fields[i].multi ) {
ArrayList res = (ArrayList)fields[i];
notNull = false;
for ( int j=0; j<_fields[i].columns.length; j++ ) {
- temp[j] = toJava( i, j, SQLTypes.getObject( rs, count, _fields[i].columns[j].sqlType ) );
+ temp[j] = toJava( i, j, SQLTypes.getObject( rs, columnIndex, _fields[i].columns[j].sqlType ) );
if ( temp[j] != null ) {
notNull = true;
}
- count++;
+ fieldIndex++;
+ columnIndex += 1;
}
if ( notNull ) {
if ( _fields[i].columns.length == 1 ) {
@@ -1165,9 +1249,12 @@
}
}
} else {
- count += _fields[i].columns.length;
+ fieldIndex += _fields[i].columns.length;
+ columnIndex += _fields[i].columns.length;
}
}
+
+ proposedObject.setFields (fields);
}
} catch ( SQLException except ) {
_log.fatal( Messages.format( "jdo.loadFatal", _type, (( accessMode == AccessMode.DbLocked ) ? _sqlLoadLock : _sqlLoad ) ), except );
@@ -1187,7 +1274,105 @@
}
return stamp;
}
-
+
+ private int numberOfExtendingClassDescriptors (JDOClassDescriptor classDescriptor) {
+ int numberOfExtendLevels = 1;
+ JDOClassDescriptor currentClassDescriptor = getDescriptor();
+ while (currentClassDescriptor.getExtends() != null) {
+ currentClassDescriptor = (JDOClassDescriptor) currentClassDescriptor.getExtends();
+ numberOfExtendLevels += 1;
+ }
+ return numberOfExtendLevels;
+ }
+
+ private Object[] calculateNumberOfFields (Collection extendingClassDescriptors,
+ int numberOfIdentityColumns,
+ int numberOfFields,
+ int numberOfExtendLevels,
+ ResultSet rs)
+ throws SQLException
+ {
+ JDOClassDescriptor potentialLeafDescriptor = null;
+ int suggestedNumberOfFields = numberOfFields;
+ Collection potentialActualClassDescriptor = new LinkedList();
+ int numberOfIdentitiesToAnalyze = 0;
+ addExtendingClassDescriptors(potentialActualClassDescriptor, extendingClassDescriptors);
+
+ JDOClassDescriptor potentialClassDescriptor = null;
+ JDOClassDescriptor potentialClassDescriptorPrevious = null;
+ int initialColumnIndex = numberOfFields + numberOfIdentityColumns * numberOfExtendLevels + 1;
+ int columnIndex = initialColumnIndex;
+ int numberOfExtendingClassDescriptors = 0;
+ for (Iterator iter = potentialActualClassDescriptor.iterator(); iter.hasNext(); ) {
+ potentialClassDescriptor = (JDOClassDescriptor) iter.next();
+ numberOfExtendingClassDescriptors += 1;
+ _log.debug ("Potential extending class descriptor: " + potentialClassDescriptor.getJavaClass().getName());
+ FieldDescriptor[] identityDescriptors = potentialClassDescriptor.getIdentities();
+ boolean isNull = true;
+
+ for (int i = 0; i < identityDescriptors.length; i++) {
+ Object temp;
+ Object[] temps;
+ JDOFieldDescriptor jdoFieldDescriptor = (JDOFieldDescriptor) identityDescriptors[i];
+ if (jdoFieldDescriptor.getSQLName().length == 1 ) {
+ temp = SQLTypes.getObject( rs, columnIndex++, java.sql.Types.JAVA_OBJECT);
+ isNull = (temp == null);
+ } else {
+ temps = new Object[jdoFieldDescriptor.getSQLName().length];
+ for ( int j=0; j 0) {
+ potentialLeafDescriptor = potentialClassDescriptor;
+ suggestedNumberOfFields += potentialClassDescriptor.getFields().length;
+ } else if (!iter.hasNext() && isNull && numberOfIdentitiesToAnalyze > 0){
+ potentialLeafDescriptor = potentialClassDescriptorPrevious;
+ // suggestedNumberOfFields += potentialClassDescriptor.getFields().length;
+ } else {
+ FieldDescriptor[] potentialFields =
+ (FieldDescriptor[]) potentialClassDescriptor.getFields();
+ for (int i = 0; i < potentialFields.length; i++) {
+ JDOFieldDescriptor jdoFieldDescriptor = (JDOFieldDescriptor) potentialFields[i];
+ String[] columnNames = jdoFieldDescriptor.getSQLName();
+ for (int j = 0; j < columnNames.length; j++) {
+ columnIndex = columnIndex + 1;
+ }
+ }
+
+ // the JDOClassDescriptor we just looked at is definitely part of the extends hierarchy,
+ // and as such we need to increase the number of potential fields
+ if (!isNull) {
+ suggestedNumberOfFields += potentialClassDescriptor.getFields().length;
+ }
+ }
+ }
+
+ _log.debug ("In total " + numberOfIdentitiesToAnalyze + " (extending) identities analyzed.");
+
+ if (potentialLeafDescriptor != null) {
+ _log.debug ("Most likely of type " + potentialLeafDescriptor.getJavaClass().getName());
+ _log.debug ("After analysis, " + suggestedNumberOfFields + " fields need to be loaded.");
+ }
+
+ return new Object[] {potentialLeafDescriptor, new Integer (suggestedNumberOfFields) };
+
+ }
private void buildSqlCreate () throws QueryException {
StringBuffer sql;
@@ -1345,7 +1530,8 @@
}
- private void buildFinder( JDOClassDescriptor clsDesc ) throws QueryException {
+ // private void buildFinder(JDOClassDescriptor clsDesc, ColumnInfo[] ids, FieldInfo[] fields, String mapTo) throws QueryException {
+ private void buildFinder(JDOClassDescriptor clsDesc) throws QueryException {
QueryExpression expr;
QueryExpression find;
@@ -1372,15 +1558,38 @@
find.addInnerJoin(curDesc.getTableName(), curDesc.getIdentityColumnNames(),
baseDesc.getTableName(), baseDesc.getIdentityColumnNames());
curDesc = baseDesc;
+
+ // add identity column names to SELECT statement
+// String[] identityColumnNames = baseDesc.getIdentityColumnNames();
+// for (int j = 0; j < identityColumnNames.length; j++) {
+// expr.addColumn (baseDesc.getTableName(), identityColumnNames[j]);
+// }
}
+
for ( int i=0; i<_ids.length; i++ ) {
- find.addColumn( _mapTo, idnames[i] );
+ // find.addColumn(_mapTo, idnames[i]);
+ // expr.addColumn(_mapTo, idnames[i]);
}
// join all the related/depended table
Vector joinTables = new Vector();
+ String aliasOld = null;
+ String alias = null;
+
for ( int i=0; i<_fields.length; i++ ) {
- String alias = _fields[i].tableName;
+ if (i > 0) {
+ aliasOld = alias;
+ }
+ alias = _fields[i].tableName;
+
+ // add id columns to select statement
+ if (!alias.equals (aliasOld) && !_fields[i].joined) {
+ for (int j = 0; j < _ids.length; j++) {
+ expr.addColumn (alias, _ids[j].getName());
+ find.addColumn (alias, _ids[j].getName());
+ }
+ }
+
if ( _fields[i].load ) {
if ( _fields[i].joined /*&& !joinTables.contains( _fields[i].tableName )*/ ) {
int offset = 0;
@@ -1404,10 +1613,71 @@
expr.addColumn( alias, _fields[i].columns[j].name );
find.addColumn( alias, _fields[i].columns[j].name );
}
+
expr.addTable(_fields[i].tableName, alias);
find.addTable(_fields[i].tableName, alias);
}
+
+
+ }
+
+ // 'join' all the extending tables
+ curDesc = clsDesc;
+ List classDescriptorsToAdd = new LinkedList();
+ JDOClassDescriptor classDescriptor = null;
+ addExtendingClassDescriptors(classDescriptorsToAdd, curDesc.getExtendedBy());
+
+ if (classDescriptorsToAdd.size() > 0) {
+ for (Iterator iter = classDescriptorsToAdd.iterator(); iter.hasNext(); ) {
+ classDescriptor = (JDOClassDescriptor) iter.next();
+ _log.debug ("Adding outer left join for " + classDescriptor.getJavaClass().getName() +
+ " on table " + classDescriptor.getTableName());
+ expr.addOuterJoin( _mapTo,
+ curDesc.getIdentityColumnNames(),
+ classDescriptor.getTableName(),
+ classDescriptor.getIdentityColumnNames());
+ find.addOuterJoin( _mapTo,
+ curDesc.getIdentityColumnNames(),
+ classDescriptor.getTableName(),
+ classDescriptor.getIdentityColumnNames());
+
+ Persistence persistenceEngine;
+ try {
+ persistenceEngine = _factory.getPersistence (classDescriptor);
+ } catch (MappingException e) {
+ throw new QueryException ("Problem obtaining persistence engine for ClassDescriptor " + classDescriptor.getJavaClass().getName(), e);
+ }
+
+ SQLEngine.ColumnInfo[] idInfos =
+ (SQLEngine.ColumnInfo[]) persistenceEngine.getColumnInfoForIdentities();
+ for (int i = 0; i < idInfos.length; i++) {
+ _log.debug ("Adding column " + idInfos[i].name + " for table " + classDescriptor.getTableName());
+ expr.addColumn (classDescriptor.getTableName(), idInfos[i].name);
+ find.addColumn (classDescriptor.getTableName(), idInfos[i].name);
+ }
+
+ SQLEngine.FieldInfo[] fieldInfos = (SQLEngine.FieldInfo[]) persistenceEngine.getInfo();
+ for (int i = 0; i < fieldInfos.length; i++) {
+ boolean hasFieldToAdd = false;
+ SQLEngine.ColumnInfo[] columnInfos = fieldInfos[i].columns;
+ if (classDescriptor.getTableName().equals(fieldInfos[i].tableName)) {
+ for ( int j = 0; j < columnInfos.length; j++ ) {
+ _log.debug ("Adding column " + fieldInfos[i].columns[j].name + " for table " + classDescriptor.getTableName());
+ expr.addColumn (classDescriptor.getTableName(), fieldInfos[i].columns[j].name);
+ find.addColumn (classDescriptor.getTableName(), fieldInfos[i].columns[j].name);
+ }
+ hasFieldToAdd = true;
+ }
+
+ if (hasFieldToAdd) {
+ expr.addTable(classDescriptor.getTableName());
+ find.addTable(classDescriptor.getTableName());
+ }
+ }
+ }
}
+
+
_sqlLoad = expr.getStatement( false );
_sqlLoadLock = expr.getStatement( true );
@@ -1415,9 +1685,21 @@
if(_log.isDebugEnabled()){
_log.debug( Messages.format( "jdo.loading", _type, _sqlLoad ) );
+ _log.debug( Messages.format( "jdo.loading.with.lock", _type, _sqlLoadLock ) );
+ _log.debug( Messages.format( "jdo.finding", _type, _sqlFinder ) );
}
}
+
+ private void addExtendingClassDescriptors (Collection classDescriptorsToAdd, Collection extendingClassDescriptors) {
+ JDOClassDescriptor classDescriptor = null;
+ for (Iterator iter = extendingClassDescriptors.iterator(); iter.hasNext(); ) {
+ classDescriptor = (JDOClassDescriptor) iter.next();
+ classDescriptorsToAdd.add (classDescriptor);
+ addExtendingClassDescriptors(classDescriptorsToAdd, classDescriptor.getExtendedBy());
+ }
+
+ }
public String toString() {
@@ -1443,10 +1725,17 @@
final String[] joinFields;
ColumnInfo[] columns;
+
+ final FieldDescriptor fieldDescriptor;
+
+ final ClassDescriptor classDescriptor;
FieldInfo( JDOClassDescriptor clsDesc, FieldDescriptor fieldDesc, String classTable, boolean ext )
throws MappingException{
+ fieldDescriptor = fieldDesc;
+ classDescriptor = clsDesc;
+
// for readability
final int FIELD_TYPE = 0;
@@ -1591,16 +1880,31 @@
}
}
- static final class ColumnInfo {
+ static final class ColumnInfo implements Persistence.ColumnInfo{
+ /**
+ * Name of the column
+ */
final String name;
+ /**
+ * SQL type of teh coplumn
+ */
final int sqlType;
+ /**
+ * TypeConvertor to use when converting to the SQLType of this column.
+ */
final TypeConvertor convertTo;
+ /**
+ * TypeConvertor to use when converting from the SQLType of this column.
+ */
final TypeConvertor convertFrom;
+ /**
+ * Type conversion parameters
+ */
final String convertParam;
ColumnInfo( String name, int type, TypeConvertor convertTo,
@@ -1611,6 +1915,41 @@
this.convertFrom = convertFrom;
this.convertParam = convertParam;
}
+
+ /* (non-Javadoc)
+ * @see org.exolab.castor.persist.spi.Persistence.ColumnInfo#getName()
+ */
+ public String getName() {
+ return name;
+ }
+
+ /* (non-Javadoc)
+ * @see org.exolab.castor.persist.spi.Persistence.ColumnInfo#getSqlType()
+ */
+ public int getSqlType() {
+ return sqlType;
+ }
+
+ /* (non-Javadoc)
+ * @see org.exolab.castor.persist.spi.Persistence.ColumnInfo#getConvertTo()
+ */
+ public TypeConvertor getConvertTo() {
+ return convertTo;
+ }
+
+ /* (non-Javadoc)
+ * @see org.exolab.castor.persist.spi.Persistence.ColumnInfo#getConvertFrom()
+ */
+ public TypeConvertor getConvertFrom() {
+ return convertFrom;
+ }
+
+ /* (non-Javadoc)
+ * @see org.exolab.castor.persist.spi.Persistence.ColumnInfo#getConvertParam()
+ */
+ public String getConvertParam() {
+ return convertParam;
+ }
}
static final class SQLQuery implements PersistenceQuery {
@@ -1619,7 +1958,8 @@
private ResultSet _rs;
- private final SQLEngine _engine;
+ private /*final*/ SQLEngine _engine;
+ private SQLEngine _requestedEngine;
private final Class[] _types;
@@ -1638,6 +1978,7 @@
SQLQuery( SQLEngine engine, String sql, Class[] types )
{
_engine = engine;
+ _requestedEngine = engine;
_types = types;
_values = new Object[ _types.length ];
_sql = sql;
@@ -1677,8 +2018,11 @@
/**
* use the jdbc 2.0 method to move to an absolute position in the
* resultset.
+ * @param row Row number to move to.
+ * @return True if the pointer has been moved to the indicated row number.
+ * @exception PersistenceException If an underlying SQLException is is reported.
*/
- public boolean absolute(int row)
+ public boolean absolute(int row)
throws PersistenceException
{
boolean retval = false;
@@ -1691,7 +2035,7 @@
}
catch (SQLException e)
{
- throw new PersistenceException(e.getMessage());
+ throw new PersistenceException(e.getMessage(), e);
}
return retval;
}
@@ -1896,19 +2240,43 @@
}
- private Object loadSingleField( int i, int count ) throws SQLException, PersistenceException
+ private Object loadSingleField( int i, CounterRef counterReference) throws SQLException, PersistenceException
{
+ String currentTableName = counterReference.getTableName();
+ int count = counterReference.getCounter();
Object[] temp = new Object[_engine._fields[i].columns.length];
boolean notNull = false;
Object field;
+
+ String fieldTableName = _engine._fields[i].tableName;
+
+ ResultSetMetaData metaData = _rs.getMetaData();
+ String columnTableName = metaData.getTableName(count);
+ _log.debug("Current column: " + columnTableName + "." + metaData.getColumnName(count) + "/" + metaData.getColumnLabel(count));
+
+ while (!columnTableName.equals(fieldTableName)) {
+ _log.debug("Skipping " + metaData.getTableName(count) + "." + metaData.getColumnName(count) + " due to wrong table name.");
+ count++;
+ columnTableName = metaData.getTableName(count);
+ }
+ String firstColumnOfField = _engine._fields[i].columns[0].name;
+ while (!metaData.getColumnName(count).equals(firstColumnOfField)) {
+ _log.debug("Skipping " + metaData.getTableName(count) + "." + metaData.getColumnName(count));
+ count++;
+ }
+
if ( _engine._fields[i].columns.length == 1 ) {
- field = _engine.toJava( i, 0, SQLTypes.getObject( _rs, count++,
+ field = _engine.toJava( i, 0, SQLTypes.getObject( _rs, count,
_engine._fields[i].columns[0].sqlType ) );
+ _log.debug ("Got value for " + metaData.getTableName(count) + "." + metaData.getColumnName(count) + ": " + field);
+ count++;
} else {
for ( int j=0; j<_engine._fields[i].columns.length; j++ ) {
- temp[j] = _engine.toJava( i, j, SQLTypes.getObject( _rs, count++,
+ temp[j] = _engine.toJava( i, j, SQLTypes.getObject( _rs, count,
_engine._fields[i].columns[j].sqlType ) );
+ _log.debug ("Got value for " + metaData.getTableName(count) + "." + metaData.getColumnName(count) + ": " + temp[j]);
+ count++;
if ( temp[j] != null ) {
notNull = true;
}
@@ -1918,12 +2286,16 @@
else
field = null;
}
+ _log.debug("Loaded field " + _engine._fields[i].getFieldName() + ": " + field);
+ counterReference.setCounter(count);
+ counterReference.setTableName(currentTableName);
return field;
}
- private Object loadMultiField( int i, int count, Object field ) throws SQLException, PersistenceException
+ private Object loadMultiField( int i, CounterRef counterReference, Object field ) throws SQLException, PersistenceException
{
+ int count = counterReference.getCounter();
Object[] temp = new Object[_engine._fields[i].columns.length];
boolean notNull = false;
ArrayList res;
@@ -1951,27 +2323,43 @@
res.add( com );
}
}
+ counterReference.setCounter(count);
+
return res;
}
- private int loadRow( Object[] fields, boolean isFirst ) throws SQLException, PersistenceException
+ private int loadRow( Object[] fields, int numberOfFields, boolean isFirst ) throws SQLException, PersistenceException
{
int count = _engine._ids.length + 1;
+ String tableName = null;
+
+ // TODO: wrong, as it could be that the first field is not part of the root class.
+ tableName = _engine._fields[0].tableName;
+
// Load all the fields.
- for ( int i = 0 ; i < _engine._fields.length ; ++i ) {
+ CounterRef counterReference = new CounterRef ();
+ counterReference.setCounter(count);
+ counterReference.setTableName(tableName);
+
+ for ( int i = 0 ; i < numberOfFields ; ++i ) {
+
if ( !_engine._fields[i].load )
continue;
if ( _engine._fields[i].multi ) {
- fields[i] = loadMultiField( i, count, fields[i] );
+ counterReference.setCounter(count);
+ fields[i] = loadMultiField( i, counterReference, fields[i] );
+ count = counterReference.getCounter();
} else if( isFirst ) {
// Non-multi fields have to be done one only once, so this is skipped
// if we have already read the first row.
- fields[i] = loadSingleField( i, count );
+ counterReference.setCounter (count);
+ fields[i] = loadSingleField( i, counterReference);
+ count = counterReference.getCounter();
}
- count += _engine._fields[i].columns.length;
+ // count += _engine._fields[i].columns.length;
}
return count;
}
@@ -2004,12 +2392,19 @@
}
- // Fill the given fields[] with the "cached" stuff from our _fields[] .
- public Object fetch( Object[] fields, Object identity ) throws ObjectNotFoundException, PersistenceException
+ /**
+ * @see org.exolab.castor.persist.spi.PersistenceQuery#fetch(org.exolab.castor.persist.ProposedObject, java.lang.Object)
+ */
+ public Object fetch( ProposedObject proposedObject, Object identity )
+ throws ObjectNotFoundException, PersistenceException
{
+ Object[] fields = proposedObject.getFields();
+
+ // Fill the given fields[] with the "cached" stuff from our _fields[] .
for( int i = 0; i < _fields.length; i++ ) {
fields[i] = _fields[i];
}
+
return null;
}
@@ -2019,7 +2414,48 @@
// maybe we can optimize a little bit here when we have time.
// Instead of creating new Object[] and ArrayList for each
// "multi field" each fetchRaw is called, we might reuse them.
- _fields = new Object[_engine._fields.length];
+
+ SQLEngine oldEngine = null;
+ int originalFieldNumber = _requestedEngine._fields.length;
+ if (_requestedEngine.getDescriptor().isExtended()) {
+ Collection extendingClassDescriptors = _requestedEngine.getDescriptor().getExtendedBy();
+ int numberOfExtendLevels = _requestedEngine.numberOfExtendingClassDescriptors(_requestedEngine.getDescriptor());
+ JDOClassDescriptor leafDescriptor = null;
+ Object[] returnValues = null;
+ try {
+ returnValues =_requestedEngine.calculateNumberOfFields(extendingClassDescriptors, _requestedEngine._ids.length, _requestedEngine._fields.length, numberOfExtendLevels, this._rs);
+ }
+ catch (SQLException e) {
+ _log.error ("Problem calculating number of concrete fields.", e);
+ throw new PersistenceException ("Problem calculating number of concrete fields.", e);
+ }
+
+ leafDescriptor = (JDOClassDescriptor) returnValues[0];
+
+ if (leafDescriptor != null) {
+ _log.debug("potential leaf descriptor = " + leafDescriptor.getJavaClass().getName());
+
+
+ if (!leafDescriptor.getJavaClass().getName().equals(_requestedEngine.getDescriptor().getJavaClass().getName())) {
+ _log.debug ("Increasing number of fields to load from " + originalFieldNumber + " to "
+ + ((Integer) returnValues[1]).intValue());
+ originalFieldNumber = ((Integer) returnValues[1]).intValue();
+
+ Persistence newEngine =null;
+ try {
+ newEngine = _requestedEngine._factory.getPersistence(leafDescriptor);
+ } catch (MappingException e) {
+ _log.error ("Problem obtaining persistence engine for " + leafDescriptor.getJavaClass().getName(), e);
+ throw new PersistenceException ("Problem obtaining persistence engine for " + leafDescriptor.getJavaClass().getName(), e);
+ }
+ _log.debug ("About to start using persistence engine for " + ((SQLEngine) newEngine).getDescriptor());
+ _engine = (SQLEngine) newEngine;
+ }
+ }
+ }
+
+
+ _fields = new Object[originalFieldNumber];
// It would prove a little difficult to fetch if we don't have any rows with data left :-)
if ( _resultSetDone )
@@ -2042,7 +2478,7 @@
// As we assume that we have called fetch() immediatly after nextIdentity(),
// we can be sure that it belongs to the object we want. This is probably not the
// safest programming style, but has to suffice currently :-)
- loadRow( _fields, true );
+ loadRow( _fields, originalFieldNumber, true );
// We move forward in the ResultSet, until we see another identity or run out of rows.
while ( _rs.next() ) {
@@ -2054,7 +2490,7 @@
if( identitiesEqual( wantedIdentity, currentIdentity ) ) {
// Load next row of object data from _rs into <_fields> array.
- loadRow( _fields, false );
+ loadRow( _fields, originalFieldNumber, false );
} else {
// We are done with all the rows for our obj. and still have rows left.
@@ -2069,7 +2505,7 @@
// We are done with all the rows for our obj. and don't have any rows left.
_resultSetDone = true;
_lastIdentity = null;
-
+
} catch ( SQLException except ) {
throw new PersistenceException( Messages.format("persist.nested", except), except );
}
Index: org/exolab/castor/jdo/engine/SQLTypes.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/jdo/engine/SQLTypes.java,v
retrieving revision 1.10
diff -u -r1.10 SQLTypes.java
--- org/exolab/castor/jdo/engine/SQLTypes.java 29 Oct 2004 14:06:17 -0000 1.10
+++ org/exolab/castor/jdo/engine/SQLTypes.java 15 Mar 2005 13:35:56 -0000
@@ -361,7 +361,6 @@
return java.toString();
}
-
public static Object getObject( ResultSet rs, int index, int sqlType )
throws SQLException
{
Index: org/exolab/castor/mapping/loader/ClassDescriptorImpl.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/mapping/loader/ClassDescriptorImpl.java,v
retrieving revision 1.2
diff -u -r1.2 ClassDescriptorImpl.java
--- org/exolab/castor/mapping/loader/ClassDescriptorImpl.java 5 Mar 2005 13:41:52 -0000 1.2
+++ org/exolab/castor/mapping/loader/ClassDescriptorImpl.java 15 Mar 2005 13:35:56 -0000
@@ -47,6 +47,12 @@
package org.exolab.castor.mapping.loader;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.exolab.castor.mapping.ValidityException;
import org.exolab.castor.mapping.ClassDescriptor;
import org.exolab.castor.mapping.FieldDescriptor;
@@ -66,7 +72,7 @@
public class ClassDescriptorImpl
implements ClassDescriptor
{
-
+ private static final Log _log = LogFactory.getLog (ClassDescriptorImpl.class);
private ClassMapping _map;
/**
@@ -85,6 +91,12 @@
* or null if this is a top-level class.
*/
private final ClassDescriptor _extends;
+
+ /**
+ * A collection of class descriptors that extend this class, or
+ * an empty collection if this is a leaf class.
+ */
+ private final Collection _extendedBy = new LinkedList();
private final ClassDescriptor _depends;
@@ -166,6 +178,13 @@
throw new MappingException( "mapping.classDoesNotExtend",
_javaClass.getName(), extend.getJavaClass().getName() );
_extends = extend;
+
+ _log.debug (_extends.getClass().getName());
+ if ( _extends.getClass().getName().equals("org.exolab.castor.jdo.engine.JDOClassDescriptor") &&
+ this.getClass().getName().equals ("org.exolab.castor.jdo.engine.JDOClassDescriptor")) {
+ ((ClassDescriptorImpl) _extends).addExtendedBy (this);
+ }
+
if ( _extends instanceof ClassDescriptorImpl )
_identities = ( identities == null ? ((ClassDescriptorImpl)_extends).getIdentities() : identities );
else
@@ -232,6 +251,31 @@
public ClassDescriptor getExtends()
{
return _extends;
+ }
+
+ public boolean isExtending()
+ {
+ return (_extends != null);
+ }
+
+ /**
+ * Returns a collection of class descriptors that extend this class descriptor.
+ * @return A collection of class descriptors.
+ */
+ public Collection getExtendedBy()
+ {
+ return _extendedBy;
+ }
+
+ public boolean isExtended()
+ {
+ return (_extendedBy.size() > 0);
+ }
+
+ public void addExtendedBy (ClassDescriptor classDesc)
+ {
+ _log.debug ("Adding ClassDescriptor of type " + classDesc.getClass().getName());
+ _extendedBy.add (classDesc);
}
public ClassDescriptor getDepends() {
Index: org/exolab/castor/persist/ClassMolder.java
===================================================================
RCS file: /scm/castor/castor/src/main/org/exolab/castor/persist/ClassMolder.java,v
retrieving revision 1.19
diff -u -r1.19 ClassMolder.java
--- org/exolab/castor/persist/ClassMolder.java 8 Mar 2005 20:46:01 -0000 1.19
+++ org/exolab/castor/persist/ClassMolder.java 15 Mar 2005 13:35:59 -0000
@@ -65,6 +65,7 @@
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
@@ -463,17 +464,31 @@
extendFields = getFullFields( extend );
thisFields = clsMap.getFieldMapping();
- fieldList = new ArrayList(extendFields.length + thisFields.length);
+ fieldList = new ArrayList(extendFields.length + thisFields.length - identities.length);
for (int i = 0; i < extendFields.length; i++) {
fieldList.add(extendFields[i]);
}
- for ( int i=0; i");
+ return buffer.toString();
+ }
+}