Merge branch 'cassandra-1.2' into trunk

Conflicts:
	doc/cql3/CQL.textile
	src/java/org/apache/cassandra/cql3/QueryProcessor.java
	src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
	src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
	src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
This commit is contained in:
Aleksey Yeschenko 2013-07-26 20:37:43 +03:00
commit 1be575da06
5 changed files with 43 additions and 28 deletions

View File

@ -109,6 +109,7 @@
1.2.8
* cqlsh: add collections support to COPY (CASSANDRA-5698)
* retry important messages for any IOException (CASSANDRA-5804)
* Allow empty IN relations in SELECT/UPDATE/DELETE statements (CASSANDRA-5626)
1.2.7

View File

@ -484,7 +484,7 @@ bc(syntax)..
| <identifier> '[' <term> ']' '=' <term>
<where-clause> ::= <identifier> '=' <term>
| <identifier> IN '(' <term> ( ',' <term> )* ')'
| <identifier> IN '(' ( <term> ( ',' <term> )* )? ')'
<option> ::= TIMESTAMP <integer>
| TTL <integer>
@ -532,7 +532,7 @@ bc(syntax)..
<selection> ::= <identifier> ( '[' <term> ']' )?
<where-clause> ::= <identifier> '=' <term>
| <identifier> IN '(' <term> ( ',' <term> )* ')'
| <identifier> IN '(' ( <term> ( ',' <term> )* )? ')'
p.
__Sample:__
@ -614,7 +614,7 @@ bc(syntax)..
<where-clause> ::= <relation> ( "AND" <relation> )*
<relation> ::= <identifier> ("=" | "<" | ">" | "<=" | ">=") <term>
| <identifier> IN '(' <term> ( ',' <term>)* ')'
| <identifier> IN '(' ( <term> ( ',' <term>)* )? ')'
| TOKEN '(' <identifier> ')' ("=" | "<" | ">" | "<=" | ">=") (<term> | TOKEN '( <term> ')' )
<order-by> ::= <ordering> ( ',' <odering> )*
@ -1084,6 +1084,10 @@ h3. 3.1.0
* @CREATE@ statements for @KEYSPACE@, @TABLE@ and @INDEX@ now supports an @IF NOT EXISTS@ condition. Similarly, @DROP@ statements support a @IF EXISTS@ condition.
* @INSERT@ statements optionally supports a @IF NOT EXISTS@ condition and @UDPATE@ supports @IF@ conditions.
h3. 3.0.5
* SELECT, UPDATE, and DELETE statements now allow empty IN relations (see "CASSANDRA-5626":https://issues.apache.org/jira/browse/CASSANDRA-5626).
h3. 3.0.4
* Updated the syntax for custom "secondary indexes":#createIndexStmt.

View File

@ -861,7 +861,7 @@ relation[List<Relation> clauses]
$clauses.add(new Relation(id, type, t, true));
}
| name=cident K_IN { Relation rel = Relation.createInRelation($name.id); }
'(' f1=term { rel.addInValue(f1); } (',' fN=term { rel.addInValue(fN); } )* ')' { $clauses.add(rel); }
'(' ( f1=term { rel.addInValue(f1); } (',' fN=term { rel.addInValue(fN); } )* )? ')' { $clauses.add(rel); }
;
comparatorType returns [CQL3Type t]

View File

@ -191,7 +191,7 @@ public abstract class ModificationStatement implements CQLStatement
for (CFDefinition.Name name : cfDef.keys.values())
{
List<Term> values = processedKeys.get(name.name);
if (values == null || values.isEmpty())
if (values == null)
throw new InvalidRequestException(String.format("Missing mandatory PRIMARY KEY part %s", name));
if (keyBuilder.remainingCount() == 1)
@ -206,7 +206,7 @@ public abstract class ModificationStatement implements CQLStatement
}
else
{
if (values.size() > 1)
if (values.isEmpty() || values.size() > 1)
throw new InvalidRequestException("IN is only supported on the last column of the partition key");
ByteBuffer val = values.get(0).bindAndGet(variables);
if (val == null)
@ -226,7 +226,7 @@ public abstract class ModificationStatement implements CQLStatement
for (CFDefinition.Name name : cfDef.columns.values())
{
List<Term> values = processedKeys.get(name.name);
if (values == null || values.isEmpty())
if (values == null)
{
firstEmptyKey = name;
if (requireFullClusteringKey() && cfDef.isComposite && !cfDef.isCompact)
@ -354,7 +354,10 @@ public abstract class ModificationStatement implements CQLStatement
else
cl.validateForWrite(cfm.ksName);
StorageProxy.mutateWithTriggers(getMutations(options.getValues(), false, cl, queryState.getTimestamp(), false), cl, false);
Collection<? extends IMutation> mutations = getMutations(options.getValues(), false, cl, queryState.getTimestamp(), false);
if (!mutations.isEmpty())
StorageProxy.mutateWithTriggers(mutations, cl, false);
return null;
}

View File

@ -271,6 +271,9 @@ public class SelectStatement implements CQLStatement
private List<ReadCommand> getSliceCommands(List<ByteBuffer> variables, int limit, long now) throws RequestValidationException
{
Collection<ByteBuffer> keys = getKeys(variables);
if (keys.isEmpty()) // in case of IN () for (the last column of) the partition key.
return null;
List<ReadCommand> commands = new ArrayList<ReadCommand>(keys.size());
IDiskAtomFilter filter = makeFilter(variables, limit);
@ -287,6 +290,7 @@ public class SelectStatement implements CQLStatement
// (this is fairly ugly and we should change that but that's probably not a tiny refactor to do that cleanly)
commands.add(ReadCommand.create(keyspace(), key, columnFamily(), now, filter.cloneShallow()));
}
return commands;
}
@ -413,6 +417,8 @@ public class SelectStatement implements CQLStatement
else
{
SortedSet<ByteBuffer> columnNames = getRequestedColumns(variables);
if (columnNames == null) // in case of IN () for the last column of the key
return null;
QueryProcessor.validateColumnNames(columnNames);
return new NamesQueryFilter(columnNames, true);
}
@ -469,7 +475,7 @@ public class SelectStatement implements CQLStatement
}
else
{
if (r.eqValues.size() > 1)
if (r.isINRestriction())
throw new InvalidRequestException("IN is only supported on the last column of the partition key");
ByteBuffer val = r.eqValues.get(0).bindAndGet(variables);
if (val == null)
@ -544,11 +550,13 @@ public class SelectStatement implements CQLStatement
{
ColumnIdentifier id = idIter.next();
assert r != null && r.isEquality();
if (r.eqValues.size() > 1)
if (r.isINRestriction())
{
// 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 (r.eqValues.isEmpty())
return null;
SortedSet<ByteBuffer> columns = new TreeSet<ByteBuffer>(cfDef.cfm.comparator);
Iterator<Term> iter = r.eqValues.iterator();
while (iter.hasNext())
@ -665,7 +673,7 @@ public class SelectStatement implements CQLStatement
if (r.isEquality())
{
if (r.eqValues.size() > 1)
if (r.isINRestriction())
{
// IN query, we only support it on the clustering column
assert name.position == names.size() - 1;
@ -738,15 +746,13 @@ public class SelectStatement implements CQLStatement
}
if (restriction.isEquality())
{
for (Term t : restriction.eqValues)
{
ByteBuffer value = t.bindAndGet(variables);
if (value == null)
throw new InvalidRequestException(String.format("Unsupported null value for indexed column %s", name));
if (value.remaining() > 0xFFFF)
throw new InvalidRequestException("Index expression values may not be larger than 64K");
expressions.add(new IndexExpression(name.name.key, IndexOperator.EQ, value));
}
assert restriction.eqValues.size() == 1; // IN is not supported for indexed columns.
ByteBuffer value = restriction.eqValues.get(0).bindAndGet(variables);
if (value == null)
throw new InvalidRequestException(String.format("Unsupported null value for indexed column %s", name));
if (value.remaining() > 0xFFFF)
throw new InvalidRequestException("Index expression values may not be larger than 64K");
expressions.add(new IndexExpression(name.name.key, IndexOperator.EQ, value));
}
else
{
@ -1062,7 +1068,7 @@ public class SelectStatement implements CQLStatement
* WHERE clause. For a given entity, rules are:
* - EQ relation conflicts with anything else (including a 2nd EQ)
* - Can't have more than one LT(E) relation (resp. GT(E) relation)
* - IN relation are restricted to row keys (for now) and conflics with anything else
* - IN relation are restricted to row keys (for now) and conflicts with anything else
* (we could allow two IN for the same entity but that doesn't seem very useful)
* - The value_alias cannot be restricted in any way (we don't support wide rows with indexed value in CQL so far)
*/
@ -1110,7 +1116,6 @@ public class SelectStatement implements CQLStatement
// But we still need to know 2 things:
// - If we don't have a queriable index, is the query ok
// - Is it queriable without 2ndary index, which is always more efficient
// If a component of the partition key is restricted by a non-EQ relation, all preceding
// components must have a EQ, and all following must have no restriction
boolean shouldBeDone = false;
@ -1156,12 +1161,9 @@ public class SelectStatement implements CQLStatement
}
else if (restriction.onToken)
{
// If this is a query on tokens, it's necessary a range query (there can be more than one key per token), so reject IN queries (as we don't know how to do them)
// If this is a query on tokens, it's necessarily a range query (there can be more than one key per token).
stmt.isKeyRange = true;
stmt.onToken = true;
if (restriction.isEquality() && restriction.eqValues.size() > 1)
throw new InvalidRequestException("Select using the token() function don't support IN clause");
}
else if (stmt.onToken)
{
@ -1169,7 +1171,7 @@ public class SelectStatement implements CQLStatement
}
else if (restriction.isEquality())
{
if (restriction.eqValues.size() > 1)
if (restriction.isINRestriction())
{
// We only support IN for the last name so far
if (i != stmt.keyRestrictions.length - 1)
@ -1226,7 +1228,7 @@ public class SelectStatement implements CQLStatement
}
// We only support IN for the last name and for compact storage so far
// TODO: #3885 allows us to extend to non compact as well, but that remains to be done
else if (restriction.eqValues.size() > 1)
else if (restriction.isINRestriction())
{
if (i != stmt.columnRestrictions.length - 1)
throw new InvalidRequestException(String.format("PRIMARY KEY part %s cannot be restricted by IN relation", cname));
@ -1502,6 +1504,11 @@ public class SelectStatement implements CQLStatement
return eqValues != null;
}
boolean isINRestriction()
{
return isEquality() && (eqValues.isEmpty() || eqValues.size() > 1);
}
public Term bound(Bound b)
{
return bounds[b.idx];