/*
* Copyright 2006 Assaf Arkin, Thomas Yip, Bruce Snyder, Werner Guttmann, 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: SQLStatementLoad.java 8435 2009-09-10 21:56:23Z rjoachim $
*/
package org.exolab.castor.jdo.engine;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.castor.core.util.Messages;
import org.exolab.castor.jdo.QueryException;
import org.exolab.castor.jdo.engine.nature.ClassDescriptorJDONature;
import org.exolab.castor.mapping.ClassDescriptor;
import org.exolab.castor.mapping.MappingException;
import org.exolab.castor.persist.spi.Persistence;
import org.exolab.castor.persist.spi.PersistenceFactory;
import org.exolab.castor.persist.spi.QueryExpression;
public final class SQLStatementQuery {
/** The <a href="http://jakarta.apache.org/commons/logging/">Jakarta
* Commons Logging</a> instance used for all logging. */
private static final Log LOG = LogFactory.getLog(SQLStatementQuery.class);
private final SQLEngine _engine;
private final PersistenceFactory _factory;
private final String _type;
private final String _mapTo;
private QueryExpression _queryExpression;
public SQLStatementQuery(final SQLEngine engine, final PersistenceFactory factory)
throws MappingException {
_engine = engine;
_factory = factory;
_type = engine.getDescriptor().getJavaClass().getName();
_mapTo = new ClassDescriptorJDONature(engine.getDescriptor()).getTableName();
buildStatement();
}
private void buildStatement() throws MappingException {
try {
QueryExpression expr = _factory.getQueryExpression();
Map<String, Boolean> identitiesUsedForTable = new HashMap<String, Boolean>();
Vector<String> joinTables = new Vector<String>();
// join all the extended table
ClassDescriptor curDesc = _engine.getDescriptor();
ClassDescriptor baseDesc;
while (curDesc.getExtends() != null) {
baseDesc = curDesc.getExtends();
String[] curDescIdNames = SQLHelper.getIdentitySQLNames(curDesc);
String[] baseDescIdNames = SQLHelper.getIdentitySQLNames(baseDesc);
expr.addInnerJoin(
new ClassDescriptorJDONature(curDesc).getTableName(), curDescIdNames,
new ClassDescriptorJDONature(curDesc).getTableName(),
new ClassDescriptorJDONature(baseDesc).getTableName(), baseDescIdNames,
new ClassDescriptorJDONature(baseDesc).getTableName());
joinTables.add(new ClassDescriptorJDONature(baseDesc).getTableName());
curDesc = baseDesc;
}
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();
// 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]);
}
identitiesUsedForTable.put(
new ClassDescriptorJDONature(curDesc).getTableName(),
Boolean.TRUE);
}
// add id columns to select statement
if (!alias.equals(aliasOld) && !field.isJoined()) {
ClassDescriptor classDescriptor =
field.getFieldDescriptor().getContainingClassDescriptor();
boolean isTableNameAlreadyAdded = identitiesUsedForTable.containsKey(
new ClassDescriptorJDONature(classDescriptor).getTableName());
if (!isTableNameAlreadyAdded) {
String[] identities = SQLHelper.getIdentitySQLNames(classDescriptor);
for (int j = 0; j < identities.length; j++) {
expr.addColumn(alias, identities[j]);
}
identitiesUsedForTable.put(
new ClassDescriptorJDONature(classDescriptor).getTableName(),
Boolean.TRUE);
}
}
if (field.isJoined()) {
int offset = 0;
String[] rightCol = field.getJoinFields();
String[] leftCol = new String[ids.length - offset];
for (int j = 0; j < leftCol.length; j++) {
leftCol[j] = ids[j + offset].getName();
}
ClassDescriptor clsDescriptor = _engine.getDescriptor();
ClassDescriptorJDONature nature = new ClassDescriptorJDONature(clsDescriptor);
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);
} else {
expr.addOuterJoin(_mapTo, leftCol,
field.getTableName(), rightCol, field.getTableName());
joinTables.add(field.getTableName());
}
}
for (int j = 0; j < field.getColumnInfo().length; j++) {
expr.addColumn(alias, field.getColumnInfo()[j].getName());
}
expr.addTable(field.getTableName(), alias);
}
// 'join' all the extending tables
List<ClassDescriptor> classDescriptorsToAdd = new LinkedList<ClassDescriptor>();
ClassDescriptor classDescriptor = null;
SQLHelper.addExtendingClassDescriptors(classDescriptorsToAdd,
new ClassDescriptorJDONature(_engine.getDescriptor()).getExtended());
if (classDescriptorsToAdd.size() > 0) {
Iterator<ClassDescriptor> iter = classDescriptorsToAdd.iterator();
while (iter.hasNext()) {
classDescriptor = iter.next();
ClassDescriptorJDONature clsDescNature =
new ClassDescriptorJDONature(classDescriptor);
if (LOG.isTraceEnabled()) {
LOG.trace("Adding outer left join for "
+ classDescriptor.getJavaClass().getName() + " on table "
+ clsDescNature.getTableName());
}
String[] engDescIdNames = SQLHelper.getIdentitySQLNames(
_engine.getDescriptor());
String[] clsDescIdNames = SQLHelper.getIdentitySQLNames(classDescriptor);
expr.addOuterJoin(_mapTo, engDescIdNames,
clsDescNature.getTableName(), clsDescIdNames,
clsDescNature.getTableName());
Persistence persistenceEngine;
try {
persistenceEngine = _factory.getPersistence(classDescriptor);
} catch (MappingException e) {
throw new QueryException(
"Problem obtaining persistence engine for ClassDescriptor "
+ classDescriptor.getJavaClass().getName(), e);
}
SQLEngine engine = (SQLEngine) persistenceEngine;
SQLColumnInfo[] idInfos = engine.getColumnInfoForIdentities();
for (int i = 0; i < idInfos.length; i++) {
expr.addColumn(clsDescNature.getTableName(), idInfos[i].getName());
}
SQLFieldInfo[] fieldInfos = ((SQLEngine) persistenceEngine).getInfo();
for (int i = 0; i < fieldInfos.length; i++) {
boolean hasFieldToAdd = false;
SQLColumnInfo[] columnInfos = fieldInfos[i].getColumnInfo();
if (clsDescNature.getTableName().equals(fieldInfos[i].getTableName())) {
for (int j = 0; j < columnInfos.length; j++) {
expr.addColumn(clsDescNature.getTableName(),
fieldInfos[i].getColumnInfo()[j].getName());
}
hasFieldToAdd = true;
}
if (hasFieldToAdd) {
expr.addTable(clsDescNature.getTableName(),
clsDescNature.getTableName());
}
}
}
}
// add table information if the class in question does not have any non-identity fields
if (fields.length == 0) {
for (int i = 0; i < ids.length; i++) {
expr.addColumn(_mapTo, ids[i].getName());
}
}
_queryExpression = expr;
if (LOG.isTraceEnabled()) {
LOG.trace(Messages.format("jdo.finding", _type, _queryExpression));
}
} catch (QueryException ex) {
LOG.warn("Problem building SQL", ex);
throw new MappingException(ex);
}
}
public QueryExpression getQueryExpression() {
return (QueryExpression) _queryExpression.clone();
}
}