/*
 * Copyright 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.oss.driver.api.core.cql;

import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.DefaultProtocolVersion;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.nio.ByteBuffer;
import java.util.List;

A query with bind variables that has been pre-parsed by the database.

Client applications create instances with CqlSession.prepare(SimpleStatement). Then they use bind(Object...) to obtain an executable BoundStatement.

The default prepared statement implementation returned by the driver is thread-safe. Client applications can -- and are expected to -- prepare each query once and store the result in a place where it can be accessed concurrently by application threads (for example a final field). Preparing the same query string twice is suboptimal and a bad practice, and will cause the driver to log a warning.

/** * A query with bind variables that has been pre-parsed by the database. * * <p>Client applications create instances with {@link CqlSession#prepare(SimpleStatement)}. Then * they use {@link #bind(Object...)} to obtain an executable {@link BoundStatement}. * * <p>The default prepared statement implementation returned by the driver is <b>thread-safe</b>. * Client applications can -- and are expected to -- prepare each query once and store the result in * a place where it can be accessed concurrently by application threads (for example a final field). * Preparing the same query string twice is suboptimal and a bad practice, and will cause the driver * to log a warning. */
public interface PreparedStatement {
A unique identifier for this prepared statement.

Note: the returned buffer is read-only.

/** * A unique identifier for this prepared statement. * * <p>Note: the returned buffer is read-only. */
@NonNull ByteBuffer getId(); @NonNull String getQuery();
A description of the bind variables of this prepared statement.
/** A description of the bind variables of this prepared statement. */
@NonNull ColumnDefinitions getVariableDefinitions();
The indices of the variables in getVariableDefinitions() that correspond to the target table's partition key.

This is only present if all the partition key columns are expressed as bind variables. Otherwise, the list will be empty. For example, given the following schema:

  CREATE TABLE foo (pk1 int, pk2 int, cc int, v int, PRIMARY KEY ((pk1, pk2), cc));
And the following definitions:
PreparedStatement ps1 = session.prepare("UPDATE foo SET v = ? WHERE pk1 = ? AND pk2 = ? AND v = ?");
PreparedStatement ps2 = session.prepare("UPDATE foo SET v = ? WHERE pk1 = 1 AND pk2 = ? AND v = ?");
Then ps1.getPartitionKeyIndices() contains 1 and 2, and ps2.getPartitionKeyIndices() is empty (because one of the partition key components is hard-coded in the query string).
/** * The indices of the variables in {@link #getVariableDefinitions()} that correspond to the target * table's partition key. * * <p>This is only present if all the partition key columns are expressed as bind variables. * Otherwise, the list will be empty. For example, given the following schema: * * <pre> * CREATE TABLE foo (pk1 int, pk2 int, cc int, v int, PRIMARY KEY ((pk1, pk2), cc)); * </pre> * * And the following definitions: * * <pre> * PreparedStatement ps1 = session.prepare("UPDATE foo SET v = ? WHERE pk1 = ? AND pk2 = ? AND v = ?"); * PreparedStatement ps2 = session.prepare("UPDATE foo SET v = ? WHERE pk1 = 1 AND pk2 = ? AND v = ?"); * </pre> * * Then {@code ps1.getPartitionKeyIndices()} contains 1 and 2, and {@code * ps2.getPartitionKeyIndices()} is empty (because one of the partition key components is * hard-coded in the query string). */
@NonNull List<Integer> getPartitionKeyIndices();
A unique identifier for result metadata (essentially a hash of getResultSetDefinitions()).

This information is mostly for internal use: with protocol DefaultProtocolVersion.V5 or higher, the driver sends it with every execution of the prepared statement, to validate that its result metadata is still up-to-date.

Note: this method returns null for protocol DefaultProtocolVersion.V4 or lower; otherwise, the returned buffer is read-only.

See Also:
/** * A unique identifier for result metadata (essentially a hash of {@link * #getResultSetDefinitions()}). * * <p>This information is mostly for internal use: with protocol {@link DefaultProtocolVersion#V5} * or higher, the driver sends it with every execution of the prepared statement, to validate that * its result metadata is still up-to-date. * * <p>Note: this method returns {@code null} for protocol {@link DefaultProtocolVersion#V4} or * lower; otherwise, the returned buffer is read-only. * * @see <a href="https://issues.apache.org/jira/browse/CASSANDRA-10786">CASSANDRA-10786</a> */
@Nullable ByteBuffer getResultMetadataId();
A description of the result set that will be returned when this prepared statement is bound and executed.

This information is only present for SELECT queries, otherwise it is always empty. Note that this is slightly incorrect for conditional updates (e.g. INSERT ... IF NOT EXISTS), which do return columns; for those cases, use PagingIterable<Row>.getColumnDefinitions() on the result, not this method.

/** * A description of the result set that will be returned when this prepared statement is bound and * executed. * * <p>This information is only present for {@code SELECT} queries, otherwise it is always empty. * Note that this is slightly incorrect for conditional updates (e.g. {@code INSERT ... IF NOT * EXISTS}), which do return columns; for those cases, use {@link * ResultSet#getColumnDefinitions()} on the result, not this method. */
@NonNull ColumnDefinitions getResultSetDefinitions();
Updates getResultMetadataId() and getResultSetDefinitions() atomically.

This is for internal use by the driver. Calling this manually with incorrect information can cause existing queries to fail.

/** * Updates {@link #getResultMetadataId()} and {@link #getResultSetDefinitions()} atomically. * * <p>This is for internal use by the driver. Calling this manually with incorrect information can * cause existing queries to fail. */
void setResultMetadata( @NonNull ByteBuffer newResultMetadataId, @NonNull ColumnDefinitions newResultSetDefinitions);
Builds an executable statement that associates a set of values with the bind variables.

Note that the built-in bound statement implementation is immutable. If you need to set multiple execution parameters on the bound statement (such as Statement<BoundStatement>.setExecutionProfileName(String), Statement<BoundStatement>.setPagingState(ByteBuffer), etc.), consider using boundStatementBuilder(Object...) instead to avoid unnecessary allocations.

Params:
  • values – the values of the bound variables in the statement. You can provide less values than the actual number of variables (or even none at all), in which case the remaining variables will be left unset. However, this method will throw an IllegalArgumentException if there are more values than variables. Individual values can be null, but the vararg array itself can't.
/** * Builds an executable statement that associates a set of values with the bind variables. * * <p>Note that the built-in bound statement implementation is immutable. If you need to set * multiple execution parameters on the bound statement (such as {@link * BoundStatement#setExecutionProfileName(String)}, {@link * BoundStatement#setPagingState(ByteBuffer)}, etc.), consider using {@link * #boundStatementBuilder(Object...)} instead to avoid unnecessary allocations. * * @param values the values of the bound variables in the statement. You can provide less values * than the actual number of variables (or even none at all), in which case the remaining * variables will be left unset. However, this method will throw an {@link * IllegalArgumentException} if there are more values than variables. Individual values can be * {@code null}, but the vararg array itself can't. */
@NonNull BoundStatement bind(@NonNull Object... values);
Returns a builder to construct an executable statement.

Note that this builder is mutable and not thread-safe.

See Also:
  • bind(Object...)
/** * Returns a builder to construct an executable statement. * * <p>Note that this builder is mutable and not thread-safe. * * @see #bind(Object...) */
@NonNull BoundStatementBuilder boundStatementBuilder(@NonNull Object... values); }