Merge cassandra-2.2 into cassandra-3.0

This commit is contained in:
blerer 2015-09-17 21:38:42 +02:00
parent 2db8370fdf
commit a90de7c61d
8 changed files with 124 additions and 9 deletions

View File

@ -118,6 +118,12 @@ Changed Defaults
of the total space of the commitlog volume. (Before: always used
8192)
New features
------------
- Custom QueryHandlers can retrieve the column specifications for the bound
variables from QueryOptions by using the hasColumnSpecifications()
and getColumnSpecifications() methods.
2.2.1
=====

View File

@ -22,6 +22,8 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.cassandra.utils.MD5Digest;
import org.apache.cassandra.db.ConsistencyLevel;
import org.apache.cassandra.service.QueryState;
@ -50,6 +52,11 @@ public abstract class BatchQueryOptions
public abstract QueryOptions forStatement(int i);
public void prepareStatement(int i, List<ColumnSpecification> boundNames)
{
forStatement(i).prepare(boundNames);
}
public ConsistencyLevel getConsistency()
{
return wrapped.getConsistency();
@ -107,5 +114,26 @@ public abstract class BatchQueryOptions
{
return perStatementOptions.get(i);
}
@Override
public void prepareStatement(int i, List<ColumnSpecification> boundNames)
{
if (isPreparedStatement(i))
{
QueryOptions options = perStatementOptions.get(i);
options.prepare(boundNames);
options = QueryOptions.addColumnSpecifications(options, boundNames);
perStatementOptions.set(i, options);
}
else
{
super.prepareStatement(i, boundNames);
}
}
private boolean isPreparedStatement(int i)
{
return getQueryOrIdList().get(i) instanceof MD5Digest;
}
}
}

View File

@ -18,6 +18,7 @@
package org.apache.cassandra.cql3;
import com.google.common.base.Objects;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.ReversedType;
@ -91,4 +92,13 @@ public class ColumnSpecification
{
return Objects.hashCode(ksName, cfName, name, type);
}
@Override
public String toString()
{
return Objects.toStringHelper(this)
.add("name", name)
.add("type", type)
.toString();
}
}

View File

@ -23,8 +23,9 @@ import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import io.netty.buffer.ByteBuf;
import com.google.common.collect.ImmutableList;
import io.netty.buffer.ByteBuf;
import org.apache.cassandra.db.ConsistencyLevel;
import org.apache.cassandra.service.QueryState;
import org.apache.cassandra.service.pager.PagingState;
@ -72,10 +73,43 @@ public abstract class QueryOptions
return new DefaultQueryOptions(consistency, values, skipMetadata, new SpecificOptions(pageSize, pagingState, serialConsistency, -1L), 0);
}
public static QueryOptions addColumnSpecifications(QueryOptions options, List<ColumnSpecification> columnSpecs)
{
return new OptionsWithColumnSpecifications(options, columnSpecs);
}
public abstract ConsistencyLevel getConsistency();
public abstract List<ByteBuffer> getValues();
public abstract boolean skipMetadata();
/**
* Tells whether or not this <code>QueryOptions</code> contains the column specifications for the bound variables.
* <p>The column specifications will be present only for prepared statements.</p>
* @return <code>true</code> this <code>QueryOptions</code> contains the column specifications for the bound
* variables, <code>false</code> otherwise.
*/
public boolean hasColumnSpecifications()
{
return false;
}
/**
* Returns the column specifications for the bound variables (<i>optional operation</i>).
*
* <p>The column specifications will be present only for prepared statements.</p>
*
* <p>Invoke the {@link hasColumnSpecifications} method before invoking this method in order to ensure that this
* <code>QueryOptions</code> contains the column specifications.</p>
*
* @return the option names
* @throws UnsupportedOperationException If this <code>QueryOptions</code> does not contains the column
* specifications.
*/
public ImmutableList<ColumnSpecification> getColumnSpecifications()
{
throw new UnsupportedOperationException();
}
/** The pageSize for this query. Will be <= 0 if not relevant for the query. */
public int getPageSize()
{
@ -159,7 +193,7 @@ public abstract class QueryOptions
}
}
static abstract class QueryOptionsWrapper extends QueryOptions
static class QueryOptionsWrapper extends QueryOptions
{
protected final QueryOptions wrapped;
@ -168,6 +202,11 @@ public abstract class QueryOptions
this.wrapped = wrapped;
}
public List<ByteBuffer> getValues()
{
return this.wrapped.getValues();
}
public ConsistencyLevel getConsistency()
{
return wrapped.getConsistency();
@ -196,6 +235,32 @@ public abstract class QueryOptions
}
}
/**
* <code>QueryOptions</code> decorator that provides access to the column specifications.
*/
static class OptionsWithColumnSpecifications extends QueryOptionsWrapper
{
private final ImmutableList<ColumnSpecification> columnSpecs;
OptionsWithColumnSpecifications(QueryOptions wrapped, List<ColumnSpecification> columnSpecs)
{
super(wrapped);
this.columnSpecs = ImmutableList.copyOf(columnSpecs);
}
@Override
public boolean hasColumnSpecifications()
{
return true;
}
@Override
public ImmutableList<ColumnSpecification> getColumnSpecifications()
{
return columnSpecs;
}
}
static class OptionsWithNames extends QueryOptionsWrapper
{
private final List<String> names;
@ -228,6 +293,7 @@ public abstract class QueryOptions
return this;
}
@Override
public List<ByteBuffer> getValues()
{
assert orderedValues != null; // We should have called prepare first!

View File

@ -519,7 +519,7 @@ public class BatchStatement implements CQLStatement
// Use the CFMetadata of the first statement for partition key bind indexes. If the statements affect
// multiple tables, we won't send partition key bind indexes.
Short[] partitionKeyBindIndexes = haveMultipleCFs ? null
Short[] partitionKeyBindIndexes = (haveMultipleCFs || batchStatement.statements.isEmpty())? null
: boundNames.getPartitionKeyBindIndexes(batchStatement.statements.get(0).cfm);
return new ParsedStatement.Prepared(batchStatement, boundNames, partitionKeyBindIndexes);

View File

@ -203,7 +203,7 @@ public class BatchMessage extends Message.Request
for (int i = 0; i < prepared.size(); i++)
{
ParsedStatement.Prepared p = prepared.get(i);
batchOptions.forStatement(i).prepare(p.boundNames);
batchOptions.prepareStatement(i, p.boundNames);
if (!(p.statement instanceof ModificationStatement))
throw new InvalidRequestException("Invalid statement in batch: only UPDATE, INSERT and DELETE statements are allowed.");

View File

@ -124,7 +124,10 @@ public class ExecuteMessage extends Message.Request
Tracing.instance.begin("Execute CQL3 prepared query", state.getClientAddress(), builder.build());
}
Message.Response response = handler.processPrepared(statement, state, options, getCustomPayload());
// Some custom QueryHandlers are interested by the bound names. We provide them this information
// by wrapping the QueryOptions.
QueryOptions queryOptions = QueryOptions.addColumnSpecifications(options, prepared.boundNames);
Message.Response response = handler.processPrepared(statement, state, queryOptions, getCustomPayload());
if (options.skipMetadata() && response instanceof ResultMessage.Rows)
((ResultMessage.Rows)response).result.metadata.setSkipMetadata();

View File

@ -18,12 +18,8 @@
package org.apache.cassandra.cql3.validation.operations;
import java.util.Arrays;
import org.junit.Test;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import org.apache.cassandra.cql3.CQLTester;
public class BatchTest extends CQLTester
@ -172,4 +168,10 @@ public class BatchTest extends CQLTester
row(0, 5, 20),
row(0, 6, 20));
}
@Test
public void testBatchEmpty() throws Throwable
{
assertEmpty(execute("BEGIN BATCH APPLY BATCH;"));
}
}