Index: cpa/src/main/java/org/castor/cpa/persistence/sql/query/visitor/UncoupleVisitor.java
===================================================================
--- cpa/src/main/java/org/castor/cpa/persistence/sql/query/visitor/UncoupleVisitor.java (revision 0)
+++ cpa/src/main/java/org/castor/cpa/persistence/sql/query/visitor/UncoupleVisitor.java (revision 0)
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2010 Dennis Butterstein, Ralf Joachim
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Id: SQLStatementDelete.java 8469 2009-12-28 16:47:54Z rjoachim $
+ */
+
+package org.castor.cpa.persistence.sql.query.visitor;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.castor.cpa.persistence.sql.query.Assignment;
+import org.castor.cpa.persistence.sql.query.Delete;
+import org.castor.cpa.persistence.sql.query.Insert;
+import org.castor.cpa.persistence.sql.query.Select;
+import org.castor.cpa.persistence.sql.query.Table;
+import org.castor.cpa.persistence.sql.query.Update;
+import org.castor.cpa.persistence.sql.query.Visitor;
+import org.castor.cpa.persistence.sql.query.condition.AndCondition;
+import org.castor.cpa.persistence.sql.query.condition.Compare;
+import org.castor.cpa.persistence.sql.query.condition.IsNullPredicate;
+import org.castor.cpa.persistence.sql.query.condition.OrCondition;
+import org.castor.cpa.persistence.sql.query.expression.Column;
+import org.castor.cpa.persistence.sql.query.expression.Expression;
+import org.castor.cpa.persistence.sql.query.expression.NextVal;
+import org.castor.cpa.persistence.sql.query.expression.Parameter;
+
+/**
+ * Visitor constructing result column map for queries to uncouple the order of
+ * select-columns from the order of resultset-columns.
+ *
+ * @author Dennis Butterstein
+ * @version $Revision: 8469 $ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr 2006) $
+ */
+public final class UncoupleVisitor implements Visitor {
+ //-----------------------------------------------------------------------------------
+
+ /** Map of parameter names to indices filled during build of SQL query string. */
+ private final Map _resultColumnMap = new HashMap();
+
+ //-----------------------------------------------------------------------------------
+
+ /**
+ * {@inheritDoc}
+ */
+ public void visit(final Assignment assignment) { }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void visit(final Delete delete) { }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void visit(final Insert insert) { }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void visit(final Select select) {
+ for (Iterator iter = select.getSelect().iterator(); iter.hasNext(); ) {
+ iter.next().accept(this);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void visit(final Table table) { }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void visit(final Update update) { }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void visit(final AndCondition andCondition) { }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void visit(final Compare compare) { }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void visit(final IsNullPredicate isNullPredicate) { }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void visit(final OrCondition orCondition) { }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void visit(final Column column) {
+ _resultColumnMap.put(column.toString(), _resultColumnMap.size() + 1);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void visit(final NextVal nextVal) { }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void visit(final Parameter parameter) { }
+
+ //-----------------------------------------------------------------------------------
+
+ /**
+ * Method returning constructed result columns map.
+ *
+ * @return Constructed result columns map.
+ */
+ public Map getResultColumnMap() {
+ return _resultColumnMap;
+ }
+
+ //-----------------------------------------------------------------------------------
+}
Index: cpa/src/main/java/org/exolab/castor/jdo/engine/SQLEngine.java
===================================================================
--- cpa/src/main/java/org/exolab/castor/jdo/engine/SQLEngine.java (revision 8639)
+++ cpa/src/main/java/org/exolab/castor/jdo/engine/SQLEngine.java (working copy)
@@ -184,6 +184,16 @@
}
}
+ for (int i = 0; i < fieldsInfo.size(); i++) {
+ SQLFieldInfo info = fieldsInfo.get(i);
+ if (info.isJoined()) {
+ String alias = info.getTableName() + "_f" + i;
+ info.setTableAlias(alias);
+ } else {
+ info.setTableAlias(info.getTableName());
+ }
+ }
+
_ids = new SQLColumnInfo[idsInfo.size()];
idsInfo.copyInto(_ids);
Index: cpa/src/main/java/org/exolab/castor/jdo/engine/SQLFieldInfo.java
===================================================================
--- cpa/src/main/java/org/exolab/castor/jdo/engine/SQLFieldInfo.java (revision 8563)
+++ cpa/src/main/java/org/exolab/castor/jdo/engine/SQLFieldInfo.java (working copy)
@@ -37,6 +37,9 @@
public class SQLFieldInfo {
private final String _tableName;
+ /** Variable holding the alias for this table. */
+ private String _tableAlias;
+
private final boolean _store;
private final boolean _multi;
@@ -169,6 +172,20 @@
public String getTableName() { return _tableName; }
+ /**
+ * Method returning table-alias currently set.
+ *
+ * @return Table-alias currently set.
+ */
+ public String getTableAlias() { return _tableAlias; }
+
+ /**
+ * Method setting current table-alias.
+ *
+ * @param tableAlias Table-alias to be set.
+ */
+ public void setTableAlias(final String tableAlias) { _tableAlias = tableAlias; }
+
public boolean isStore() { return _store; }
public boolean isMulti() { return _multi; }
Index: cpa/src/main/java/org/exolab/castor/jdo/engine/SQLStatementLoad.java
===================================================================
--- cpa/src/main/java/org/exolab/castor/jdo/engine/SQLStatementLoad.java (revision 8563)
+++ cpa/src/main/java/org/exolab/castor/jdo/engine/SQLStatementLoad.java (working copy)
@@ -24,17 +24,19 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.Vector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.castor.core.util.Messages;
+import org.castor.cpa.persistence.sql.query.Select;
+import org.castor.cpa.persistence.sql.query.Table;
+import org.castor.cpa.persistence.sql.query.expression.Column;
+import org.castor.cpa.persistence.sql.query.visitor.UncoupleVisitor;
import org.castor.jdo.engine.SQLTypeInfos;
import org.castor.jdo.util.JDOUtils;
import org.castor.persist.ProposedEntity;
@@ -63,6 +65,9 @@
private final String _mapTo;
+ /** Map storing mapping between select-column and resultset-column. */
+ private Map _resultColumnMap;
+
/** Number of ClassDescriptor that extend this one. */
private final int _numberOfExtendLevels;
@@ -89,12 +94,15 @@
}
private void buildStatement() throws MappingException {
+ // Provisional select to construct map holding mapping between select- and
+ // resultset-columns.
+ Select select = new Select("provisional Select");
try {
QueryExpression expr = _factory.getQueryExpression();
Map identitiesUsedForTable = new HashMap();
Vector joinTables = new Vector();
-
+
// join all the extended table
ClassDescriptor curDesc = _engine.getDescriptor();
ClassDescriptor baseDesc;
@@ -114,23 +122,18 @@
SQLColumnInfo[] ids = _engine.getColumnInfoForIdentities();
SQLFieldInfo[] fields = _engine.getInfo();
- // join all the related/depended table
- String aliasOld = null;
- String alias = null;
for (int i = 0; i < fields.length; i++) {
SQLFieldInfo field = fields[i];
-
- if (i > 0) { aliasOld = alias; }
- alias = field.getTableName();
+ String tableName = field.getTableName();
// add id fields for root table if first field points to a separate table
if ((i == 0) && field.isJoined()) {
String[] identities = SQLHelper.getIdentitySQLNames(_engine.getDescriptor());
for (int j = 0; j < identities.length; j++) {
- expr.addColumn(
- new ClassDescriptorJDONature(curDesc).getTableName(),
- identities[j]);
+ String name = new ClassDescriptorJDONature(curDesc).getTableName();
+ select.addSelect(new Column(new Table(name), identities[j]));
+ expr.addColumn(name, identities[j]);
}
identitiesUsedForTable.put(
new ClassDescriptorJDONature(curDesc).getTableName(),
@@ -138,7 +141,7 @@
}
// add id columns to select statement
- if (!alias.equals(aliasOld) && !field.isJoined()) {
+ if (!field.isJoined()) {
ClassDescriptor classDescriptor =
field.getFieldDescriptor().getContainingClassDescriptor();
boolean isTableNameAlreadyAdded = identitiesUsedForTable.containsKey(
@@ -146,7 +149,8 @@
if (!isTableNameAlreadyAdded) {
String[] identities = SQLHelper.getIdentitySQLNames(classDescriptor);
for (int j = 0; j < identities.length; j++) {
- expr.addColumn(alias, identities[j]);
+ select.addSelect(new Column(new Table(tableName), identities[j]));
+ expr.addColumn(tableName, identities[j]);
}
identitiesUsedForTable.put(
new ClassDescriptorJDONature(classDescriptor).getTableName(),
@@ -166,21 +170,22 @@
if (joinTables.contains(field.getTableName())
|| nature.getTableName().equals(field.getTableName())) {
- // should not mix with aliases in ParseTreeWalker
- alias = alias.replace('.', '_') + "_f" + i;
- expr.addOuterJoin(_mapTo, leftCol, field.getTableName(), rightCol, alias);
+ tableName = field.getTableAlias();
+ expr.addOuterJoin(_mapTo, leftCol, field.getTableName(), rightCol,
+ tableName);
} else {
- expr.addOuterJoin(_mapTo, leftCol,
- field.getTableName(), rightCol, field.getTableName());
- joinTables.add(field.getTableName());
+ expr.addOuterJoin(_mapTo, leftCol, tableName, rightCol, tableName);
+ joinTables.add(tableName);
}
}
for (int j = 0; j < field.getColumnInfo().length; j++) {
- expr.addColumn(alias, field.getColumnInfo()[j].getName());
+ select.addSelect(new Column(new Table(tableName),
+ field.getColumnInfo()[j].getName()));
+ expr.addColumn(tableName, field.getColumnInfo()[j].getName());
}
- expr.addTable(field.getTableName(), alias);
+ expr.addTable(field.getTableName(), tableName);
}
// 'join' all the extending tables
@@ -220,6 +225,8 @@
SQLEngine engine = (SQLEngine) persistenceEngine;
SQLColumnInfo[] idInfos = engine.getColumnInfoForIdentities();
for (int i = 0; i < idInfos.length; i++) {
+ select.addSelect(new Column(new Table(clsDescNature.getTableName()),
+ idInfos[i].getName()));
expr.addColumn(clsDescNature.getTableName(), idInfos[i].getName());
}
@@ -229,6 +236,8 @@
SQLColumnInfo[] columnInfos = fieldInfos[i].getColumnInfo();
if (clsDescNature.getTableName().equals(fieldInfos[i].getTableName())) {
for (int j = 0; j < columnInfos.length; j++) {
+ select.addSelect(new Column(new Table(clsDescNature.getTableName()),
+ fieldInfos[i].getColumnInfo()[j].getName()));
expr.addColumn(clsDescNature.getTableName(),
fieldInfos[i].getColumnInfo()[j].getName());
}
@@ -237,7 +246,7 @@
if (hasFieldToAdd) {
expr.addTable(clsDescNature.getTableName(),
- clsDescNature.getTableName());
+ clsDescNature.getTableName());
}
}
}
@@ -250,6 +259,8 @@
_statementNoLock = expr.getStatement(false);
_statementLock = expr.getStatement(true);
+
+ System.out.println(_statementNoLock);
if (LOG.isTraceEnabled()) {
LOG.trace(Messages.format("jdo.loading", _type, _statementNoLock));
@@ -259,27 +270,29 @@
LOG.warn("Problem building SQL", ex);
throw new MappingException(ex);
}
+
+ UncoupleVisitor uncle = new UncoupleVisitor();
+ uncle.visit(select);
+ _resultColumnMap = uncle.getResultColumnMap();
}
public void executeStatement(final Connection conn, final Identity identity,
- final ProposedEntity entity,
- final AccessMode accessMode)
- throws PersistenceException {
+ final ProposedEntity entity,final AccessMode accessMode) throws PersistenceException {
PreparedStatement stmt = null;
ResultSet rs = null;
SQLColumnInfo[] ids = _engine.getColumnInfoForIdentities();
SQLFieldInfo[] fields = _engine.getInfo();
-
+
try {
boolean locked = accessMode == AccessMode.DbLocked;
String sqlString = locked ? _statementLock : _statementNoLock;
stmt = conn.prepareStatement(sqlString);
-
+
if (LOG.isTraceEnabled()) {
LOG.trace(Messages.format("jdo.loading", _type, stmt.toString()));
}
-
+
int fieldIndex = 1;
// bind the identity of the preparedStatement
for (int i = 0; i < ids.length; i++) {
@@ -309,10 +322,10 @@
SQLHelper.calculateNumberOfFields(_extendingClassDescriptors,
ids.length, fields.length, _numberOfExtendLevels, rs);
ClassDescriptor potentialLeafDescriptor = (ClassDescriptor) returnValues[0];
-
+
if ((potentialLeafDescriptor != null)
&& !potentialLeafDescriptor.getJavaClass().getName().equals(_type)) {
-
+
entity.initializeFields(potentialLeafDescriptor.getFields().length);
entity.setActualEntityClass(potentialLeafDescriptor.getJavaClass());
entity.setExpanded(true);
@@ -324,41 +337,32 @@
return;
}
}
-
- // Load all the fields of the object including one-one relations
- // index to use during ResultSet.getXXX(); don't forget to ignore
- // the identity columns
- int columnIndex = ids.length + 1;
-
- Set processedTables = new HashSet();
- if (fields.length > 0 && fields[0].isJoined()) {
- ClassDescriptor clsDesc = _engine.getDescriptor();
- processedTables.add(new ClassDescriptorJDONature(clsDesc).getTableName());
- }
+
boolean notNull;
// index in fields[] for storing result of SQLTypes.getObject()
- fieldIndex = 1;
- String tableName = null;
for (int i = 0; i < fields.length; ++i) {
SQLFieldInfo field = fields[i];
SQLColumnInfo[] columns = field.getColumnInfo();
- tableName = field.getTableName();
- if (i > 0 && !field.isJoined() && !processedTables.contains(tableName)) {
- columnIndex = columnIndex + ids.length;
+
+ String tableName = field.getTableAlias();
+
+ // If alias of the field is not used, we have to use the tablename
+ if (!_resultColumnMap.containsKey(
+ tableName + "." + field.getColumnInfo()[0].getName())) {
+ tableName = field.getTableName();
}
- processedTables.add(tableName);
-
+
if (!field.isJoined() && (field.getJoinFields() == null)) {
entity.setField(columns[0].toJava(SQLTypeInfos.getValue(
- rs, columnIndex++, columns[0].getSqlType())), i);
- fieldIndex++;
+ rs, _resultColumnMap.get(tableName + "." + columns[0].getName()),
+ columns[0].getSqlType())), i);
} else if (!field.isMulti()) {
- notNull = false;
+ notNull = false;
Object[] id = new Object[columns.length];
for (int j = 0; j < columns.length; j++) {
- id[j] = columns[j].toJava(SQLTypeInfos.getValue(
- rs, columnIndex++, columns[j].getSqlType()));
- fieldIndex++;
+ id[j] = columns[j].toJava(SQLTypeInfos.getValue(rs,
+ _resultColumnMap.get(tableName + "." + columns[j].getName()),
+ columns[j].getSqlType()));
if (id[j] != null) { notNull = true; }
}
entity.setField(((notNull) ? new Identity(id) : null), i);
@@ -367,11 +371,10 @@
notNull = false;
Object[] id = new Object[columns.length];
for (int j = 0; j < columns.length; j++) {
- id[j] = columns[j].toJava(SQLTypeInfos.getValue(
- rs, columnIndex, columns[j].getSqlType()));
+ id[j] = columns[j].toJava(SQLTypeInfos.getValue(rs,
+ _resultColumnMap.get(tableName + "." + columns[j].getName()),
+ columns[j].getSqlType()));
if (id[j] != null) { notNull = true; }
- fieldIndex++;
- columnIndex++;
}
if (notNull) { res.add(new Identity(id)); }
entity.setField(res, i);
@@ -379,44 +382,35 @@
}
while (rs.next()) {
- fieldIndex = 1;
- columnIndex = ids.length + 1;
- processedTables.clear();
- if (fields[0].isJoined()) {
- ClassDescriptor clsDesc = _engine.getDescriptor();
- processedTables.add(new ClassDescriptorJDONature(clsDesc).getTableName());
- }
-
for (int i = 0; i < fields.length; ++i) {
SQLFieldInfo field = fields[i];
SQLColumnInfo[] columns = field.getColumnInfo();
- tableName = field.getTableName();
- if (i > 0 && !field.isJoined() && !processedTables.contains(tableName)) {
- columnIndex = columnIndex + ids.length;
+
+ String tableName = field.getTableAlias();
+ // If alias of the field is not used, we have to use the tablename
+ if (!_resultColumnMap.containsKey(
+ tableName + "." + field.getColumnInfo()[0].getName())) {
+ tableName = field.getTableName();
}
- processedTables.add(tableName);
-
+
if (field.isMulti()) {
ArrayList res = (ArrayList) entity.getField(i);
notNull = false;
Object[] id = new Object[columns.length];
for (int j = 0; j < columns.length; j++) {
- id[j] = columns[j].toJava(SQLTypeInfos.getValue(
- rs, columnIndex, columns[j].getSqlType()));
+ id[j] = columns[j].toJava(SQLTypeInfos.getValue(rs,
+ _resultColumnMap.get(tableName + "." + columns[j].getName()),
+ columns[j].getSqlType()));
if (id[j] != null) { notNull = true; }
- columnIndex++;
}
- fieldIndex++;
if (notNull) {
Identity com = new Identity(id);
if (!res.contains(com)) { res.add(com); }
}
- } else {
- fieldIndex++;
- columnIndex += columns.length;
}
}
}
+
} catch (SQLException except) {
LOG.fatal(Messages.format("jdo.loadFatal", _type,
(accessMode == AccessMode.DbLocked) ? _statementLock : _statementNoLock),