/**
* @see nexj.core.meta.persistence.PersistenceMapping#getSortKeys(nexj.core.meta.Attribute[], nexj.core.meta.persistence.PersistenceMapping[], Attribute[])
*/
public Pair getSortKeys(Attribute[] assocs, PersistenceMapping[] mappings, Attribute[] restrictions)
{
Pair sortKeys = null;
Pair lastKey = null;
for (int nTable = 0; nTable < m_nTableCount; ++nTable)
{
Table table = m_tableArray[nTable];
RelationalPrimitiveMapping[] primitiveMappings = table.findMappingArray(this);
BitSet filterSet = null;
BitSet optionalSet = null;
int nFilterCount = 0;
if (primitiveMappings == null)
{
continue;
}
// Create a set of columns, which participate in equality
// comparisons due to the associations.
if (assocs != null && assocs.length > 0)
{
filterSet = new BitSet(table.getColumnCount());
for (int i = 0; i < assocs.length; ++i)
{
PersistenceMapping mapping = mappings[i];
if (mapping == null)
{
continue;
}
AttributeMapping attributeMapping = mapping.getAttributeMapping(assocs[i]);
if (attributeMapping instanceof RelationalClassMapping)
{
RelationalClassMapping classMapping = (RelationalClassMapping)attributeMapping;
if (classMapping.getMapping() == this &&
classMapping.getDestinationKey() instanceof Index)
{
Index key = (Index)classMapping.getDestinationKey();
if (key.getTable() != table)
{
key = table.getPrimaryKey();
}
if (!key.isUnique())
{
for (int k = key.getIndexColumnCount() - 1; k >= 0; --k)
{
filterSet.set(key.getIndexColumn(k).getColumn().getOrdinal());
}
}
}
}
}
nFilterCount = filterSet.cardinality();
}
// Create a set of columns, which participate in equality
// comparisons and can be optionally excluded from the index.
if (restrictions != null && restrictions.length > 0)
{
optionalSet = new BitSet(table.getColumnCount());
for (int i = 0; i < restrictions.length; ++i)
{
AttributeMapping attributeMapping = getAttributeMapping(restrictions[i]);
if (attributeMapping instanceof RelationalClassMapping)
{
Index index = ((RelationalClassMapping)attributeMapping).getSourceKey();
for (int k = index.getIndexColumnCount() - 1; k >= 0; --k)
{
optionalSet.set(index.getIndexColumn(k).getColumn().getOrdinal());
}
}
else if (attributeMapping instanceof RelationalPrimitiveMapping)
{
optionalSet.set(((RelationalPrimitiveMapping)attributeMapping).getColumn().getOrdinal());
}
}
}
// Collect the sort keys
for (int nIndex = 0; nIndex < table.getIndexCount(); ++nIndex)
{
Index index = table.getIndex(nIndex);
if (index.getType() != Index.CLUSTER &&
index.getType() != Index.BTREE &&
index.getType() != Index.QUERY)
{
continue;
}
// Ignore indexes that do not start with the columns specified
// in the association filter, in arbitrary order
if (nFilterCount > 0)
{
if (index.getIndexColumnCount() < nFilterCount)
{
continue;
}
int i;
for (i = 0; i < nFilterCount; ++i)
{
if (!filterSet.get(index.getIndexColumn(i).getColumn().getOrdinal()))
{
break;
}
}
if (i < nFilterCount)
{
continue;
}
}
Index pk = table.getPrimaryKey();
boolean bMatch = true;
boolean bAscending = true;
Pair key = null;
// Check whether the primary key columns are a subset of the index columns
for (int i = 0; i < pk.getIndexColumnCount(); ++i)
{
IndexColumn pkIndexColumn = pk.getIndexColumn(i);
Column pkColumn = pkIndexColumn.getColumn();
if (optionalSet != null &&
optionalSet.get(pkColumn.getOrdinal()) &&
index.findIndexColumn(pkColumn) != null)
{
continue;
}
int k;
for (k = 0; k < index.getIndexColumnCount(); ++k)
{
IndexColumn indexColumn = index.getIndexColumn(k);
if (indexColumn.getColumn() == pkColumn)
{
if (i == 0)
{
bAscending = indexColumn.isAscending();
}
break;
}
}
if (k == index.getIndexColumnCount())
{
bMatch = false;
break;
}
}
// If the above is true, then append the primary key
// at the end of the sort key
if (bMatch)
{
key = new Pair(new Pair(new Pair(Symbol.AT),
Boolean.valueOf(!(pk.getIndexColumn(0).isAscending() ^ bAscending))));
}
else
{
pk = null;
}
int nCount;
for (nCount = nFilterCount; nCount < index.getIndexColumnCount(); ++nCount)
{
int nOrdinal = index.getIndexColumn(nCount).getColumn().getOrdinal();
if (primitiveMappings[nOrdinal] == null)
{
if (optionalSet == null || !optionalSet.get(nOrdinal))
{
break;
}
}
}
bMatch = true;
if (pk != null)
{
if (nCount == index.getIndexColumnCount())
{
key = null;
}
else
{
for (int i = nCount; i < index.getIndexColumnCount(); ++i)
{
if (!index.getIndexColumn(i).getColumn().isPrimary())
{
bMatch = false;
break;
}
}
}
}
if (!bMatch)
{
continue;
}
boolean bPrimitive = false;
for (int i = nCount - 1; i >= nFilterCount; --i)
{
IndexColumn indexColumn = index.getIndexColumn(i);
int nOrdinal = indexColumn.getColumn().getOrdinal();
RelationalPrimitiveMapping mapping = primitiveMappings[nOrdinal];
if (mapping != null)
{
if (optionalSet == null || !optionalSet.get(nOrdinal))
{
key = new Pair(new Pair(mapping.getAttribute().getSymbol(),
Boolean.valueOf(indexColumn.isAscending())), key);
bPrimitive = true;
}
}
}
// Append the new sort key to the end of the sort key list
if (key != null)
{
lastKey = addKey(new Pair(Boolean.valueOf(pk != null ||
index.isUnique() && nCount == index.getIndexColumnCount()), key), sortKeys, lastKey);
if (sortKeys == null)
{
sortKeys = lastKey;
}
if (pk == index && bPrimitive)
{
lastKey = addKey(new Pair(Boolean.TRUE,
new Pair(new Pair(new Pair(Symbol.AT), Boolean.TRUE))), sortKeys, lastKey);
}
}
}
}