All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.datastax.driver.core.BatchStatement Maven / Gradle / Ivy

There is a newer version: 3.6.0-1
Show newest version
/*
 *      Copyright (C) 2012-2015 DataStax Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
package com.datastax.driver.core;

import com.datastax.driver.core.exceptions.UnsupportedFeatureException;
import com.datastax.driver.$internal.com.google.common.collect.ImmutableList;

import java.nio.ByteBuffer;
import java.util.*;

/**
 * A statement that groups a number of {@link Statement} so they get executed as
 * a batch.
 * 

* Note: BatchStatement is not supported with the native protocol version 1: you * will get an {@link UnsupportedFeatureException} when submitting one if * version 1 of the protocol is in use (i.e. if you've force version 1 through * {@link Cluster.Builder#withProtocolVersion} or you use Cassandra 1.2). Note * however that you can still use CQL Batch statements * even with the protocol version 1. *

* Setting a BatchStatement's serial consistency level is only supported with the * native protocol version 3 or higher (see {@link #setSerialConsistencyLevel(ConsistencyLevel)}). */ public class BatchStatement extends Statement { /** * The type of batch to use. */ public enum Type { /** * A logged batch: Cassandra will first write the batch to its distributed batch log * to ensure the atomicity of the batch (atomicity meaning that if any statement in * the batch succeeds, all will eventually succeed). */ LOGGED, /** * A batch that doesn't use Cassandra's distributed batch log. Such batch are not * guaranteed to be atomic. */ UNLOGGED, /** * A counter batch. Note that such batch is the only type that can contain counter * operations and it can only contain these. */ COUNTER } ; final Type batchType; private final List statements = new ArrayList(); /** * Creates a new {@code LOGGED} batch statement. */ public BatchStatement() { this(Type.LOGGED); } /** * Creates a new batch statement of the provided type. * * @param batchType the type of batch. */ public BatchStatement(Type batchType) { this.batchType = batchType; } IdAndValues getIdAndValues(ProtocolVersion protocolVersion, CodecRegistry codecRegistry) { IdAndValues idAndVals = new IdAndValues(statements.size()); for (Statement statement : statements) { if (statement instanceof StatementWrapper) statement = ((StatementWrapper) statement).getWrappedStatement(); if (statement instanceof RegularStatement) { RegularStatement st = (RegularStatement) statement; ByteBuffer[] vals = st.getValues(protocolVersion, codecRegistry); String query = st.getQueryString(codecRegistry); idAndVals.ids.add(query); idAndVals.values.add(vals == null ? Collections.emptyList() : Arrays.asList(vals)); } else { // We handle BatchStatement in add() so ... assert statement instanceof BoundStatement; BoundStatement st = (BoundStatement) statement; idAndVals.ids.add(st.statement.getPreparedId().id); idAndVals.values.add(Arrays.asList(st.wrapper.values)); } } return idAndVals; } /** * Adds a new statement to this batch. *

* Note that {@code statement} can be any {@code Statement}. It is allowed to mix * {@code RegularStatement} and {@code BoundStatement} in the same * {@code BatchStatement} in particular. Adding another {@code BatchStatement} * is also allowed for convenience and is equivalent to adding all the {@code Statement} * contained in that other {@code BatchStatement}. *

* Due to a protocol-level limitation, adding a {@code RegularStatement} with named values * is currently not supported; an {@code IllegalArgument} will be thrown. *

* When adding a {@code BoundStatement}, all of its values must be set, otherwise an * {@code IllegalStateException} will be thrown when submitting the batch statement. * See {@link BoundStatement} for more details, in particular how to handle {@code null} * values. *

* Please note that the options of the added Statement (all those defined directly by the * {@link Statement} class: consistency level, fetch size, tracing, ...) will be ignored * for the purpose of the execution of the Batch. Instead, the options used are the one * of this {@code BatchStatement} object. * * @param statement the new statement to add. * @return this batch statement. * @throws IllegalStateException if adding the new statement means that this * {@code BatchStatement} has more than 65536 statements (since this is the maximum number * of statements for a BatchStatement allowed by the underlying protocol). * @throws IllegalArgumentException if adding a regular statement that uses named values. */ public BatchStatement add(Statement statement) { if (statement instanceof StatementWrapper) { statement = ((StatementWrapper) statement).getWrappedStatement(); } if ((statement instanceof RegularStatement) && ((RegularStatement) statement).usesNamedValues()) { throw new IllegalArgumentException("Batch statement cannot contain regular statements with named values (" + ((RegularStatement) statement).getQueryString() + ")"); } // We handle BatchStatement here (rather than in getIdAndValues) as it make it slightly // easier to avoid endless loops if the user mistakenly passes a batch that depends on this // object (or this directly). if (statement instanceof BatchStatement) { for (Statement subStatements : ((BatchStatement) statement).statements) { add(subStatements); } } else { if (statements.size() >= 0xFFFF) throw new IllegalStateException("Batch statement cannot contain more than " + 0xFFFF + " statements."); statements.add(statement); } return this; } /** * Adds multiple statements to this batch. *

* This is a shortcut method that calls {@link #add} on all the statements * from {@code statements}. * * @param statements the statements to add. * @return this batch statement. */ public BatchStatement addAll(Iterable statements) { for (Statement statement : statements) add(statement); return this; } /** * The statements that have been added to this batch so far. * * @return an (immutable) collection of the statements that have been added * to this batch so far. */ public Collection getStatements() { return ImmutableList.copyOf(statements); } /** * Clears this batch, removing all statements added so far. * * @return this (now empty) {@code BatchStatement}. */ public BatchStatement clear() { statements.clear(); return this; } /** * Returns the number of elements in this batch. * * @return the number of elements in this batch. */ public int size() { return statements.size(); } /** * Sets the serial consistency level for the query. *

* This is only supported with version 3 or higher of the native protocol. If you call * this method when version 2 is in use, you will get an {@link UnsupportedFeatureException} * when submitting the statement. With version 2, protocol batches with conditions * have their serial consistency level hardcoded to SERIAL; if you need to execute a batch * with LOCAL_SERIAL, you will have to use a CQL batch. * * @param serialConsistency the serial consistency level to set. * @return this {@code Statement} object. * @throws IllegalArgumentException if {@code serialConsistency} is not one of * {@code ConsistencyLevel.SERIAL} or {@code ConsistencyLevel.LOCAL_SERIAL}. * @see Statement#setSerialConsistencyLevel(ConsistencyLevel) */ @Override public BatchStatement setSerialConsistencyLevel(ConsistencyLevel serialConsistency) { return (BatchStatement) super.setSerialConsistencyLevel(serialConsistency); } @Override public ByteBuffer getRoutingKey(ProtocolVersion protocolVersion, CodecRegistry codecRegistry) { for (Statement statement : statements) { if (statement instanceof StatementWrapper) statement = ((StatementWrapper) statement).getWrappedStatement(); ByteBuffer rk = statement.getRoutingKey(protocolVersion, codecRegistry); if (rk != null) return rk; } return null; } @Override public String getKeyspace() { for (Statement statement : statements) { String keyspace = statement.getKeyspace(); if (keyspace != null) return keyspace; } return null; } @Override public Boolean isIdempotent() { if (idempotent != null) { return idempotent; } return isBatchIdempotent(statements); } void ensureAllSet() { for (Statement statement : statements) if (statement instanceof BoundStatement) ((BoundStatement) statement).ensureAllSet(); } static class IdAndValues { public final List ids; public final List> values; IdAndValues(int nbstatements) { ids = new ArrayList(nbstatements); values = new ArrayList>(nbstatements); } } }