/**
* @see nexj.core.meta.persistence.PersistenceMapping#getSortKeys(nexj.core.meta.Attribute[], nexj.core.meta.persistence.PersistenceMapping[], nexj.core.meta.Attribute[])
*/
public Pair getSortKeys(Attribute[] assocs, PersistenceMapping[] mappings, Attribute[] restrictions)
{
Pair sortKeys = null;
Pair lastKey = null;
BitSet filterSet = null;
BitSet optionalSet = null;
int nFilterCount = 0;
// Create a set of attributes that participate in equality
// comparisons due to the associations.
if (assocs != null && assocs.length > 0)
{
filterSet = new BitSet(m_metaclass.getInstanceAttributeCount());
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 VirtualClassMapping)
{
VirtualClassMapping classMapping = (VirtualClassMapping)attributeMapping;
if (classMapping.getMapping() == this && classMapping.getKey(true) instanceof VirtualKey)
{
VirtualKey key = (VirtualKey)classMapping.getKey(true);
if (!key.isUnique())
{
for (int k = 0, nCount = key.getAttributeCount(); k < nCount; k++)
{
Attribute attr = key.getAttribute(k);
assert attr.getMetaclass() == m_metaclass;
assert !attr.getType().isPrimitive();
filterSet.set(attr.getOrdinal());
}
}
}
}
}
nFilterCount = filterSet.cardinality();
}
// Create a set of attributes that participate in equality
// comparisons and can be optionally excluded from the index.
if (restrictions != null && restrictions.length > 0)
{
optionalSet = new BitSet(m_metaclass.getInstanceAttributeCount());
for (int i = 0; i < restrictions.length; i++)
{
optionalSet.set(restrictions[i].getOrdinal());
}
}
// Collect the sort keys
for (int nSortKey = 0; nSortKey < m_sortKeyList.size(); nSortKey++)
{
VirtualSortKey sortKey = (VirtualSortKey)m_sortKeyList.get(nSortKey);
// Ignore sort keys that do not start with the columns specified in the
// association filter, in arbitrary order
if (nFilterCount > 0)
{
if (sortKey.getAttributeCount() < nFilterCount)
{
continue;
}
int i;
for (i = 0; i < nFilterCount; i++)
{
Attribute attr = sortKey.getAttribute(i);
if (attr == null || !filterSet.get(attr.getOrdinal()))
{
break;
}
}
if (i < nFilterCount)
{
continue;
}
}
// Find out if the sort key includes the primary key
Key pk = getObjectKey();
boolean bMatch = false;
boolean bAscending = true;
for (int i = 0, k = -1; i < sortKey.getAttributeCount(); i++)
{
Attribute attr = sortKey.getAttribute(i);
if (attr == null)
{
bMatch = true;
bAscending = sortKey.isAscending(i);
break;
}
if (optionalSet != null && optionalSet.get(attr.getOrdinal()))
{
continue;
}
if (getAttributeMapping(attr) instanceof VirtualPrimitiveMapping)
{
VirtualPrimitiveMapping mapping = (VirtualPrimitiveMapping)getAttributeMapping(attr);
if (mapping.getObjectKeyPart() >= 0)
{
if (k == -1)
{
if (mapping.getObjectKeyPart() == 0)
{
k = 1;
bAscending = sortKey.isAscending(i);
continue;
}
break;
}
if (mapping.getObjectKeyPart() == k)
{
if ((pk.isPartAscending(0) ^ pk.isPartAscending(k)) != (bAscending ^ sortKey.isAscending(i)))
{
break;
}
else
{
if (k == pk.getPartCount() - 1)
{
bMatch = true;
break;
}
}
}
else
{
break;
}
}
}
}
Pair key = null;
// If the above is true, then append the primary key
// at the end of the sort key
if (bMatch)
{
Pair[] objKeyAttributeArray = new Pair[pk.getPartCount()];
for (int i = 0; i < m_metaclass.getInstanceAttributeCount(); i++)
{
Attribute attr = m_metaclass.getInstanceAttribute(i);
if (getAttributeMapping(attr) instanceof VirtualPrimitiveMapping)
{
VirtualPrimitiveMapping mapping = (VirtualPrimitiveMapping)getAttributeMapping(attr);
if (mapping.getObjectKeyPart() >= 0)
{
objKeyAttributeArray[mapping.getObjectKeyPart()] = new Pair(
attr.getSymbol(),
Boolean.valueOf(bAscending ^ !pk.isPartAscending(mapping.getObjectKeyPart()))
);
}
}
}
boolean bObjKeyFullyMapped = true;
for (int i = 0; i < objKeyAttributeArray.length; i++)
{
if (objKeyAttributeArray[i] == null)
{
bObjKeyFullyMapped = false;
break;
}
}
if (bObjKeyFullyMapped)
{
key = Pair.fromArray(objKeyAttributeArray);
}
else
{
key = new Pair(new Pair(new Pair(Symbol.AT),
Boolean.valueOf(bAscending)));
}
}
else
{
pk = null;
}
int nCount;
// Advance, stopping at first non-ignorable non-primitive-mapped attribute
for (nCount = nFilterCount; nCount < sortKey.getAttributeCount(); nCount++)
{
Attribute attr = sortKey.getAttribute(nCount);
if (attr == null || !attr.getType().isPrimitive())
{
if (optionalSet == null || attr == null || !optionalSet.get(attr.getOrdinal()))
{
break;
}
}
}
bMatch = true;
// Verify that remainder of index is the primary key, or that there is no remaining index
if (pk != null)
{
if (nCount == sortKey.getAttributeCount())
{
key = null;
}
else
{
for (int i = nCount; i < sortKey.getAttributeCount(); i++)
{
Attribute attr = sortKey.getAttribute(i);
if (attr != null)
{
AttributeMapping mapping = getAttributeMapping(attr);
if (mapping instanceof VirtualPrimitiveMapping)
{
if (((VirtualPrimitiveMapping)mapping).getObjectKeyPart() >= 0)
{
continue;
}
}
bMatch = false;
break;
}
}
}
}
if (!bMatch)
{
continue;
}
// Add non-ignorable primitive-mapped columns to the sort key
for (int i = nCount - 1; i >= nFilterCount; i--)
{
Attribute attr = sortKey.getAttribute(i);
if (attr.getType().isPrimitive())
{
if (optionalSet == null || !optionalSet.get(attr.getOrdinal()))
{
key = new Pair(
new Pair(attr.getSymbol(), Boolean.valueOf(sortKey.isAscending(i))),
key
);
}
}
}
// Append the new sort key to the end of the sort key list
if (key != null)
{
key = new Pair(
Boolean.valueOf(pk != null || sortKey.isUnique() && nCount == sortKey.getAttributeCount()),
key
);
if (lastKey == null)
{
sortKeys = lastKey = new Pair(key);
}
else
{
Pair pair;
// Filter out the duplicates
for (pair = sortKeys; pair != null; pair = pair.getNext())
{
if (pair.getHead().equals(key))
{
break;
}
}
if (pair == null)
{
key = new Pair(key);
lastKey.setTail(key);
lastKey = key;
}
}
}