m_query.visit(new Query.Visitor()
{
public boolean visit(final Query query)
{
boolean bHomogeneous = (query.getRoot() == m_query);
Query primarySource = query, fieldSource = null;
SQLJoin primaryJoin, fieldJoin = null;
Index primaryKey, fieldKey = null;
if (query.isRoot() && bHomogeneous)
{
primaryJoin = addTable(query, ((RelationalMapping)query.getPersistenceMapping()).getPrimaryTable());
primaryJoin.isInner = true;
primaryJoin.isEnabled = true;
primaryKey = primaryJoin.table.getPrimaryKey();
if (query.isJoin())
{
Index destinationKey = (Index)query.getKey(true);
int nDKColumnCount = destinationKey.getIndexColumnCount();
Field[] dkFieldArray = new Field[nDKColumnCount];
SQLJoin join = addTable(query, destinationKey.getTable());
join.isInner = true;
join.isEnabled = true;
for (int i = 0; i < nDKColumnCount; ++i)
{
Column column = destinationKey.getIndexColumn(i).getColumn();
addOutputField(dkFieldArray[i] = new Field(query, join, column,
column.getValueType(), m_adapter.getConverter(column.getValueType(), column),
m_adapter.getBind(column), true));
}
query.setChildItem(dkFieldArray);
}
}
else
{
Index sourceKey = (Index)query.getKey(false);
SQLJoin parent;
if (sourceKey.isObjectKey())
{
parent = (SQLJoin)query.getParent().getMapping();
sourceKey = parent.table.getPrimaryKey();
}
else
{
parent = addTable(query.getParent(), sourceKey.getTable());
}
parent.isEnabled = true;
if (bHomogeneous)
{
Index destinationKey = (Index)query.getKey(true);
SQLJoin join = addTable(query, destinationKey.getTable());
join.parent = parent;
join.sourceKey = sourceKey;
join.destinationKey = destinationKey;
// Decide whether we can use the left joined table
// source key instead of the right joined table primary key
// to reduce the number of indirections in the SQL query
// TODO: Traverse the parent list up for more potential savings
if (query.getWhere() == null &&
(destinationKey.isObjectKey() &&
(!query.isOutput() ||
(!sourceKey.isObjectKey() || query.isRequired()) &&
query.getFieldCount() == 0 &&
query.getAssocCount(Query.ASSOC_QUERY) == 0) ||
destinationKey.isObjectKeyPart() &&
!query.isOutput() &&
query.getFieldCount() == 0 &&
query.getAssocCount(Query.ASSOC_QUERY) == 0))
{
primarySource = query.getParent();
primaryJoin = parent;
primaryKey = sourceKey;
}
else
{
primaryJoin = join;
primaryKey = join.table.getPrimaryKey();
if (destinationKey.isObjectKeyPart() &&
(!sourceKey.isObjectKey() || query.isRequired()))
{
fieldSource = query.getParent();
fieldJoin = parent;
fieldKey = sourceKey;
}
}
if (join.parent.isInner && query.isRequired())
{
join.isInner = true;
}
}
else
{
primarySource = query.getParent();
primaryJoin = parent;
primaryKey = sourceKey;
}
}
primaryJoin.isEnabled = true;
int nPKColumnCount = primaryKey.getIndexColumnCount();
Field[] pkFieldArray = new Field[nPKColumnCount];
for (int i = 0; i < nPKColumnCount; ++i)
{
Column column = primaryKey.getIndexColumn(i).getColumn();
pkFieldArray[i] = new Field(primarySource, primaryJoin, column,
column.getValueType(), m_adapter.getConverter(column.getValueType(), column),
m_adapter.getBind(column), true);
}
if (query.getParent() != null && query.getParentItem() == null)
{
query.setParentItem(pkFieldArray);
}
if (bHomogeneous || (query.getRestriction() & Query.RESTRICTION_WHERE) != 0)
{
// The following conditional relies on the visit order
// to avoid overwriting the PK in a hetero query
if (query.getItem() == null)
{
query.setItem(pkFieldArray);
if (fieldSource != null)
{
int nColumnCount = fieldKey.getIndexColumnCount();
Field[] fieldArray = new Field[nColumnCount];
for (int i = 0; i < nColumnCount; ++i)
{
Column column = fieldKey.getIndexColumn(i).getColumn();
fieldArray[i] = new Field(primarySource, fieldJoin, column,
column.getValueType(), m_adapter.getConverter(column.getValueType(), column),
m_adapter.getBind(column), true);
}
query.setFieldItem(fieldArray);
}
else
{
query.setFieldItem(pkFieldArray);
}
}
}
if (query.isOutput() ||
!bHomogeneous && (query.getRestriction() & Query.RESTRICTION_WHERE) == 0)
{
if (query.isIdentity() || !query.isOutput())
{
// Output the primary key columns
for (int i = 0; i < nPKColumnCount; ++i)
{
addOutputField(pkFieldArray[i]);
}
}
m_query.addOutputQuery(query);
}
if (bHomogeneous)
{
// Bind the columns to the attributes
for (Iterator itr = query.getFieldIterator(); itr.hasNext();)
{
Field field = (Field)itr.next();
if (!field.isPersistent())
{
continue;
}
Operator op = field.getOperator();
if (op != null)
{
if (op.getType() instanceof Primitive)
{
field.setBind(m_adapter.getBind((Primitive)op.getType()));
}
}
else
{
Column column = ((RelationalPrimitiveMapping)field.getAttributeMapping()).getColumn();
SQLJoin join = addTable(query, column.getTable());
join.isEnabled = true;
field.setMapping(join);
field.setItem(column);
field.setConverter(m_adapter.getConverter((Primitive)field.getAttribute().getType(), column));
field.setBind(m_adapter.getBind(column));
}
// Add the output columns to the join
if (field.isOutput() && field.getBind() != null)
{
addOutputField(field);
}
}
assert query.getMapping() != null;
}
return true;
}
public boolean postVisit(final Query query)
{
if (query.isMatch()) // only postprocess operators if any require it
{
opVisit(query);
}
// Determine if a subquery should be generated
Operator where = query.getWhere();
if (where != null && !query.isRoot() && !query.isQuantorRoot())
{
for (Iterator itr = query.getAssocIterator(Query.ASSOC_WHERE); itr.hasNext();)
{
Query assoc = (Query)itr.next();
if (assoc.isSameRoot(query))
{
SQLJoin join = (SQLJoin)assoc.getMapping();
do
{
if (join.isEnabled)
{