mirror of https://github.com/apache/cassandra
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:
commit
1be575da06
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
Loading…
Reference in New Issue