Fix multicolumn relation + COMPACT STORAGE issues

Patch by Tyler Hobbs; reviewed by Benjamin Lerer for CASSANDRA-8264
This commit is contained in:
Tyler Hobbs 2014-11-19 11:25:09 -06:00
parent 1945384fdf
commit 084d93daf6
3 changed files with 730 additions and 611 deletions

View File

@ -1,4 +1,6 @@
2.0.12:
* Fix some failing queries that use multi-column relations
on COMPACT STORAGE tables (CASSANDRA-8264)
* Fix InvalidRequestException with ORDER BY (CASSANDRA-8286)
* Disable SSLv3 for POODLE (CASSANDRA-8265)
* Fix millisecond timestamps in Tracing (CASSANDRA-8297)

View File

@ -713,9 +713,9 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
CFDefinition.Name name = idIter.next();
assert r != null && !r.isSlice();
List<ByteBuffer> values = r.values(variables);
if (values.size() == 1)
if (r.isEQ())
{
List<ByteBuffer> values = r.values(variables);
ByteBuffer val = values.get(0);
if (val == null)
throw new InvalidRequestException(String.format("Invalid null value for clustering key part %s", name.name));
@ -723,26 +723,56 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
}
else
{
// We have a IN, which we only support for the last column.
// If compact, just add all values and we're done. Otherwise,
// for each value of the IN, creates all the columns corresponding to the selection.
if (values.isEmpty())
return null;
SortedSet<ByteBuffer> columns = new TreeSet<ByteBuffer>(cfDef.cfm.comparator);
Iterator<ByteBuffer> iter = values.iterator();
while (iter.hasNext())
if (!r.isMultiColumn())
{
ByteBuffer val = iter.next();
ColumnNameBuilder b = iter.hasNext() ? builder.copy() : builder;
if (val == null)
throw new InvalidRequestException(String.format("Invalid null value for clustering key part %s", name.name));
b.add(val);
if (cfDef.isCompact)
columns.add(b.build());
else
columns.addAll(addSelectedColumns(b));
// We have a IN, which we only support for the last column.
// If compact, just add all values and we're done. Otherwise,
// for each value of the IN, creates all the columns corresponding to the selection.
List<ByteBuffer> values = r.values(variables);
if (values.isEmpty())
return null;
SortedSet<ByteBuffer> columns = new TreeSet<ByteBuffer>(cfDef.cfm.comparator);
Iterator<ByteBuffer> iter = values.iterator();
while (iter.hasNext())
{
ByteBuffer val = iter.next();
ColumnNameBuilder b = iter.hasNext() ? builder.copy() : builder;
if (val == null)
throw new InvalidRequestException(String.format("Invalid null value for clustering key part %s", name.name));
b.add(val);
if (cfDef.isCompact)
columns.add(b.build());
else
columns.addAll(addSelectedColumns(b));
}
return columns;
}
else
{
// we have a multi-column IN restriction
List<List<ByteBuffer>> values = ((MultiColumnRestriction.IN) r).splitValues(variables);
if (values.isEmpty())
return null;
TreeSet<ByteBuffer> inValues = new TreeSet<>(cfDef.cfm.comparator);
for (List<ByteBuffer> components : values)
{
ColumnNameBuilder b = builder.copy();
for (int i = 0; i < components.size(); i++)
{
if (components.get(i) == null)
{
List<CFDefinition.Name> clusteringCols = new ArrayList<>(cfDef.clusteringColumns());
throw new InvalidRequestException("Invalid null value in condition for clustering column " + clusteringCols.get(i + name.position));
}
b.add(components.get(i));
}
if (cfDef.isCompact)
inValues.add(b.build());
else
inValues.addAll(addSelectedColumns(b));
}
return inValues;
}
return columns;
}
}
@ -1127,10 +1157,27 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
{
Comparator<ByteBuffer> comp = cfDef.cfm.comparator;
// For dynamic CF, the column could be out of the requested bounds, filter here
if (!sliceRestriction.isInclusive(Bound.START) && comp.compare(c.name(), sliceRestriction.bound(Bound.START, variables)) == 0)
continue;
if (!sliceRestriction.isInclusive(Bound.END) && comp.compare(c.name(), sliceRestriction.bound(Bound.END, variables)) == 0)
continue;
if (!sliceRestriction.isInclusive(Bound.START))
{
// even though it's a multi-column restriction, we know it can only contain a bound for one
// column because we've already checked that the comparator is not composite
ByteBuffer bounds = sliceRestriction.isMultiColumn()
? ((MultiColumnRestriction.Slice) sliceRestriction).componentBounds(Bound.START, variables).get(0)
: sliceRestriction.bound(Bound.START, variables);
if (comp.compare(c.name(), bounds) == 0)
continue;
}
if (!sliceRestriction.isInclusive(Bound.END))
{
// see the above comment on using the first bound from the multi-column restriction
ByteBuffer bounds = sliceRestriction.isMultiColumn()
? ((MultiColumnRestriction.Slice) sliceRestriction).componentBounds(Bound.END, variables).get(0)
: sliceRestriction.bound(Bound.END, variables);
if (comp.compare(c.name(), bounds) == 0)
continue;
}
}
result.newRow();