* @param lock Whether to lock the rows found by this SELECT
* @return The statement
*/
public String toString(boolean lock)
{
final RDBMSAdapter datastoreAdapter = ((RDBMSAdapter) mainTable.getStoreManager().getDatastoreAdapter());
// Build the SELECT list
StringBuffer stmt = new StringBuffer("SELECT ");
Iterator iter = selected.iterator();
while (iter.hasNext())
{
stmt.append(iter.next());
if (iter.hasNext())
{
stmt.append(',');
}
}
// Generate the FROM clause
String[] mainTableColumnID = new String[mainTable.getIDMapping().getNumberOfDatastoreFields()];
int countIdFields = mainTable.getIDMapping().getNumberOfDatastoreFields();
for (int j=0; j<countIdFields; j++)
{
mainTableColumnID[j] = referenceDatastoreField(mainTable.getIDMapping().getDataStoreMapping(j).getDatastoreField());
}
stmt.append(" FROM ").append(mainTable.toString()).append(" ").append("THIS");
// Add any locking of the rows for datastores that require WITH option to be placed after the FROM clause
if (lock && datastoreAdapter.getPlaceWithOptionAfterFromClause() && datastoreAdapter.getSelectWithLockOption() != null)
{
stmt.append(" WITH ").append(datastoreAdapter.getSelectWithLockOption());
}
StringBuffer joinConditions = new StringBuffer();
RDBMSAdapter dba = (RDBMSAdapter)mainTable.getStoreManager().getDatastoreAdapter();
// LEFT OUTER JOINs
if (!outerTableMappings.isEmpty())
{
JavaTypeMapping mainIdMapping = mainTable.getIDMapping();
iter = outerTableMappings.entrySet().iterator();
while (iter.hasNext())
{
Map.Entry entry = (Map.Entry)iter.next();
String alias = (String)entry.getKey();
OuterJoinDefinition def = (OuterJoinDefinition)entry.getValue();
JavaTypeMapping refMapping = def.getReferenceMapping();
JavaTypeMapping refDiscrimMapping = def.getReferenceDiscrimMapping();
Object[] refDiscrimValues = def.getDiscriminatorValues();
JavaTypeMapping refTypeMapping = def.getReferenceTypeMapping();
String refTableName = ((Column)refMapping.getDataStoreMapping(0).getDatastoreField()).getDatastoreContainerObject().toString();
if (dba.supportsAnsiJoinSyntax())
{
// ANSI syntax left outer join
stmt.append(" LEFT OUTER JOIN ").append(refTableName).append(" ").append(alias);
if (datastoreAdapter.getPlaceWithOptionWithinJoinClauses())
{
stmt.append(" WITH ").append(datastoreAdapter.getSelectWithLockOption());
}
stmt.append(" ON ");
if (refDiscrimMapping != null && refDiscrimValues != null)
{
stmt.append("(");
}
int countMainIdFields = mainIdMapping.getNumberOfDatastoreFields();
for (int i=0; i<countMainIdFields; i++)
{
if (i > 0)
{
stmt.append(" AND ");
}
stmt.append(getColumnReference("THIS", mainIdMapping.getDataStoreMapping(i).getDatastoreField()));
stmt.append(" = ");
stmt.append(getColumnReference(alias, refMapping.getDataStoreMapping(i).getDatastoreField()));
}
if (refDiscrimMapping != null && refDiscrimValues != null)
{
// Add constraint on discriminator in related table
stmt.append(" AND (");
for (int i=0;i<refDiscrimValues.length;i++)
{
if (i > 0)
{
stmt.append(" OR ");
}
stmt.append(getColumnReference(alias, refDiscrimMapping.getDataStoreMapping(0).getDatastoreField()));
stmt.append(" = ");
// TODO Cater for numeric discriminator types
// TODO Should we always use single quote for character values ?
stmt.append("'" + refDiscrimValues[i] + "'");
}
stmt.append("))");
}
else if (refTypeMapping != null)
{
// Add join to reference type mapping table from reference table
String refTypeTableName = refTypeMapping.getDataStoreMapping(0).getDatastoreField().getDatastoreContainerObject().toString();
stmt.append(" INNER JOIN ").append(refTypeTableName).append(" ").append(alias + "_SUB");
if (datastoreAdapter.getPlaceWithOptionWithinJoinClauses())
{
stmt.append(" WITH ").append(datastoreAdapter.getSelectWithLockOption());
}
stmt.append(" ON ");
int countRefTypeTableFields = refTypeMapping.getNumberOfDatastoreFields();
JavaTypeMapping refIdMapping = refMapping.getDatastoreContainer().getIDMapping();
for (int i=0; i<countRefTypeTableFields; i++)
{
if (i > 0)
{
stmt.append(" AND ");
}
stmt.append(getColumnReference(alias + "_SUB", refTypeMapping.getDataStoreMapping(i).getDatastoreField()));
stmt.append(" = ");
stmt.append(getColumnReference(alias, refIdMapping.getDataStoreMapping(i).getDatastoreField()));
}
}
}
else
{
// Non-ANSI syntax - add table to "stmt", and join definition to "joinConditions"
stmt.append(',').append(refTableName).append(" ").append(alias);
if (refDiscrimMapping != null && refDiscrimValues != null)
{
joinConditions.append("(");
}
int countMainIdFields = mainIdMapping.getNumberOfDatastoreFields();
for (int i=0; i<countMainIdFields; i++)
{
if (joinConditions.length() > 0)
{
joinConditions.append(" AND ");
}
joinConditions.append(
dba.getNonAnsiLeftOuterJoinWhereClause(mainIdMapping.getDataStoreMapping(i).getDatastoreField().toString(),
refMapping.getDataStoreMapping(i).getDatastoreField().toString()));
}
if (refDiscrimMapping != null && refDiscrimValues != null)
{
// Add constraint on discriminator in related table
joinConditions.append(" AND (");
for (int i=0;i<refDiscrimValues.length;i++)
{
if (i > 0)
{
joinConditions.append(" OR ");
}
joinConditions.append(getColumnReference(alias, refDiscrimMapping.getDataStoreMapping(0).getDatastoreField()));
joinConditions.append(" = ");
// TODO Cater for numeric discriminator types
// TODO Should we always use single quote for character values ?
joinConditions.append("'" + refDiscrimValues[i] + "'");
}
joinConditions.append("))");
}
else if (refTypeMapping != null)
{
// Add join to ref type mapping table
String refTypeTableName = refTypeMapping.getDataStoreMapping(0).getDatastoreField().getDatastoreContainerObject().toString();
stmt.append(',').append(refTypeTableName).append(" ").append(alias + "_SUB");
int countRefTypeTableFields = refTypeMapping.getNumberOfDatastoreFields();
JavaTypeMapping refIdMapping = refMapping.getDatastoreContainer().getIDMapping();
for (int i=0; i<countRefTypeTableFields; i++)
{
if (i > 0)
{
stmt.append(" AND ");
}
joinConditions.append(
dba.getNonAnsiInnerJoinWhereClause(refTypeMapping.getDataStoreMapping(i).getDatastoreField().toString(),
refIdMapping.getDataStoreMapping(i).getDatastoreField().toString()));
}
}
}
}
}
// INNER JOINs
if (!innerTableMappings.isEmpty())
{
JavaTypeMapping mainIdMapping = mainTable.getIDMapping();
iter = innerTableMappings.entrySet().iterator();
while (iter.hasNext())
{
Map.Entry entry = (Map.Entry)iter.next();
String alias = (String)entry.getKey();
InnerJoinDefinition join = (InnerJoinDefinition)entry.getValue();
if (dba.supportsAnsiJoinSyntax())
{
stmt.append(" INNER JOIN ").append(join.getTable()).append(" ").append(alias);
if (lock && datastoreAdapter.getPlaceWithOptionWithinJoinClauses())
{
stmt.append(" WITH ").append(datastoreAdapter.getSelectWithLockOption());
}
stmt.append(" ON ");
int countReferenceFields = join.getReferenceMapping().getNumberOfDatastoreFields();
for (int i=0; i<countReferenceFields; i++)
{
stmt.append(getColumnReference("THIS", mainIdMapping.getDataStoreMapping(i).getDatastoreField()));
stmt.append(" = ");
stmt.append(getColumnReference(alias, join.getReferenceMapping().getDataStoreMapping(i).getDatastoreField()));
if (i < join.getReferenceMapping().getNumberOfDatastoreFields()-1)
{
stmt.append(" AND ");
}
}
}
else
{
stmt.append(',').append(join.getTable()).append(" ").append(alias);
String[] supertableColumnID = new String[mainTable.getIDMapping().getNumberOfDatastoreFields()];
int countReferenceFields = join.getReferenceMapping().getNumberOfDatastoreFields();
for (int i=0; i<countReferenceFields; i++)
{
supertableColumnID[i] = getColumnReference(alias, join.getReferenceMapping().getDataStoreMapping(i).getDatastoreField());
}
for (int i=0; i<countReferenceFields; i++)
{
if (joinConditions.length() > 0)
{
joinConditions.append(" AND ");
}
joinConditions.append(dba.getNonAnsiInnerJoinWhereClause(mainTableColumnID[i], supertableColumnID[i]));
}
}
}
}