Merge branch cassandra-3.0 into trunk

This commit is contained in:
blerer 2015-09-17 21:48:20 +02:00
commit d6d5698b8d
10 changed files with 166 additions and 19 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

@ -63,7 +63,7 @@ public class DropTableStatement extends SchemaAlteringStatement
try
{
KeyspaceMetadata ksm = Schema.instance.getKSMetaData(keyspace());
CFMetaData cfm = ksm.tables.getNullable(columnFamily());
CFMetaData cfm = ksm.getTableOrViewNullable(columnFamily());
if (cfm != null)
{
if (cfm.isView())

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

@ -22,18 +22,16 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.datastax.driver.core.*;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.exceptions.InvalidQueryException;
import junit.framework.Assert;
import org.apache.cassandra.concurrent.SEPExecutor;
import org.apache.cassandra.concurrent.Stage;
import org.apache.cassandra.concurrent.StageManager;
@ -46,6 +44,14 @@ import org.apache.cassandra.serializers.SimpleDateSerializer;
import org.apache.cassandra.serializers.TimeSerializer;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.FBUtilities;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.exceptions.InvalidQueryException;
public class ViewTest extends CQLTester
{
@ -1352,4 +1358,30 @@ public class ViewTest extends CQLTester
row(2),
row(1));
}
@Test
public void testDropTableWithMV() throws Throwable
{
createTable("CREATE TABLE %s (" +
"a int," +
"b int," +
"c int," +
"d int," +
"PRIMARY KEY (a, b, c))");
executeNet(protocolVersion, "USE " + keyspace());
createView(keyspace() + ".mv1",
"CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE b IS NOT NULL AND c IS NOT NULL PRIMARY KEY (a, b, c)");
try
{
executeNet(protocolVersion, "DROP TABLE " + keyspace() + ".mv1");
Assert.fail();
}
catch (InvalidQueryException e)
{
Assert.assertEquals("Cannot use DROP TABLE on Materialized View", e.getMessage());
}
}
}

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;"));
}
}