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

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

Go to download

A driver for Apache Cassandra 1.2+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's binary protocol.

The newest version!
/*
 *      Copyright (C) 2012 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 java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.*;

import com.datastax.driver.core.exceptions.InvalidTypeException;

/**
 * A prepared statement with values bound to the bind variables.
 * 

* Once values has been provided for the variables of the {@link PreparedStatement} * it has been created from, such BoundStatement can be executed (through * {@link Session#execute(Statement)}). *

* The values of a BoundStatement can be set by either index or name. When * setting them by name, names follow the case insensitivity rules explained in * {@link ColumnDefinitions} but with the difference that if multiple bind * variables have the same name, setting that name will set all the * variables for that name. *

* Any variable that hasn't been specifically set will be considered {@code null}. */ public class BoundStatement extends Statement { final PreparedStatement statement; final ByteBuffer[] values; /** * Creates a new {@code BoundStatement} from the provided prepared * statement. * @param statement the prepared statement from which to create a {@code BoundStatement}. */ public BoundStatement(PreparedStatement statement) { this.statement = statement; this.values = new ByteBuffer[statement.getVariables().size()]; if (statement.getConsistencyLevel() != null) this.setConsistencyLevel(statement.getConsistencyLevel()); if (statement.getSerialConsistencyLevel() != null) this.setSerialConsistencyLevel(statement.getSerialConsistencyLevel()); if (statement.isTracing()) this.enableTracing(); if (statement.getRetryPolicy() != null) this.setRetryPolicy(statement.getRetryPolicy()); } /** * Returns the prepared statement on which this BoundStatement is based. * * @return the prepared statement on which this BoundStatement is based. */ public PreparedStatement preparedStatement() { return statement; } /** * Returns whether the {@code i}th variable has been bound to a non null value. * * @param i the index of the variable to check. * @return whether the {@code i}th variable has been bound to a non null value. * * @throws IndexOutOfBoundsException if {@code i < 0 || i >= this.preparedStatement().variables().size()}. */ public boolean isSet(int i) { metadata().checkBounds(i); return values[i] != null; } /** * Returns whether the first occurrence of variable {@code name} has been * bound to a non-null value. * * @param name the name of the variable to check. * @return whether the first occurrence of variable {@code name} has been * bound to a non-null value. * * @throws IllegalArgumentException if {@code name} is not a prepared * variable, that is if {@code !this.preparedStatement().variables().names().contains(name)}. */ public boolean isSet(String name) { return isSet(metadata().getFirstIdx(name)); } /** * Bound values to the variables of this statement. * * This is a convenience method to bind all the variables of the * {@code BoundStatement} in one call. * * @param values the values to bind to the variables of the newly created * BoundStatement. The first element of {@code values} will be bound to the * first bind variable, etc. It is legal to provide fewer values than the * statement has bound variables. In that case, the remaining variable need * to be bound before execution. If more values than variables are provided * however, an IllegalArgumentException wil be raised. * @return this bound statement. * * @throws IllegalArgumentException if more {@code values} are provided * than there is of bound variables in this statement. * @throws InvalidTypeException if any of the provided value is not of * correct type to be bound to the corresponding bind variable. * @throws NullPointerException if one of {@code values} is a collection * (List, Set or Map) containing a null value. Nulls are not supported in * collections by CQL. */ public BoundStatement bind(Object... values) { if (values.length > statement.getVariables().size()) throw new IllegalArgumentException(String.format("Prepared statement has only %d variables, %d values provided", statement.getVariables().size(), values.length)); for (int i = 0; i < values.length; i++) { Object toSet = values[i]; if (toSet == null) { setValue(i, null); continue; } DataType columnType = statement.getVariables().getType(i); switch (columnType.getName()) { case LIST: if (!(toSet instanceof List)) throw new InvalidTypeException(String.format("Invalid type for value %d, column is a list but %s provided", i, toSet.getClass())); List l = (List)toSet; // If the list is empty, it will never fail validation, but otherwise we should check the list given if of the right type if (!l.isEmpty()) { // Ugly? Yes Class providedClass = l.get(0).getClass(); Class expectedClass = columnType.getTypeArguments().get(0).asJavaClass(); if (!expectedClass.isAssignableFrom(providedClass)) throw new InvalidTypeException(String.format("Invalid type for value %d of CQL type %s, expecting list of %s but provided list of %s", i, columnType, expectedClass, providedClass)); } break; case SET: if (!(toSet instanceof Set)) throw new InvalidTypeException(String.format("Invalid type for value %d, column is a set but %s provided", i, toSet.getClass())); Set s = (Set)toSet; // If the list is empty, it will never fail validation, but otherwise we should check the list given if of the right type if (!s.isEmpty()) { // Ugly? Yes Class providedClass = s.iterator().next().getClass(); Class expectedClass = columnType.getTypeArguments().get(0).getName().javaType; if (!expectedClass.isAssignableFrom(providedClass)) throw new InvalidTypeException(String.format("Invalid type for value %d of CQL type %s, expecting set of %s but provided set of %s", i, columnType, expectedClass, providedClass)); } break; case MAP: if (!(toSet instanceof Map)) throw new InvalidTypeException(String.format("Invalid type for value %d, column is a map but %s provided", i, toSet.getClass())); Map m = (Map)toSet; // If the list is empty, it will never fail validation, but otherwise we should check the list given if of the right type if (!m.isEmpty()) { // Ugly? Yes Map.Entry entry = m.entrySet().iterator().next(); Class providedKeysClass = entry.getKey().getClass(); Class providedValuesClass = entry.getValue().getClass(); Class expectedKeysClass = columnType.getTypeArguments().get(0).getName().javaType; Class expectedValuesClass = columnType.getTypeArguments().get(1).getName().javaType; if (!expectedKeysClass.isAssignableFrom(providedKeysClass) || !expectedValuesClass.isAssignableFrom(providedValuesClass)) throw new InvalidTypeException(String.format("Invalid type for value %d of CQL type %s, expecting map of %s->%s but provided set of %s->%s", i, columnType, expectedKeysClass, expectedValuesClass, providedKeysClass, providedValuesClass)); } break; default: Class providedClass = toSet.getClass(); Class expectedClass = columnType.getName().javaType; if (!expectedClass.isAssignableFrom(providedClass)) throw new InvalidTypeException(String.format("Invalid type for value %d of CQL type %s, expecting %s but %s provided", i, columnType, expectedClass, providedClass)); break; } setValue(i, columnType.codec().serialize(toSet)); } return this; } /** * The routing key for this bound query. *

* This method will return a non-{@code null} value if either of the following occur: *

    *
  • All the columns composing the partition key are bound * variables of this {@code BoundStatement}. The routing key will then be * built using the values provided for these partition key columns.
  • *
  • The routing key has been set through {@link PreparedStatement#setRoutingKey} * for the {@code PreparedStatement} this statement has been built from.
  • *
* Otherwise, {@code null} is returned. *

* Note that if the routing key has been set through {@link PreparedStatement#setRoutingKey}, * that latter value takes precedence even if the partition key is part of the bound variables. * * @return the routing key for this statement or {@code null}. */ @Override public ByteBuffer getRoutingKey() { if (statement.getRoutingKey() != null) return statement.getRoutingKey(); int[] rkIndexes = statement.getPreparedId().routingKeyIndexes; if (rkIndexes != null) { if (rkIndexes.length == 1) { return values[rkIndexes[0]]; } else { ByteBuffer[] components = new ByteBuffer[rkIndexes.length]; for (int i = 0; i < components.length; ++i) { ByteBuffer value = values[rkIndexes[i]]; if (value == null) return null; components[i] = value; } return SimpleStatement.compose(components); } } return null; } /** * Returns the keyspace this query operates on. *

* This method will always return a non-{@code null} value (unless the statement * has no variables, but you should avoid prepared statement in the first in that * case). The keyspace returned will be the one corresponding to the first * variable prepared in this statement (which in almost all case will be the * keyspace for the operation, though it's possible in CQL to build a batch * statement that acts on multiple keyspace). * * @return the keyspace for this statement (see above), or {@code null} if the * statement has no variables. */ @Override public String getKeyspace() { return statement.getPreparedId().metadata.size() == 0 ? null : statement.getPreparedId().metadata.getKeyspace(0); } /** * Sets the {@code i}th value to the provided boolean. * * @param i the index of the variable to set. * @param v the value to set. * @return this BoundStatement. * * @throws IndexOutOfBoundsException if {@code i < 0 || i >= this.preparedStatement().variables().size()}. * @throws InvalidTypeException if column {@code i} is not of type BOOLEAN. */ public BoundStatement setBool(int i, boolean v) { metadata().checkType(i, DataType.Name.BOOLEAN); return setValue(i, TypeCodec.BooleanCodec.instance.serializeNoBoxing(v)); } /** * Sets the value for (all occurrences of) variable {@code name} to the * provided boolean. * * @param name the name of the variable to set; if multiple variables * {@code name} are prepared, all of them are set. * @param v the value to set. * @return this BoundStatement. * * @throws IllegalArgumentException if {@code name} is not a prepared * variable, that is, if {@code !this.preparedStatement().variables().names().contains(name)}. * @throws InvalidTypeException if (any one occurrence of) {@code name} is not of type BOOLEAN. */ public BoundStatement setBool(String name, boolean v) { int[] indexes = metadata().getAllIdx(name); ByteBuffer value = TypeCodec.BooleanCodec.instance.serializeNoBoxing(v); for (int i = 0; i < indexes.length; i++) { metadata().checkType(indexes[i], DataType.Name.BOOLEAN); setValue(indexes[i], value); } return this; } /** * Set the {@code i}th value to the provided integer. * * @param i the index of the variable to set. * @param v the value to set. * @return this BoundStatement. * * @throws IndexOutOfBoundsException if {@code i < 0 || i >= this.preparedStatement().variables().size()}. * @throws InvalidTypeException if column {@code i} is not of type INT. */ public BoundStatement setInt(int i, int v) { metadata().checkType(i, DataType.Name.INT); return setValue(i, TypeCodec.IntCodec.instance.serializeNoBoxing(v)); } /** * Sets the value for (all occurrences of) variable {@code name} to the * provided integer. * * @param name the name of the variable to set; if multiple variables * {@code name} are prepared, all of them are set. * @param v the value to set. * @return this BoundStatement. * * @throws IllegalArgumentException if {@code name} is not a prepared * variable, that is, if {@code !this.preparedStatement().variables().names().contains(name)}. * @throws InvalidTypeException if (any one occurrence of) {@code name} is not of type INT. */ public BoundStatement setInt(String name, int v) { int[] indexes = metadata().getAllIdx(name); ByteBuffer value = TypeCodec.IntCodec.instance.serializeNoBoxing(v); for (int i = 0; i < indexes.length; i++) { metadata().checkType(indexes[i], DataType.Name.INT); setValue(indexes[i], value); } return this; } /** * Sets the {@code i}th value to the provided long. * * @param i the index of the variable to set. * @param v the value to set. * @return this BoundStatement. * * @throws IndexOutOfBoundsException if {@code i < 0 || i >= this.preparedStatement().variables().size()}. * @throws InvalidTypeException if column {@code i} is not of type BIGINT or COUNTER. */ public BoundStatement setLong(int i, long v) { metadata().checkType(i, DataType.Name.BIGINT, DataType.Name.COUNTER); return setValue(i, TypeCodec.LongCodec.instance.serializeNoBoxing(v)); } /** * Sets the value for (all occurrences of) variable {@code name} to the * provided long. * * @param name the name of the variable to set; if multiple variables * {@code name} are prepared, all of them are set. * @param v the value to set. * @return this BoundStatement. * * @throws IllegalArgumentException if {@code name} is not a prepared * variable, that is, if {@code !this.preparedStatement().variables().names().contains(name)}. * @throws InvalidTypeException if (any occurrence of) {@code name} is * not of type BIGINT or COUNTER. */ public BoundStatement setLong(String name, long v) { int[] indexes = metadata().getAllIdx(name); ByteBuffer value = TypeCodec.LongCodec.instance.serializeNoBoxing(v); for (int i = 0; i < indexes.length; i++) { metadata().checkType(indexes[i], DataType.Name.BIGINT, DataType.Name.COUNTER); setValue(indexes[i], value); } return this; } /** * Set the {@code i}th value to the provided date. * * @param i the index of the variable to set. * @param v the value to set. * @return this BoundStatement. * * @throws IndexOutOfBoundsException if {@code i < 0 || i >= this.preparedStatement().variables().size()}. * @throws InvalidTypeException if column {@code i} is not of type TIMESTAMP. */ public BoundStatement setDate(int i, Date v) { metadata().checkType(i, DataType.Name.TIMESTAMP); return setValue(i, v == null ? null : TypeCodec.DateCodec.instance.serialize(v)); } /** * Sets the value for (all occurrences of) variable {@code name} to the * provided date. * * @param name the name of the variable to set; if multiple variables * {@code name} are prepared, all of them are set. * @param v the value to set. * @return this BoundStatement. * * @throws IllegalArgumentException if {@code name} is not a prepared * variable, that is, if {@code !this.preparedStatement().variables().names().contains(name)}. * @throws InvalidTypeException if (any occurrence of) {@code name} is * not of type TIMESTAMP. */ public BoundStatement setDate(String name, Date v) { int[] indexes = metadata().getAllIdx(name); ByteBuffer value = v == null ? null : TypeCodec.DateCodec.instance.serialize(v); for (int i = 0; i < indexes.length; i++) { metadata().checkType(indexes[i], DataType.Name.TIMESTAMP); setValue(indexes[i], value); } return this; } /** * Sets the {@code i}th value to the provided float. * * @param i the index of the variable to set. * @param v the value to set. * @return this BoundStatement. * * @throws IndexOutOfBoundsException if {@code i < 0 || i >= this.preparedStatement().variables().size()}. * @throws InvalidTypeException if column {@code i} is not of type FLOAT. */ public BoundStatement setFloat(int i, float v) { metadata().checkType(i, DataType.Name.FLOAT); return setValue(i, TypeCodec.FloatCodec.instance.serializeNoBoxing(v)); } /** * Sets the value for (all occurrences of) variable {@code name} to the * provided float. * * @param name the name of the variable to set; if multiple variables * {@code name} are prepared, all of them are set. * @param v the value to set. * @return this BoundStatement. * * @throws IllegalArgumentException if {@code name} is not a prepared * variable, that is, if {@code !this.preparedStatement().variables().names().contains(name)}. * @throws InvalidTypeException if (any occurrence of) {@code name} is * not of type FLOAT. */ public BoundStatement setFloat(String name, float v) { int[] indexes = metadata().getAllIdx(name); ByteBuffer value = TypeCodec.FloatCodec.instance.serializeNoBoxing(v); for (int i = 0; i < indexes.length; i++) { metadata().checkType(indexes[i], DataType.Name.FLOAT); setValue(indexes[i], value); } return this; } /** * Sets the {@code i}th value to the provided double. * * @param i the index of the variable to set. * @param v the value to set. * @return this BoundStatement. * * @throws IndexOutOfBoundsException if {@code i < 0 || i >= this.preparedStatement().variables().size()}. * @throws InvalidTypeException if column {@code i} is not of type DOUBLE. */ public BoundStatement setDouble(int i, double v) { metadata().checkType(i, DataType.Name.DOUBLE); return setValue(i, TypeCodec.DoubleCodec.instance.serializeNoBoxing(v)); } /** * Sets the value for (all occurrences of) variable {@code name} to the * provided double. * * @param name the name of the variable to set; if multiple variables * {@code name} are prepared, all of them are set. * @param v the value to set. * @return this BoundStatement. * * @throws IllegalArgumentException if {@code name} is not a prepared * variable, that is, if {@code !this.preparedStatement().variables().names().contains(name)}. * @throws InvalidTypeException if (any occurrence of) {@code name} is * not of type DOUBLE. */ public BoundStatement setDouble(String name, double v) { int[] indexes = metadata().getAllIdx(name); ByteBuffer value = TypeCodec.DoubleCodec.instance.serializeNoBoxing(v); for (int i = 0; i < indexes.length; i++) { metadata().checkType(indexes[i], DataType.Name.DOUBLE); setValue(indexes[i], value); } return this; } /** * Sets the {@code i}th value to the provided string. * * @param i the index of the variable to set. * @param v the value to set. * @return this BoundStatement. * * @throws IndexOutOfBoundsException if {@code i < 0 || i >= this.preparedStatement().variables().size()}. * @throws InvalidTypeException if column {@code i} is of neither of the * following types: VARCHAR, TEXT or ASCII. */ public BoundStatement setString(int i, String v) { DataType.Name type = metadata().checkType(i, DataType.Name.VARCHAR, DataType.Name.TEXT, DataType.Name.ASCII); switch (type) { case ASCII: return setValue(i, v == null ? null : TypeCodec.StringCodec.asciiInstance.serialize(v)); case TEXT: case VARCHAR: return setValue(i, v == null ? null : TypeCodec.StringCodec.utf8Instance.serialize(v)); default: throw new AssertionError(); } } /** * Sets the value for (all occurrences of) variable {@code name} to the * provided string. * * @param name the name of the variable to set; if multiple variables * {@code name} are prepared, all of them are set. * @param v the value to set. * @return this BoundStatement. * * @throws IllegalArgumentException if {@code name} is not a prepared * variable, that is, if {@code !this.preparedStatement().variables().names().contains(name)}. * @throws InvalidTypeException if (any occurrence of) {@code name} is * of neither of the following types: VARCHAR, TEXT or ASCII. */ public BoundStatement setString(String name, String v) { int[] indexes = metadata().getAllIdx(name); for (int i = 0; i < indexes.length; i++) setString(indexes[i], v); return this; } /** * Sets the {@code i}th value to the provided byte buffer. * * This method validate that the type of the column set is BLOB. If you * want to insert manually serialized data into columns of another type, * use {@link #setBytesUnsafe} instead. * * @param i the index of the variable to set. * @param v the value to set. * @return this BoundStatement. * * @throws IndexOutOfBoundsException if {@code i < 0 || i >= this.preparedStatement().variables().size()}. * @throws InvalidTypeException if column {@code i} is not of type BLOB. */ public BoundStatement setBytes(int i, ByteBuffer v) { metadata().checkType(i, DataType.Name.BLOB); return setBytesUnsafe(i, v); } /** * Sets the value for (all occurrences of) variable {@code name} to the * provided byte buffer. * * This method validate that the type of the column set is BLOB. If you * want to insert manually serialized data into columns of another type, * use {@link #setBytesUnsafe} instead. * * @param name the name of the variable to set; if multiple variables * {@code name} are prepared, all of them are set. * @param v the value to set. * @return this BoundStatement. * * @throws IllegalArgumentException if {@code name} is not a prepared * variable, that is if {@code !this.preparedStatement().variables().names().contains(name)}. * @throws InvalidTypeException if (any occurrence of) {@code name} is not of type BLOB. */ public BoundStatement setBytes(String name, ByteBuffer v) { int[] indexes = metadata().getAllIdx(name); ByteBuffer value = v == null ? null : v.duplicate(); for (int i = 0; i < indexes.length; i++) { metadata().checkType(indexes[i], DataType.Name.BLOB); setValue(indexes[i], value); } return this; } /** * Sets the {@code i}th value to the provided byte buffer. * * Contrary to {@link #setBytes}, this method does not check the * type of the column set. If you insert data that is not compatible with * the type of the column, you will get an {@code InvalidQueryException} at * execute time. * * @param i the index of the variable to set. * @param v the value to set. * @return this BoundStatement. * * @throws IndexOutOfBoundsException if {@code i < 0 || i >= this.preparedStatement().variables().size()}. */ public BoundStatement setBytesUnsafe(int i, ByteBuffer v) { return setValue(i, v == null ? null : v.duplicate()); } /** * Sets the value for (all occurrences of) variable {@code name} to the * provided byte buffer. * * Contrary to {@link #setBytes}, this method does not check the * type of the column set. If you insert data that is not compatible with * the type of the column, you will get an {@code InvalidQueryException} at * execute time. * * @param name the name of the variable to set; if multiple variables * {@code name} are prepared, all of them are set. * @param v the value to set. * @return this BoundStatement. * * @throws IllegalArgumentException if {@code name} is not a prepared * variable, that is if {@code !this.preparedStatement().variables().names().contains(name)}. */ public BoundStatement setBytesUnsafe(String name, ByteBuffer v) { int[] indexes = metadata().getAllIdx(name); ByteBuffer value = v == null ? null : v.duplicate(); for (int i = 0; i < indexes.length; i++) setValue(indexes[i], value); return this; } /** * Sets the {@code i}th value to the provided big integer. * * @param i the index of the variable to set. * @param v the value to set. * @return this BoundStatement. * * @throws IndexOutOfBoundsException if {@code i < 0 || i >= this.preparedStatement().variables().size()}. * @throws InvalidTypeException if column {@code i} is not of type VARINT. */ public BoundStatement setVarint(int i, BigInteger v) { metadata().checkType(i, DataType.Name.VARINT); return setValue(i, v == null ? null : TypeCodec.BigIntegerCodec.instance.serialize(v)); } /** * Sets the value for (all occurrences of) variable {@code name} to the * provided big integer. * * @param name the name of the variable to set; if multiple variables * {@code name} are prepared, all of them are set. * @param v the value to set. * @return this BoundStatement. * * @throws IllegalArgumentException if {@code name} is not a prepared * variable, that is, if {@code !this.preparedStatement().variables().names().contains(name)}. * @throws InvalidTypeException if (any occurrence of) {@code name} is * not of type VARINT. */ public BoundStatement setVarint(String name, BigInteger v) { int[] indexes = metadata().getAllIdx(name); ByteBuffer value = v == null ? null : TypeCodec.BigIntegerCodec.instance.serialize(v); for (int i = 0; i < indexes.length; i++) { metadata().checkType(indexes[i], DataType.Name.VARINT); setValue(indexes[i], value); } return this; } /** * Sets the {@code i}th value to the provided big decimal. * * @param i the index of the variable to set. * @param v the value to set. * @return this BoundStatement. * * @throws IndexOutOfBoundsException if {@code i < 0 || i >= this.preparedStatement().variables().size()}. * @throws InvalidTypeException if column {@code i} is not of type DECIMAL. */ public BoundStatement setDecimal(int i, BigDecimal v) { metadata().checkType(i, DataType.Name.DECIMAL); return setValue(i, v == null ? null : TypeCodec.DecimalCodec.instance.serialize(v)); } /** * Sets the value for (all occurrences of) variable {@code name} to the * provided big decimal. * * @param name the name of the variable to set; if multiple variables * {@code name} are prepared, all of them are set. * @param v the value to set. * @return this BoundStatement. * * @throws IllegalArgumentException if {@code name} is not a prepared * variable, that is, if {@code !this.preparedStatement().variables().names().contains(name)}. * @throws InvalidTypeException if (any occurrence of) {@code name} is * not of type DECIMAL. */ public BoundStatement setDecimal(String name, BigDecimal v) { int[] indexes = metadata().getAllIdx(name); ByteBuffer value = v == null ? null : TypeCodec.DecimalCodec.instance.serialize(v); for (int i = 0; i < indexes.length; i++) { metadata().checkType(indexes[i], DataType.Name.DECIMAL); setValue(indexes[i], value); } return this; } /** * Sets the {@code i}th value to the provided UUID. * * @param i the index of the variable to set. * @param v the value to set. * @return this BoundStatement. * * @throws IndexOutOfBoundsException if {@code i < 0 || i >= this.preparedStatement().variables().size()}. * @throws InvalidTypeException if column {@code i} is not of type UUID or * TIMEUUID, or if column {@code i} is of type TIMEUUID but {@code v} is * not a type 1 UUID. */ public BoundStatement setUUID(int i, UUID v) { DataType.Name type = metadata().checkType(i, DataType.Name.UUID, DataType.Name.TIMEUUID); if (v == null) return setValue(i, null); if (type == DataType.Name.TIMEUUID && v.version() != 1) throw new InvalidTypeException(String.format("%s is not a Type 1 (time-based) UUID", v)); return type == DataType.Name.UUID ? setValue(i, TypeCodec.UUIDCodec.instance.serialize(v)) : setValue(i, TypeCodec.TimeUUIDCodec.instance.serialize(v)); } /** * Sets the value for (all occurrences of) variable {@code name} to the * provided UUID. * * @param name the name of the variable to set; if multiple variables * {@code name} are prepared, all of them are set. * @param v the value to set. * @return this BoundStatement. * * @throws IllegalArgumentException if {@code name} is not a prepared * variable, that is, if {@code !this.preparedStatement().variables().names().contains(name)}. * @throws InvalidTypeException if (any occurrence of) {@code name} is * not of type UUID or TIMEUUID, or if column {@code name} is of type * TIMEUUID but {@code v} is not a type 1 UUID. */ public BoundStatement setUUID(String name, UUID v) { int[] indexes = metadata().getAllIdx(name); ByteBuffer value = v == null ? null : TypeCodec.UUIDCodec.instance.serialize(v); for (int i = 0; i < indexes.length; i++) { DataType.Name type = metadata().checkType(indexes[i], DataType.Name.UUID, DataType.Name.TIMEUUID); if (v != null && type == DataType.Name.TIMEUUID && v.version() != 1) throw new InvalidTypeException(String.format("%s is not a Type 1 (time-based) UUID", v)); setValue(indexes[i], value); } return this; } /** * Sets the {@code i}th value to the provided inet address. * * @param i the index of the variable to set. * @param v the value to set. * @return this BoundStatement. * * @throws IndexOutOfBoundsException if {@code i < 0 || i >= this.preparedStatement().variables().size()}. * @throws InvalidTypeException if column {@code i} is not of type INET. */ public BoundStatement setInet(int i, InetAddress v) { metadata().checkType(i, DataType.Name.INET); return setValue(i, v == null ? null : TypeCodec.InetCodec.instance.serialize(v)); } /** * Sets the value for (all occurrences of) variable {@code name} to the * provided inet address. * * @param name the name of the variable to set; if multiple variables * {@code name} are prepared, all of them are set. * @param v the value to set. * @return this BoundStatement. * * @throws IllegalArgumentException if {@code name} is not a prepared * variable, that is, if {@code !this.preparedStatement().variables().names().contains(name)}. * @throws InvalidTypeException if (any occurrence of) {@code name} is * not of type INET. */ public BoundStatement setInet(String name, InetAddress v) { int[] indexes = metadata().getAllIdx(name); ByteBuffer value = v == null ? null : TypeCodec.InetCodec.instance.serialize(v); for (int i = 0; i < indexes.length; i++) { metadata().checkType(indexes[i], DataType.Name.INET); setValue(indexes[i], value); } return this; } /** * Sets the {@code i}th value to the provided list. *

* Please note that {@code null} values are not supported inside collection by CQL. * * @param the type of the elements of the list to set. * @param i the index of the variable to set. * @param v the value to set. * @return this BoundStatement. * * @throws IndexOutOfBoundsException if {@code i < 0 || i >= this.preparedStatement().variables().size()}. * @throws InvalidTypeException if column {@code i} is not a list type or * if the elements of {@code v} are not of the type of the elements of * column {@code i}. * @throws NullPointerException if {@code v} contains null values. Nulls are not supported in collections * by CQL. */ public BoundStatement setList(int i, List v) { DataType type = metadata().getType(i); if (type.getName() != DataType.Name.LIST) throw new InvalidTypeException(String.format("Column %s is of type %s, cannot set to a list", metadata().getName(i), type)); if (v == null) return setValue(i, null); // If the list is empty, it will never fail validation, but otherwise we should check the list given if of the right type if (!v.isEmpty()) { // Ugly? Yes Class providedClass = v.get(0).getClass(); Class expectedClass = type.getTypeArguments().get(0).asJavaClass(); if (!expectedClass.isAssignableFrom(providedClass)) throw new InvalidTypeException(String.format("Invalid value for column %s of CQL type %s, expecting list of %s but provided list of %s", metadata().getName(i), type, expectedClass, providedClass)); } return setValue(i, type.codec().serialize(v)); } /** * Sets the value for (all occurrences of) variable {@code name} to the * provided list. *

* Please note that {@code null} values are not supported inside collection by CQL. * * @param the type of the elements of the list to set. * @param name the name of the variable to set; if multiple variables * {@code name} are prepared, all of them are set. * @param v the value to set. * @return this BoundStatement. * * @throws IllegalArgumentException if {@code name} is not a prepared * variable, that is, if {@code !this.preparedStatement().variables().names().contains(name)}. * @throws InvalidTypeException if (any occurrence of) {@code name} is * not a list type or if the elements of {@code v} are not of the type of * the elements of column {@code name}. * @throws NullPointerException if {@code v} contains null values. Nulls are not supported in collections * by CQL. */ public BoundStatement setList(String name, List v) { int[] indexes = metadata().getAllIdx(name); for (int i = 0; i < indexes.length; i++) setList(indexes[i], v); return this; } /** * Sets the {@code i}th value to the provided map. *

* Please note that {@code null} values are not supported inside collection by CQL. * * @param the type of the keys for the map to set. * @param the type of the values for the map to set. * @param i the index of the variable to set. * @param v the value to set. * @return this BoundStatement. * * @throws IndexOutOfBoundsException if {@code i < 0 || i >= this.preparedStatement().variables().size()}. * @throws InvalidTypeException if column {@code i} is not a map type or * if the elements (keys or values) of {@code v} are not of the type of the * elements of column {@code i}. * @throws NullPointerException if {@code v} contains null values. Nulls are not supported in collections * by CQL. */ public BoundStatement setMap(int i, Map v) { DataType type = metadata().getType(i); if (type.getName() != DataType.Name.MAP) throw new InvalidTypeException(String.format("Column %s is of type %s, cannot set to a map", metadata().getName(i), type)); if (v == null) return setValue(i, null); if (!v.isEmpty()) { // Ugly? Yes Map.Entry entry = v.entrySet().iterator().next(); Class providedKeysClass = entry.getKey().getClass(); Class providedValuesClass = entry.getValue().getClass(); Class expectedKeysClass = type.getTypeArguments().get(0).getName().javaType; Class expectedValuesClass = type.getTypeArguments().get(1).getName().javaType; if (!expectedKeysClass.isAssignableFrom(providedKeysClass) || !expectedValuesClass.isAssignableFrom(providedValuesClass)) throw new InvalidTypeException(String.format("Invalid value for column %s of CQL type %s, expecting map of %s->%s but provided map of %s->%s", metadata().getName(i), type, expectedKeysClass, expectedValuesClass, providedKeysClass, providedValuesClass)); } return setValue(i, type.codec().serialize(v)); } /** * Sets the value for (all occurrences of) variable {@code name} to the * provided map. *

* Please note that {@code null} values are not supported inside collection by CQL. * * @param the type of the keys for the map to set. * @param the type of the values for the map to set. * @param name the name of the variable to set; if multiple variables * {@code name} are prepared, all of them are set. * @param v the value to set. * @return this BoundStatement. * * @throws IllegalArgumentException if {@code name} is not a prepared * variable, that is, if {@code !this.preparedStatement().variables().names().contains(name)}. * @throws InvalidTypeException if (any occurrence of) {@code name} is * not a map type or if the elements (keys or values) of {@code v} are not of * the type of the elements of column {@code name}. * @throws NullPointerException if {@code v} contains null values. Nulls are not supported in collections * by CQL. */ public BoundStatement setMap(String name, Map v) { int[] indexes = metadata().getAllIdx(name); for (int i = 0; i < indexes.length; i++) setMap(indexes[i], v); return this; } /** * Sets the {@code i}th value to the provided set. *

* Please note that {@code null} values are not supported inside collection by CQL. * * @param the type of the elements of the set to set. * @param i the index of the variable to set. * @param v the value to set. * @return this BoundStatement. * * @throws IndexOutOfBoundsException if {@code i < 0 || i >= this.preparedStatement().variables().size()}. * @throws InvalidTypeException if column {@code i} is not a set type or * if the elements of {@code v} are not of the type of the elements of * column {@code i}. * @throws NullPointerException if {@code v} contains null values. Nulls are not supported in collections * by CQL. */ public BoundStatement setSet(int i, Set v) { DataType type = metadata().getType(i); if (type.getName() != DataType.Name.SET) throw new InvalidTypeException(String.format("Column %s is of type %s, cannot set to a set", metadata().getName(i), type)); if (v == null) return setValue(i, null); if (!v.isEmpty()) { // Ugly? Yes Class providedClass = v.iterator().next().getClass(); Class expectedClass = type.getTypeArguments().get(0).getName().javaType; if (!expectedClass.isAssignableFrom(providedClass)) throw new InvalidTypeException(String.format("Invalid value for column %s of CQL type %s, expecting set of %s but provided set of %s", metadata().getName(i), type, expectedClass, providedClass)); } return setValue(i, type.codec().serialize(v)); } /** * Sets the value for (all occurrences of) variable {@code name} to the * provided set. *

* Please note that {@code null} values are not supported inside collection by CQL. * * @param the type of the elements of the set to set. * @param name the name of the variable to set; if multiple variables * {@code name} are prepared, all of them are set. * @param v the value to set. * @return this BoundStatement. * * @throws IllegalArgumentException if {@code name} is not a prepared * variable, that is, if {@code !this.preparedStatement().variables().names().contains(name)}. * @throws InvalidTypeException if (any occurrence of) {@code name} is * not a map type or if the elements of {@code v} are not of the type of * the elements of column {@code name}. * @throws NullPointerException if {@code v} contains null values. Nulls are not supported in collections * by CQL. */ public BoundStatement setSet(String name, Set v) { int[] indexes = metadata().getAllIdx(name); for (int i = 0; i < indexes.length; i++) setSet(indexes[i], v); return this; } private ColumnDefinitions metadata() { return statement.getVariables(); } private BoundStatement setValue(int i, ByteBuffer value) { values[i] = value; return this; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy