Skip to content

Commit

Permalink
JAVA-1495: Add prepared statements
Browse files Browse the repository at this point in the history
  • Loading branch information
olim7t committed Jun 15, 2017
1 parent 02b9074 commit 9b5a45f
Show file tree
Hide file tree
Showing 19 changed files with 1,420 additions and 77 deletions.
7 changes: 7 additions & 0 deletions changelog/README.md
@@ -0,0 +1,7 @@
## Changelog

<!-- Note: contrary to 3.x, insert new entries *first* in their section -->

### 4.0.0-alpha1 (in progress)

- [new feature] JAVA-1495: Add prepared statements
@@ -0,0 +1,78 @@
/*
* Copyright (C) 2017-2017 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.config.DriverConfigProfile;
import com.datastax.oss.driver.api.core.data.GettableById;
import com.datastax.oss.driver.api.core.data.GettableByName;
import com.datastax.oss.driver.api.core.data.SettableById;
import com.datastax.oss.driver.api.core.data.SettableByName;
import com.datastax.oss.driver.internal.core.cql.DefaultBoundStatement;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;

/**
* A prepared statement in its executable form, with values bound to the variables.
*
* <p>The default implementation provided by the driver is:
*
* <ul>
* <li>not thread-safe: all methods (setting values, etc.) must be called from the thread that
* created the instance. Besides, if you use {@link CqlSession#executeAsync(Statement)}
* asynchronous execution}, do not reuse the same instance for multiple calls, as you run the
* risk of modifying the statement while the driver internals are still processing it.
* <li>mutable: all setters that return a {@code BoundStatement} modify and return the same
* instance, instead of creating a copy.
* </ul>
*/
public interface BoundStatement
extends Statement,
GettableById,
GettableByName,
SettableById<BoundStatement>,
SettableByName<BoundStatement> {

/** The prepared statement that was used to create this statement. */
PreparedStatement getPreparedStatement();

/** The values to bind, in their serialized form. */
List<ByteBuffer> getValues();

/**
* Sets the name of the configuration profile to use.
*
* <p>Note that this will be ignored if {@link #getConfigProfile()} return a non-null value.
*/
BoundStatement setConfigProfileName(String configProfileName);

/** Sets the configuration profile to use. */
BoundStatement setConfigProfile(DriverConfigProfile configProfile);

/** Sets the custom payload to send alongside the request. */
BoundStatement setCustomPayload(Map<String, ByteBuffer> customPayload);

/**
* Indicates whether the statement is idempotent.
*
* @param idempotent true or false, or {@code null} to use the default defined in the
* configuration.
*/
BoundStatement setIdempotent(Boolean idempotent);

/** Request tracing information for this statement. */
BoundStatement setTracing();
}
Expand Up @@ -17,18 +17,59 @@

import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.core.data.AccessibleByName;
import com.datastax.oss.driver.api.core.detach.AttachmentPoint;
import com.datastax.oss.driver.api.core.detach.Detachable;
import java.io.Serializable;
import java.util.Collections;
import java.util.Iterator;

/** Metadata about a set of CQL columns. */
public interface ColumnDefinitions extends Iterable<ColumnDefinition>, Detachable, Serializable {
int size();

ColumnDefinition get(int i);

/**
* Get a definition by name.
*
* <p>This is the equivalent of:
*
* <pre>
* get(firstIndexOf(name))
* </pre>
*
* @throws IllegalArgumentException if the name does not exist (in other words, if {@code
* !contains(name))}).
* @see #contains(String)
* @see #firstIndexOf(String)
*/
default ColumnDefinition get(String name) {
if (!contains(name)) {
throw new IllegalArgumentException("No definition named " + name);
} else {
return get(firstIndexOf(name));
}
}

/**
* Get a definition by name.
*
* <p>This is the equivalent of:
*
* <pre>
* get(firstIndexOf(name))
* </pre>
*
* @throws IllegalArgumentException if the name does not exist (in other words, if {@code
* !contains(name))}).
* @see #contains(CqlIdentifier)
* @see #firstIndexOf(CqlIdentifier)
*/
default ColumnDefinition get(CqlIdentifier name) {
if (!contains(name)) {
throw new IllegalArgumentException("No definition named " + name);
} else {
return get(firstIndexOf(name));
}
}

/**
* Whether there is a definition using the given name.
*
Expand Down
Expand Up @@ -18,6 +18,7 @@
import com.datastax.oss.driver.api.core.session.Request;
import com.datastax.oss.driver.api.core.session.Session;
import java.util.concurrent.CompletionStage;
import com.datastax.oss.driver.internal.core.cql.DefaultPrepareRequest;

public interface CqlSession extends Session {

Expand All @@ -40,18 +41,18 @@ default CompletionStage<AsyncResultSet> executeAsync(String query) {
}

default PreparedStatement prepare(String query) {
return execute(PrepareRequest.from(query));
return execute(new DefaultPrepareRequest(query));
}

default PreparedStatement prepare(Statement query) {
return execute(PrepareRequest.from(query));
default PreparedStatement prepare(SimpleStatement query) {
return execute(new DefaultPrepareRequest(query));
}

default CompletionStage<PreparedStatement> prepareAsync(String query) {
return executeAsync(PrepareRequest.from(query));
return executeAsync(new DefaultPrepareRequest(query));
}

default CompletionStage<PreparedStatement> prepareAsync(Statement query) {
return executeAsync(PrepareRequest.from(query));
default CompletionStage<PreparedStatement> prepareAsync(SimpleStatement query) {
return executeAsync(new DefaultPrepareRequest(query));
}
}
Expand Up @@ -15,28 +15,69 @@
*/
package com.datastax.oss.driver.api.core.cql;

import com.datastax.oss.driver.api.core.config.DriverConfigProfile;
import com.datastax.oss.driver.api.core.retry.RetryPolicy;
import com.datastax.oss.driver.api.core.session.Request;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.concurrent.CompletionStage;

/** A request to prepare a CQL query. */
/**
* A request to prepare a CQL query.
*
* <p>Driver clients should rarely have to deal directly with this type, it's used internally by
* {@link CqlSession}'s prepare methods. However a {@link RetryPolicy} implementation might use it
* if it needs a custom behavior for prepare requests.
*/
public interface PrepareRequest
extends Request<PreparedStatement, CompletionStage<PreparedStatement>> {

static PrepareRequest from(String query) {
throw new UnsupportedOperationException("TODO");
}

static PrepareRequest from(Statement statement) {
throw new UnsupportedOperationException("TODO");
}
/** The CQL query to prepare. */
String getQuery();

/**
* {@inheritDoc}
*
* <p>Note that this refers to the prepare query itself, not to the bound statements that will be
* created from the prepared statement (see {@link #areBoundStatementsIdempotent()}).
*/
@Override
default Boolean isIdempotent() {
return true; // Retrying to prepare is always safe
// Retrying to prepare is always safe
return true;
}

@Override
default boolean isTracing() {
// Tracing prepare requests is unlikely to be useful, we don't expose an API for it.
return false;
}

/**
* The name of the driver configuration profile to use for the bound statements that will be
* created from the prepared statement.
*
* <p>Note that this will be ignored if {@link #getConfigProfileForBoundStatements()} returns a
* non-null value.
*/
String getConfigProfileNameForBoundStatements();

/**
* The configuration profile to use for the bound statements that will be created from the
* prepared statement.
*/
DriverConfigProfile getConfigProfileForBoundStatements();

/**
* Returns the custom payload to send alongside the bound statements that will be created from the
* prepared statement.
*/
Map<String, ByteBuffer> getCustomPayloadForBoundStatements();

/**
* Whether bound statements that will be created from the prepared statement are idempotent.
*
* <p>This follows the same semantics as {@link #isIdempotent()}.
*/
Boolean areBoundStatementsIdempotent();
}
Expand Up @@ -15,4 +15,27 @@
*/
package com.datastax.oss.driver.api.core.cql;

public interface PreparedStatement {}
import java.nio.ByteBuffer;

public interface PreparedStatement {

/**
* A unique identifier for this prepared statement.
*
* <p>Note: the returned buffer is read-only.
*/
ByteBuffer getId();

String getQuery();

/** A description of the bind variables of this prepared statement. */
ColumnDefinitions getVariableDefinitions();

/**
* A description of the result set that will be returned when this prepared statement is bound and
* executed.
*/
ColumnDefinitions getResultSetDefinitions();

BoundStatement bind();
}
Expand Up @@ -70,11 +70,6 @@ public static AdminRequestHandler query(
return query(channel, query, Collections.emptyMap(), timeout, pageSize);
}

public static AdminRequestHandler prepare(DriverChannel channel, String query, Duration timeout) {
String debugString = "prepare '" + query + "'";
return new AdminRequestHandler(channel, new Prepare(query), timeout, debugString);
}

private final DriverChannel channel;
private final Message message;
private final Duration timeout;
Expand All @@ -84,7 +79,7 @@ public static AdminRequestHandler prepare(DriverChannel channel, String query, D
// This is only ever accessed on the channel's event loop, so it doesn't need to be volatile
private ScheduledFuture<?> timeoutFuture;

private AdminRequestHandler(
public AdminRequestHandler(
DriverChannel channel, Message message, Duration timeout, String debugString) {
this.channel = channel;
this.message = message;
Expand Down

0 comments on commit 9b5a45f

Please sign in to comment.