java: checkstyle for client module

Signed-off-by: Ze'ev Klapow <zklapow@hubspot.com>
This commit is contained in:
Ze'ev Klapow 2019-02-06 12:54:55 -05:00
Родитель af4a648d7e
Коммит 4a36888bf5
33 изменённых файлов: 1306 добавлений и 1125 удалений

1
java/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
target/

Просмотреть файл

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Puppy Crawl//DTD Suppressions 1.1//EN"
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<suppressions>
<suppress files="[\\/]generated-sources[\\/]" checks=".*"/>
<suppress files="[\\/]main[\\/]java[\\/].*\.java" id="JavadocParagraph"/>
<suppress checks="JavadocParagraph" files=".*[\\/]src[\\/](test|main)[\\/].*\.java"/>
<suppress checks="AbbreviationAsWordInName" files=".*[\\/]src[\\/](test|main)[\\/].*\.java"/>
<suppress checks="JavadocMethod" files=".*[\\/]src[\\/](test|main)[\\/].*\.java"/>
<suppress checks="SummaryJavadoc" files=".*[\\/]src[\\/](test|main)[\\/].*\.java"/>
<suppress checks="OverloadMethodsDeclarationOrder" files=".*[\\/]src[\\/](test|main)[\\/].*\.java"/>
</suppressions>

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -16,31 +16,41 @@
package io.vitess.client;
import javax.annotation.Nullable;
import io.vitess.proto.Vtrpc.CallerID;
import org.joda.time.Duration;
import org.joda.time.Instant;
import io.vitess.proto.Vtrpc.CallerID;
import javax.annotation.Nullable;
/**
* Context is an immutable object that carries per-request info.
*
* <p>RPC frameworks like gRPC have their own Context implementations that
* allow propagation of deadlines, cancellation, and end-user credentials
* across RPC boundaries (between client and server). Since these
* framework-specific Context implementations are not compatible with one
* another, we provide our own Context class that wraps common features.
* allow propagation of deadlines, cancellation, and end-user credentials across RPC boundaries
* (between client and server). Since these framework-specific Context implementations are not
* compatible with one another, we provide our own Context class that wraps common features.
*
* <p>In gRPC and other frameworks, the current Context is maintained in
* thread-local storage, so it's implicitly available to any method that
* needs it. In this Vitess client library, we pass Context as an explicit
* parameter to methods that need it. This allows us to defer enforcement
* of the specified request constraints until the request reaches the
* underlying framework-specific Vitess client implementation, at which point
* the native Context class can be used.
* thread-local storage, so it's implicitly available to any method that needs it. In this Vitess
* client library, we pass Context as an explicit parameter to methods that need it. This allows us
* to defer enforcement of the specified request constraints until the request reaches the
* underlying framework-specific Vitess client implementation, at which point the native Context
* class can be used.
*/
public class Context {
private static final Context DEFAULT_CONTEXT = new Context();
private Instant deadline;
private CallerID callerId;
private Context() {
}
private Context(Instant deadline, CallerID callerId) {
this.deadline = deadline;
this.callerId = callerId;
}
// getDefault returns an empty context.
public static Context getDefault() {
@ -57,8 +67,8 @@ public class Context {
}
/**
* withDeadlineAfter returns a derived context with a maximum deadline
* specified relative to the current time.
* withDeadlineAfter returns a derived context with a maximum deadline specified relative to the
* current time.
*/
public Context withDeadlineAfter(Duration duration) {
return withDeadline(Instant.now().plus(duration));
@ -90,14 +100,4 @@ public class Context {
public CallerID getCallerId() {
return callerId;
}
private Instant deadline;
private CallerID callerId;
private Context() {}
private Context(Instant deadline, CallerID callerId) {
this.deadline = deadline;
this.callerId = callerId;
}
}

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -21,20 +21,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.primitives.UnsignedLong;
import com.google.protobuf.ByteString;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.sql.SQLInvalidAuthorizationSpecException;
import java.sql.SQLNonTransientException;
import java.sql.SQLRecoverableException;
import java.sql.SQLSyntaxErrorException;
import java.sql.SQLTimeoutException;
import java.sql.SQLTransientException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import io.vitess.client.cursor.Cursor;
import io.vitess.client.cursor.CursorWithError;
@ -48,11 +34,41 @@ import io.vitess.proto.Vtgate.BoundShardQuery;
import io.vitess.proto.Vtgate.ExecuteEntityIdsRequest.EntityId;
import io.vitess.proto.Vtrpc.RPCError;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.sql.SQLInvalidAuthorizationSpecException;
import java.sql.SQLNonTransientException;
import java.sql.SQLRecoverableException;
import java.sql.SQLSyntaxErrorException;
import java.sql.SQLTimeoutException;
import java.sql.SQLTransientException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
/**
* Proto contains methods for working with Vitess protobuf messages.
*/
public class Proto {
public static final Function<byte[], ByteString> BYTE_ARRAY_TO_BYTE_STRING =
new Function<byte[], ByteString>() {
@Override
public ByteString apply(byte[] from) {
return ByteString.copyFrom(from);
}
};
public static final Function<Map.Entry<byte[], ?>, EntityId> MAP_ENTRY_TO_ENTITY_KEYSPACE_ID =
new Function<Map.Entry<byte[], ?>, EntityId>() {
@Override
public EntityId apply(Map.Entry<byte[], ?> entry) {
return buildEntityId(entry.getKey(), entry.getValue());
}
};
private static final int MAX_DECIMAL_UNIT = 30;
/**
@ -133,7 +149,7 @@ public class Proto {
}
try {
return Integer.parseInt(errorMessage.substring(start, end));
} catch (NumberFormatException e) {
} catch (NumberFormatException exc) {
return 0;
}
}
@ -256,7 +272,8 @@ public class Proto {
return builder.build();
}
public static List<CursorWithError> fromQueryResponsesToCursorList(List<Query.ResultWithError> resultWithErrorList) {
public static List<CursorWithError> fromQueryResponsesToCursorList(
List<Query.ResultWithError> resultWithErrorList) {
ImmutableList.Builder<CursorWithError> builder = new ImmutableList.Builder<CursorWithError>();
for (Query.ResultWithError resultWithError : resultWithErrorList) {
builder.add(new CursorWithError(resultWithError));
@ -264,26 +281,11 @@ public class Proto {
return builder.build();
}
public static final Function<byte[], ByteString> BYTE_ARRAY_TO_BYTE_STRING =
new Function<byte[], ByteString>() {
@Override
public ByteString apply(byte[] from) {
return ByteString.copyFrom(from);
}
};
public static final Function<Map.Entry<byte[], ?>, EntityId> MAP_ENTRY_TO_ENTITY_KEYSPACE_ID =
new Function<Map.Entry<byte[], ?>, EntityId>() {
@Override
public EntityId apply(Map.Entry<byte[], ?> entry) {
return buildEntityId(entry.getKey(), entry.getValue());
}
};
/**
* Represents a type and value in the type system used in query.proto.
*/
protected static class TypedValue {
Query.Type type;
ByteString value;
@ -300,7 +302,7 @@ public class Proto {
this.type = Query.Type.VARBINARY;
this.value = ByteString.copyFrom((byte[]) value);
} else if (value instanceof Integer || value instanceof Long || value instanceof Short
|| value instanceof Byte ) {
|| value instanceof Byte) {
// Int32, Int64, Short, Byte
this.type = Query.Type.INT64;
this.value = ByteString.copyFromUtf8(value.toString());

Просмотреть файл

@ -3,33 +3,34 @@ package io.vitess.client;
import java.io.File;
public class RefreshableVTGateConnection extends VTGateConnection {
private final File keystoreFile;
private final File truststoreFile;
private volatile long keystoreMtime;
private volatile long truststoreMtime;
public RefreshableVTGateConnection(RpcClient client,
String keystorePath,
String truststorePath) {
super(client);
this.keystoreFile = new File(keystorePath);
this.truststoreFile = new File(truststorePath);
this.keystoreMtime = this.keystoreFile.exists() ? this.keystoreFile.lastModified() : 0;
this.truststoreMtime = this.truststoreFile.exists() ? this.truststoreFile.lastModified() : 0;
}
private final File keystoreFile;
private final File truststoreFile;
private volatile long keystoreMtime;
private volatile long truststoreMtime;
public boolean checkKeystoreUpdates() {
long keystoreMtime = keystoreFile.exists() ? keystoreFile.lastModified() : 0;
long truststoreMtime = truststoreFile.exists() ? truststoreFile.lastModified() : 0;
boolean modified = false;
if (keystoreMtime > this.keystoreMtime) {
modified = true;
this.keystoreMtime = keystoreMtime;
}
if (truststoreMtime > this.truststoreMtime) {
modified = true;
this.truststoreMtime = truststoreMtime;
}
return modified;
public RefreshableVTGateConnection(RpcClient client,
String keystorePath,
String truststorePath) {
super(client);
this.keystoreFile = new File(keystorePath);
this.truststoreFile = new File(truststorePath);
this.keystoreMtime = this.keystoreFile.exists() ? this.keystoreFile.lastModified() : 0;
this.truststoreMtime = this.truststoreFile.exists() ? this.truststoreFile.lastModified() : 0;
}
public boolean checkKeystoreUpdates() {
long keystoreMtime = keystoreFile.exists() ? keystoreFile.lastModified() : 0;
long truststoreMtime = truststoreFile.exists() ? truststoreFile.lastModified() : 0;
boolean modified = false;
if (keystoreMtime > this.keystoreMtime) {
modified = true;
this.keystoreMtime = keystoreMtime;
}
if (truststoreMtime > this.truststoreMtime) {
modified = true;
this.truststoreMtime = truststoreMtime;
}
return modified;
}
}

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -17,8 +17,6 @@
package io.vitess.client;
import com.google.common.util.concurrent.ListenableFuture;
import java.io.Closeable;
import java.sql.SQLException;
import io.vitess.proto.Query.QueryResult;
import io.vitess.proto.Vtgate;
@ -51,10 +49,14 @@ import io.vitess.proto.Vtgate.StreamExecuteKeyspaceIdsRequest;
import io.vitess.proto.Vtgate.StreamExecuteRequest;
import io.vitess.proto.Vtgate.StreamExecuteShardsRequest;
import java.io.Closeable;
import java.sql.SQLException;
/**
* RpcClient defines a set of methods to communicate with VTGates.
*/
public interface RpcClient extends Closeable {
/**
* Sends a single query using the VTGate V3 API.
*
@ -112,7 +114,8 @@ public interface RpcClient extends Closeable {
* <a href="https://github.com/vitessio/vitess/blob/master/proto/vtgateservice.proto">proto</a>
* definition for canonical documentation on this VTGate API.
*/
ListenableFuture<Vtgate.ExecuteBatchResponse> executeBatch(Context ctx, Vtgate.ExecuteBatchRequest request)
ListenableFuture<Vtgate.ExecuteBatchResponse> executeBatch(Context ctx,
Vtgate.ExecuteBatchRequest request)
throws SQLException;
/**
@ -139,9 +142,9 @@ public interface RpcClient extends Closeable {
* Starts stream queries with the VTGate V3 API.
*
* <p>Note: Streaming queries are not asynchronous, because they typically shouldn't
* be used from a latency-critical serving path anyway. This method will return as
* soon as the request is initiated, but StreamIterator methods will block until the
* next chunk of results is received from the server.
* be used from a latency-critical serving path anyway. This method will return as soon as the
* request is initiated, but StreamIterator methods will block until the next chunk of results is
* received from the server.
*
* <p>See the
* <a href="https://github.com/vitessio/vitess/blob/master/proto/vtgateservice.proto">proto</a>
@ -154,9 +157,9 @@ public interface RpcClient extends Closeable {
* Starts stream queries with multiple shards.
*
* <p>Note: Streaming queries are not asynchronous, because they typically shouldn't
* be used from a latency-critical serving path anyway. This method will return as
* soon as the request is initiated, but StreamIterator methods will block until the
* next chunk of results is received from the server.
* be used from a latency-critical serving path anyway. This method will return as soon as the
* request is initiated, but StreamIterator methods will block until the next chunk of results is
* received from the server.
*
* <p>See the
* <a href="https://github.com/vitessio/vitess/blob/master/proto/vtgateservice.proto">proto</a>
@ -169,9 +172,9 @@ public interface RpcClient extends Closeable {
* Starts a list of stream queries with keyspace ids as bind variables.
*
* <p>Note: Streaming queries are not asynchronous, because they typically shouldn't
* be used from a latency-critical serving path anyway. This method will return as
* soon as the request is initiated, but StreamIterator methods will block until the
* next chunk of results is received from the server.
* be used from a latency-critical serving path anyway. This method will return as soon as the
* request is initiated, but StreamIterator methods will block until the next chunk of results is
* received from the server.
*
* <p>See the
* <a href="https://github.com/vitessio/vitess/blob/master/proto/vtgateservice.proto">proto</a>
@ -184,9 +187,9 @@ public interface RpcClient extends Closeable {
* Starts stream query with a set of key ranges.
*
* <p>Note: Streaming queries are not asynchronous, because they typically shouldn't
* be used from a latency-critical serving path anyway. This method will return as
* soon as the request is initiated, but StreamIterator methods will block until the
* next chunk of results is received from the server.
* be used from a latency-critical serving path anyway. This method will return as soon as the
* request is initiated, but StreamIterator methods will block until the next chunk of results is
* received from the server.
*
* <p>See the
* <a href="https://github.com/vitessio/vitess/blob/master/proto/vtgateservice.proto">proto</a>

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -18,6 +18,7 @@ package io.vitess.client;
import com.google.common.util.concurrent.ForwardingListenableFuture.SimpleForwardingListenableFuture;
import com.google.common.util.concurrent.ListenableFuture;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
@ -31,22 +32,22 @@ import java.util.concurrent.TimeoutException;
*
* <p>
* When used as a {@link ListenableFuture}, the {@link SQLException} thrown by Vitess will be
* wrapped in {@link ExecutionException}. You can retrieve it by calling
* {@link ExecutionException#getCause()}.
* wrapped in {@link ExecutionException}. You can retrieve it by calling {@link
* ExecutionException#getCause()}.
*
* <p>
* For users who want to get results synchronously, we provide {@link #checkedGet()} as a
* convenience method. Unlike {@link #get()}, it throws only {@code SQLException}, so e.g.
* {@code vtgateConn.execute(...).checkedGet()} behaves the same as our old synchronous API.
* convenience method. Unlike {@link #get()}, it throws only {@code SQLException}, so e.g. {@code
* vtgateConn.execute(...).checkedGet()} behaves the same as our old synchronous API.
*
* <p>
* The additional methods are similar to the {@code CheckedFuture} interface (marked as beta), but
* this class does not declare that it implements {@code CheckedFuture} because that interface is
* not recommended for new projects. See the <a href=
* "https://google.github.io/guava/releases/19.0/api/docs/com/google/common/util/concurrent/CheckedFuture.html">
* not recommended for new projects. See the <a href= "https://google.github.io/guava/releases/19.0/api/docs/com/google/common/util/concurrent/CheckedFuture.html">
* CheckedFuture docs</a> for more information.
*/
public class SQLFuture<V> extends SimpleForwardingListenableFuture<V> {
/**
* Creates a SQLFuture that wraps the given ListenableFuture.
*/
@ -64,13 +65,11 @@ public class SQLFuture<V> extends SimpleForwardingListenableFuture<V> {
public V checkedGet() throws SQLException {
try {
return get();
} catch (InterruptedException e) {
} catch (InterruptedException exc) {
Thread.currentThread().interrupt();
throw mapException(e);
} catch (CancellationException e) {
throw mapException(e);
} catch (ExecutionException e) {
throw mapException(e);
throw mapException(exc);
} catch (CancellationException | ExecutionException exc) {
throw mapException(exc);
}
}
@ -84,33 +83,31 @@ public class SQLFuture<V> extends SimpleForwardingListenableFuture<V> {
public V checkedGet(long timeout, TimeUnit unit) throws TimeoutException, SQLException {
try {
return get(timeout, unit);
} catch (InterruptedException e) {
} catch (InterruptedException exc) {
Thread.currentThread().interrupt();
throw mapException(e);
} catch (CancellationException e) {
throw mapException(e);
} catch (ExecutionException e) {
throw mapException(e);
throw mapException(exc);
} catch (CancellationException | ExecutionException exc) {
throw mapException(exc);
}
}
/**
* Translates from an {@link InterruptedException}, {@link CancellationException} or
* {@link ExecutionException} thrown by {@code get} to an exception of type {@code SQLException}
* to be thrown by {@code checkedGet}.
* Translates from an {@link InterruptedException}, {@link CancellationException} or {@link
* ExecutionException} thrown by {@code get} to an exception of type {@code SQLException} to be
* thrown by {@code checkedGet}.
*
* <p>
* If {@code e} is an {@code InterruptedException}, the calling {@code checkedGet} method has
* already restored the interrupt after catching the exception. If an implementation of
* {@link #mapException(Exception)} wishes to swallow the interrupt, it can do so by calling
* {@link Thread#interrupted()}.
* If {@code exc} is an {@code InterruptedException}, the calling {@code checkedGet} method has
* already restored the interrupt after catching the exception. If an implementation of {@link
* #mapException(Exception)} wishes to swallow the interrupt, it can do so by calling {@link
* Thread#interrupted()}.
*/
protected SQLException mapException(Exception e) {
if (e instanceof ExecutionException) {
protected SQLException mapException(Exception exc) {
if (exc instanceof ExecutionException) {
// To preserve both the stack trace and SQLException subclass type of the error
// being wrapped, we use reflection to create a new instance of the particular
// subclass of the original exception.
Throwable cause = e.getCause();
Throwable cause = exc.getCause();
if (cause instanceof SQLException) {
SQLException se = (SQLException) cause;
try {
@ -119,7 +116,7 @@ public class SQLFuture<V> extends SimpleForwardingListenableFuture<V> {
.getClass()
.getConstructor(String.class, String.class, int.class, Throwable.class);
return (SQLException)
constructor.newInstance(se.getMessage(), se.getSQLState(), se.getErrorCode(), e);
constructor.newInstance(se.getMessage(), se.getSQLState(), se.getErrorCode(), exc);
} catch (NoSuchMethodException
| InstantiationException
| IllegalAccessException
@ -131,6 +128,6 @@ public class SQLFuture<V> extends SimpleForwardingListenableFuture<V> {
}
}
return new SQLException(e);
return new SQLException(exc);
}
}

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -20,29 +20,30 @@ import java.sql.SQLException;
import java.util.NoSuchElementException;
/**
* An {@link java.util.Iterator Iterator}-like interface for accessing the results of a
* Vitess streaming call.
* An {@link java.util.Iterator Iterator}-like interface for accessing the results of a Vitess
* streaming call.
*
* <p>It is similar to {@link java.util.Iterator}, but the hasNext() method is
* understood to block until either a result is ready, an error occurs,
* or there are no more results. Also, unlike Iterator, these methods
* can throw SQLException.
* understood to block until either a result is ready, an error occurs, or there are no more
* results. Also, unlike Iterator, these methods can throw SQLException.
*
* <p>The {@link #close()} method should be called when done to free up threads that may be blocking
* <p>The {@link #close()} method should be called when done to free up threads that may be
* blocking
* on the streaming connection.
*
* @param <E> the type of result returned by the iterator,
* e.g. {@link io.vitess.proto.Query.QueryResult QueryResult}
* @param <E> the type of result returned by the iterator, e.g. {@link
* io.vitess.proto.Query.QueryResult QueryResult}
*/
public interface StreamIterator<E> extends AutoCloseable {
/**
* hasNext returns true if next() would return a value.
*
* <p>If no value is available, hasNext() will block until either:
* <ul>
* <li>A value becomes available (returns true),
* <li>The stream completes successfully (returns false),
* <li>An error occurs (throws exception).
* <li>A value becomes available (returns true),
* <li>The stream completes successfully (returns false),
* <li>An error occurs (throws exception).
* </ul>
*/
boolean hasNext() throws SQLException;
@ -52,9 +53,9 @@ public interface StreamIterator<E> extends AutoCloseable {
*
* <p>If no value is available, next() will block until either:
* <ul>
* <li>A value becomes available (returns the value),
* <li>The stream completes successfully (throws NoSuchElementException),
* <li>An error occurs (throws other exception).
* <li>A value becomes available (returns the value),
* <li>The stream completes successfully (throws NoSuchElementException),
* <li>An error occurs (throws other exception).
* </ul>
*/
E next() throws NoSuchElementException, SQLException;

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -16,14 +16,6 @@
package io.vitess.client;
import java.io.Closeable;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import io.vitess.client.cursor.Cursor;
import io.vitess.client.cursor.CursorWithError;
import io.vitess.proto.Query;
@ -35,6 +27,15 @@ import io.vitess.proto.Vtgate.BoundKeyspaceIdQuery;
import io.vitess.proto.Vtgate.BoundShardQuery;
import io.vitess.proto.Vtgate.SplitQueryResponse;
import java.io.Closeable;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
/**
* A synchronous wrapper around a VTGate connection.
*
@ -44,6 +45,7 @@ import io.vitess.proto.Vtgate.SplitQueryResponse;
*/
@Deprecated
public class VTGateBlockingConn implements Closeable {
private final VTGateConn conn;
/**
@ -76,15 +78,18 @@ public class VTGateBlockingConn implements Closeable {
}
public Cursor executeShards(Context ctx, String query, String keyspace, Iterable<String> shards,
Map<String, ?> bindVars, TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
return conn.executeShards(ctx, query, keyspace, shards, bindVars, tabletType, includedFields).checkedGet();
Map<String, ?> bindVars, TabletType tabletType,
Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
return conn.executeShards(ctx, query, keyspace, shards, bindVars, tabletType, includedFields)
.checkedGet();
}
public Cursor executeKeyspaceIds(Context ctx, String query, String keyspace,
Iterable<byte[]> keyspaceIds, Map<String, ?> bindVars, TabletType tabletType,
Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
return conn.executeKeyspaceIds(ctx, query, keyspace, keyspaceIds, bindVars, tabletType, includedFields)
return conn
.executeKeyspaceIds(ctx, query, keyspace, keyspaceIds, bindVars, tabletType, includedFields)
.checkedGet();
}
@ -92,13 +97,15 @@ public class VTGateBlockingConn implements Closeable {
Iterable<? extends KeyRange> keyRanges, Map<String, ?> bindVars, TabletType tabletType,
Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
return conn.executeKeyRanges(ctx, query, keyspace, keyRanges, bindVars, tabletType, includedFields)
return conn
.executeKeyRanges(ctx, query, keyspace, keyRanges, bindVars, tabletType, includedFields)
.checkedGet();
}
public Cursor executeEntityIds(Context ctx, String query, String keyspace,
String entityColumnName, Map<byte[], ?> entityKeyspaceIds, Map<String, ?> bindVars,
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
return conn.executeEntityIds(ctx, query, keyspace, entityColumnName, entityKeyspaceIds,
bindVars, tabletType, includedFields).checkedGet();
}
@ -111,36 +118,44 @@ public class VTGateBlockingConn implements Closeable {
public List<CursorWithError> executeBatch(Context ctx, ArrayList<String> queryList,
@Nullable ArrayList<Map<String, ?>> bindVarsList, TabletType tabletType,
boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
return conn.executeBatch(ctx, queryList, bindVarsList, tabletType, asTransaction, includedFields).checkedGet();
boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
return conn
.executeBatch(ctx, queryList, bindVarsList, tabletType, asTransaction, includedFields)
.checkedGet();
}
/**
* Execute multiple keyspace ID queries as a batch.
*
* @param asTransaction If true, automatically create a transaction (per shard) that encloses all
* the batch queries.
* @param asTransaction If true, automatically create a transaction (per shard) that encloses
* all the batch queries.
*/
public List<Cursor> executeBatchShards(Context ctx, Iterable<? extends BoundShardQuery> queries,
TabletType tabletType, boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields)
TabletType tabletType, boolean asTransaction,
Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
return conn.executeBatchShards(ctx, queries, tabletType, asTransaction, includedFields).checkedGet();
return conn.executeBatchShards(ctx, queries, tabletType, asTransaction, includedFields)
.checkedGet();
}
/**
* Execute multiple keyspace ID queries as a batch.
*
* @param asTransaction If true, automatically create a transaction (per shard) that encloses all
* the batch queries.
* @param asTransaction If true, automatically create a transaction (per shard) that encloses
* all the batch queries.
*/
public List<Cursor> executeBatchKeyspaceIds(Context ctx,
Iterable<? extends BoundKeyspaceIdQuery> queries, TabletType tabletType,
boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
return conn.executeBatchKeyspaceIds(ctx, queries, tabletType, asTransaction, includedFields).checkedGet();
boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
return conn.executeBatchKeyspaceIds(ctx, queries, tabletType, asTransaction, includedFields)
.checkedGet();
}
public Cursor streamExecute(Context ctx, String query, Map<String, ?> bindVars,
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
return conn.streamExecute(ctx, query, bindVars, tabletType, includedFields);
}
@ -148,21 +163,24 @@ public class VTGateBlockingConn implements Closeable {
Iterable<String> shards, Map<String, ?> bindVars, TabletType tabletType,
Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
return conn.streamExecuteShards(ctx, query, keyspace, shards, bindVars, tabletType, includedFields);
return conn
.streamExecuteShards(ctx, query, keyspace, shards, bindVars, tabletType, includedFields);
}
public Cursor streamExecuteKeyspaceIds(Context ctx, String query, String keyspace,
Iterable<byte[]> keyspaceIds, Map<String, ?> bindVars, TabletType tabletType,
Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
return conn.streamExecuteKeyspaceIds(ctx, query, keyspace, keyspaceIds, bindVars, tabletType, includedFields);
return conn.streamExecuteKeyspaceIds(ctx, query, keyspace, keyspaceIds, bindVars, tabletType,
includedFields);
}
public Cursor streamExecuteKeyRanges(Context ctx, String query, String keyspace,
Iterable<? extends KeyRange> keyRanges, Map<String, ?> bindVars, TabletType tabletType,
Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
return conn.streamExecuteKeyRanges(ctx, query, keyspace, keyRanges, bindVars, tabletType, includedFields);
return conn.streamExecuteKeyRanges(ctx, query, keyspace, keyRanges, bindVars, tabletType,
includedFields);
}
public VTGateBlockingTx begin(Context ctx) throws SQLException {

Просмотреть файл

@ -16,135 +16,162 @@
package io.vitess.client;
import java.io.Closeable;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import io.vitess.client.cursor.Cursor;
import io.vitess.client.cursor.CursorWithError;
import io.vitess.proto.Query.SplitQueryRequest.Algorithm;
import io.vitess.proto.Vtgate.SplitQueryResponse;
import java.io.Closeable;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
/**
* An asynchronous VTGate connection.
* <p>
* <p>All the information regarding this connection is maintained by {@code Session},
* only one operation can be in flight at a time on a given instance.
* The methods are {@code synchronized} only because the session cookie is updated asynchronously
* when the RPC response comes back.</p>
* only one operation can be in flight at a time on a given instance. The methods are {@code
* synchronized} only because the session cookie is updated asynchronously when the RPC response
* comes back.</p>
* <p>
* <p>After calling any method that returns a {@link SQLFuture}, you must wait for that future to
* complete before calling any other methods on that {@code VTGateConnection} instance.
* An {@link IllegalStateException} will be thrown if this constraint is violated.</p>
* complete before calling any other methods on that {@code VTGateConnection} instance. An {@link
* IllegalStateException} will be thrown if this constraint is violated.</p>
* <p>
* <p>All non-streaming calls on {@code VTGateConnection} are asynchronous. Use {@link VTGateBlockingConnection} if
* <p>All non-streaming calls on {@code VTGateConnection} are asynchronous. Use {@link
* VTGateBlockingConnection} if
* you want synchronous calls.</p>
*/
public final class VTGateBlockingConnection implements Closeable {
private final VTGateConnection vtGateConnection;
/**
* Creates a VTGate connection with no specific parameters.
* <p>
* <p>In this mode, VTGate will use VSchema to resolve the keyspace for any unprefixed
* table names. Note that this only works if the table name is unique across all keyspaces.</p>
*
* @param client RPC connection
*/
public VTGateBlockingConnection(RpcClient client) {
vtGateConnection = new VTGateConnection(client);
}
private final VTGateConnection vtGateConnection;
/**
* This method calls the VTGate to execute the query.
*
* @param ctx Context on user and execution deadline if any.
* @param query Sql Query to be executed.
* @param bindVars Parameters to bind with sql.
* @param vtSession Session to be used with the call.
* @return Cursor
* @throws SQLException If anything fails on query execution.
*/
public Cursor execute(Context ctx, String query, @Nullable Map<String, ?> bindVars, final VTSession vtSession) throws SQLException {
return vtGateConnection.execute(ctx, query, bindVars, vtSession).checkedGet();
}
/**
* Creates a VTGate connection with no specific parameters.
* <p>
* <p>In this mode, VTGate will use VSchema to resolve the keyspace for any unprefixed
* table names. Note that this only works if the table name is unique across all keyspaces.</p>
*
* @param client RPC connection
*/
public VTGateBlockingConnection(RpcClient client) {
vtGateConnection = new VTGateConnection(client);
}
/**
* This method calls the VTGate to execute list of queries as a batch.
*
* @param ctx Context on user and execution deadline if any.
* @param queryList List of sql queries to be executed.
* @param bindVarsList <p>For each sql query it will provide a list of parameters to bind with.
* If provided, should match the number of sql queries.</p>
* @param vtSession Session to be used with the call.
* @return List of Cursors
* @throws SQLException If anything fails on query execution.
*/
public List<CursorWithError> executeBatch(Context ctx, List<String> queryList, @Nullable List<Map<String, ?>> bindVarsList, final VTSession vtSession) throws SQLException {
return vtGateConnection.executeBatch(ctx, queryList, bindVarsList, vtSession).checkedGet();
}
/**
* This method calls the VTGate to execute the query.
*
* @param ctx Context on user and execution deadline if any.
* @param query Sql Query to be executed.
* @param bindVars Parameters to bind with sql.
* @param vtSession Session to be used with the call.
* @return Cursor
* @throws SQLException If anything fails on query execution.
*/
public Cursor execute(Context ctx,
String query,
@Nullable Map<String, ?> bindVars,
final VTSession vtSession) throws SQLException {
return vtGateConnection.execute(ctx, query, bindVars, vtSession).checkedGet();
}
/**
* This method calls the VTGate to execute list of queries as a batch.
* <p>
* <p>If asTransaction is set to <code>true</code> then query execution will not change the session cookie.
* Otherwise, query execution will become part of the session.</p>
*
* @param ctx Context on user and execution deadline if any.
* @param queryList List of sql queries to be executed.
* @param bindVarsList <p>For each sql query it will provide a list of parameters to bind with.
* If provided, should match the number of sql queries.</p>
* @param asTransaction To execute query without impacting session cookie.
* @param vtSession Session to be used with the call.
* @return List of Cursors
* @throws SQLException If anything fails on query execution.
*/
public List<CursorWithError> executeBatch(Context ctx, List<String> queryList, @Nullable List<Map<String, ?>> bindVarsList, boolean asTransaction, final VTSession vtSession) throws SQLException {
return vtGateConnection.executeBatch(ctx, queryList, bindVarsList, asTransaction, vtSession).checkedGet();
}
/**
* This method calls the VTGate to execute list of queries as a batch.
*
* @param ctx Context on user and execution deadline if any.
* @param queryList List of sql queries to be executed.
* @param bindVarsList <p>For each sql query it will provide a list of parameters to bind with. If
* provided, should match the number of sql queries.</p>
* @param vtSession Session to be used with the call.
* @return List of Cursors
* @throws SQLException If anything fails on query execution.
*/
public List<CursorWithError> executeBatch(Context ctx,
List<String> queryList,
@Nullable List<Map<String, ?>> bindVarsList,
final VTSession vtSession) throws SQLException {
return vtGateConnection.executeBatch(ctx, queryList, bindVarsList, vtSession).checkedGet();
}
/**
* This method should be used execute select query to return response as a stream.
*
* @param ctx Context on user and execution deadline if any.
* @param query Sql Query to be executed.
* @param bindVars Parameters to bind with sql.
* @param vtSession Session to be used with the call.
* @return Cursor
* @throws SQLException Returns SQLException if there is any failure on VTGate.
*/
public Cursor streamExecute(Context ctx, String query, @Nullable Map<String, ?> bindVars, VTSession vtSession) throws SQLException {
return vtGateConnection.streamExecute(ctx, query, bindVars, vtSession);
}
/**
* This method calls the VTGate to execute list of queries as a batch.
* <p>
* <p>If asTransaction is set to <code>true</code> then query execution will not change the
* session cookie.
* Otherwise, query execution will become part of the session.</p>
*
* @param ctx Context on user and execution deadline if any.
* @param queryList List of sql queries to be executed.
* @param bindVarsList <p>For each sql query it will provide a list of parameters to bind with. If
* provided, should match the number of sql queries.</p>
* @param asTransaction To execute query without impacting session cookie.
* @param vtSession Session to be used with the call.
* @return List of Cursors
* @throws SQLException If anything fails on query execution.
*/
public List<CursorWithError> executeBatch(Context ctx,
List<String> queryList,
@Nullable List<Map<String, ?>> bindVarsList,
boolean asTransaction,
final VTSession vtSession) throws SQLException {
return vtGateConnection.executeBatch(ctx, queryList, bindVarsList, asTransaction, vtSession)
.checkedGet();
}
/**
* This method splits the query into small parts based on the splitColumn and Algorithm type provided.
*
* @param ctx Context on user and execution deadline if any.
* @param keyspace Keyspace to execute the query on.
* @param query Sql Query to be executed.
* @param bindVars Parameters to bind with sql.
* @param splitColumns Column to be used to split the data.
* @param splitCount Number of Partitions
* @param numRowsPerQueryPart Limit the number of records per query part.
* @param algorithm EQUAL_SPLITS or FULL_SCAN
* @return Query Parts
* @throws SQLException If anything fails on query execution.
*/
public List<SplitQueryResponse.Part> splitQuery(Context ctx, String keyspace, String query, @Nullable Map<String, ?> bindVars, Iterable<String> splitColumns,
int splitCount, int numRowsPerQueryPart, Algorithm algorithm) throws SQLException {
return vtGateConnection.splitQuery(ctx, keyspace, query, bindVars, splitColumns, splitCount, numRowsPerQueryPart, algorithm).checkedGet();
}
/**
* This method should be used execute select query to return response as a stream.
*
* @param ctx Context on user and execution deadline if any.
* @param query Sql Query to be executed.
* @param bindVars Parameters to bind with sql.
* @param vtSession Session to be used with the call.
* @return Cursor
* @throws SQLException Returns SQLException if there is any failure on VTGate.
*/
public Cursor streamExecute(Context ctx,
String query,
@Nullable Map<String, ?> bindVars,
VTSession vtSession) throws SQLException {
return vtGateConnection.streamExecute(ctx, query, bindVars, vtSession);
}
/**
* @inheritDoc
*/
@Override
public void close() throws IOException {
vtGateConnection.close();
}
/**
* This method splits the query into small parts based on the splitColumn and Algorithm type
* provided.
*
* @param ctx Context on user and execution deadline if any.
* @param keyspace Keyspace to execute the query on.
* @param query Sql Query to be executed.
* @param bindVars Parameters to bind with sql.
* @param splitColumns Column to be used to split the data.
* @param splitCount Number of Partitions
* @param numRowsPerQueryPart Limit the number of records per query part.
* @param algorithm EQUAL_SPLITS or FULL_SCAN
* @return Query Parts
* @throws SQLException If anything fails on query execution.
*/
public List<SplitQueryResponse.Part> splitQuery(Context ctx,
String keyspace,
String query,
@Nullable Map<String, ?> bindVars,
Iterable<String> splitColumns,
int splitCount,
int numRowsPerQueryPart,
Algorithm algorithm) throws SQLException {
return vtGateConnection
.splitQuery(ctx, keyspace, query, bindVars, splitColumns, splitCount, numRowsPerQueryPart,
algorithm).checkedGet();
}
/**
* @inheritDoc
*/
@Override
public void close() throws IOException {
vtGateConnection.close();
}
}

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -16,11 +16,6 @@
package io.vitess.client;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import io.vitess.client.cursor.Cursor;
import io.vitess.client.cursor.CursorWithError;
import io.vitess.proto.Query;
@ -29,6 +24,12 @@ import io.vitess.proto.Topodata.TabletType;
import io.vitess.proto.Vtgate.BoundKeyspaceIdQuery;
import io.vitess.proto.Vtgate.BoundShardQuery;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
/**
* A synchronous wrapper around a VTGate transaction.
*
@ -37,6 +38,7 @@ import io.vitess.proto.Vtgate.BoundShardQuery;
*/
@Deprecated
public class VTGateBlockingTx {
private final VTGateTx tx;
/**
@ -61,7 +63,8 @@ public class VTGateBlockingTx {
TabletType tabletType,
Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
return tx.executeShards(ctx, query, keyspace, shards, bindVars, tabletType, includedFields).checkedGet();
return tx.executeShards(ctx, query, keyspace, shards, bindVars, tabletType, includedFields)
.checkedGet();
}
public Cursor executeKeyspaceIds(
@ -73,7 +76,8 @@ public class VTGateBlockingTx {
TabletType tabletType,
Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
return tx.executeKeyspaceIds(ctx, query, keyspace, keyspaceIds, bindVars, tabletType, includedFields)
return tx
.executeKeyspaceIds(ctx, query, keyspace, keyspaceIds, bindVars, tabletType, includedFields)
.checkedGet();
}
@ -86,7 +90,9 @@ public class VTGateBlockingTx {
TabletType tabletType,
Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
return tx.executeKeyRanges(ctx, query, keyspace, keyRanges, bindVars, tabletType, includedFields).checkedGet();
return tx
.executeKeyRanges(ctx, query, keyspace, keyRanges, bindVars, tabletType, includedFields)
.checkedGet();
}
public Cursor executeEntityIds(
@ -100,7 +106,8 @@ public class VTGateBlockingTx {
Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
return tx.executeEntityIds(
ctx, query, keyspace, entityColumnName, entityKeyspaceIds, bindVars, tabletType, includedFields)
ctx, query, keyspace, entityColumnName, entityKeyspaceIds, bindVars, tabletType,
includedFields)
.checkedGet();
}

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -24,14 +24,6 @@ import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.io.Closeable;
import java.io.IOException;
import java.sql.SQLDataException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import io.vitess.client.cursor.Cursor;
import io.vitess.client.cursor.CursorWithError;
@ -70,12 +62,21 @@ import io.vitess.proto.Vtgate.StreamExecuteKeyspaceIdsRequest;
import io.vitess.proto.Vtgate.StreamExecuteRequest;
import io.vitess.proto.Vtgate.StreamExecuteShardsRequest;
import java.io.Closeable;
import java.io.IOException;
import java.sql.SQLDataException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
/**
* An asynchronous VTGate connection.
*
* <p>
* See the <a href=
* "https://github.com/vitessio/vitess/blob/master/java/example/src/main/java/io/vitess/example/VitessClientExample.java">VitessClientExample</a>
* See the <a href= "https://github.com/vitessio/vitess/blob/master/java/example/src/main/java/io/vitess/example/VitessClientExample.java">VitessClientExample</a>
* for a usage example.
*
* <p>
@ -84,6 +85,7 @@ import io.vitess.proto.Vtgate.StreamExecuteShardsRequest;
*/
@Deprecated
public final class VTGateConn implements Closeable {
private final RpcClient client;
private final String keyspace;
@ -107,8 +109,8 @@ public final class VTGateConn implements Closeable {
* The given {@code keyspace} will be used as the connection-wide default for {@code execute()}
* and {@code streamExecute()} calls, since those do not specify the keyspace for each call. Like
* the connection-wide default database of a MySQL connection, individual queries can still refer
* to other keyspaces by prefixing table names. For example:
* {@code "SELECT ... FROM keyspace.table ..."}
* to other keyspaces by prefixing table names. For example: {@code "SELECT ... FROM
* keyspace.table ..."}
*/
public VTGateConn(RpcClient client, String keyspace) {
this.client = checkNotNull(client);
@ -116,13 +118,14 @@ public final class VTGateConn implements Closeable {
}
public SQLFuture<Cursor> execute(Context ctx, String query, @Nullable Map<String, ?> bindVars,
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
ExecuteRequest.Builder requestBuilder = ExecuteRequest.newBuilder()
.setQuery(Proto.bindQuery(checkNotNull(query), bindVars))
.setKeyspaceShard(keyspace)
.setTabletType(checkNotNull(tabletType))
.setOptions(Query.ExecuteOptions.newBuilder()
.setIncludedFields(includedFields));
.setQuery(Proto.bindQuery(checkNotNull(query), bindVars))
.setKeyspaceShard(keyspace)
.setTabletType(checkNotNull(tabletType))
.setOptions(Query.ExecuteOptions.newBuilder()
.setIncludedFields(includedFields));
if (ctx.getCallerId() != null) {
requestBuilder.setCallerId(ctx.getCallerId());
@ -205,7 +208,8 @@ public final class VTGateConn implements Closeable {
public SQLFuture<Cursor> executeKeyRanges(Context ctx, String query, String keyspace,
Iterable<? extends KeyRange> keyRanges, @Nullable Map<String, ?> bindVars,
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
ExecuteKeyRangesRequest.Builder requestBuilder = ExecuteKeyRangesRequest.newBuilder()
.setQuery(Proto.bindQuery(checkNotNull(query), bindVars))
.setKeyspace(checkNotNull(keyspace))
@ -234,7 +238,8 @@ public final class VTGateConn implements Closeable {
public SQLFuture<Cursor> executeEntityIds(Context ctx, String query, String keyspace,
String entityColumnName, Map<byte[], ?> entityKeyspaceIds, @Nullable Map<String, ?> bindVars,
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
ExecuteEntityIdsRequest.Builder requestBuilder = ExecuteEntityIdsRequest.newBuilder()
.setQuery(Proto.bindQuery(checkNotNull(query), bindVars))
.setKeyspace(checkNotNull(keyspace))
@ -263,39 +268,40 @@ public final class VTGateConn implements Closeable {
directExecutor()));
}
public SQLFuture<List<CursorWithError>> executeBatch(Context ctx, List<String> queryList,
@Nullable List<Map<String, ?>> bindVarsList, TabletType tabletType,
Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
return executeBatch(ctx, queryList, bindVarsList, tabletType, false, includedFields);
public SQLFuture<List<CursorWithError>> executeBatch(Context ctx, List<String> queryList,
@Nullable List<Map<String, ?>> bindVarsList, TabletType tabletType,
Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
return executeBatch(ctx, queryList, bindVarsList, tabletType, false, includedFields);
}
public SQLFuture<List<CursorWithError>> executeBatch(Context ctx, List<String> queryList,
@Nullable List<Map<String, ?>> bindVarsList, TabletType tabletType,
boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
List<Query.BoundQuery> queries = new ArrayList<>();
if (null != bindVarsList && bindVarsList.size() != queryList.size()) {
throw new SQLDataException(
"Size of SQL Query list does not match the bind variables list");
}
public SQLFuture<List<CursorWithError>> executeBatch(Context ctx, List<String> queryList,
@Nullable List<Map<String, ?>> bindVarsList, TabletType tabletType,
boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
List<Query.BoundQuery> queries = new ArrayList<>();
for (int i = 0; i < queryList.size(); ++i) {
queries.add(i, Proto.bindQuery(checkNotNull(queryList.get(i)),
bindVarsList == null ? null : bindVarsList.get(i)));
}
if (null != bindVarsList && bindVarsList.size() != queryList.size()) {
throw new SQLDataException(
"Size of SQL Query list does not match the bind variables list");
}
Vtgate.ExecuteBatchRequest.Builder requestBuilder =
Vtgate.ExecuteBatchRequest.newBuilder()
.addAllQueries(checkNotNull(queries))
.setKeyspaceShard(keyspace)
.setTabletType(checkNotNull(tabletType))
.setAsTransaction(asTransaction)
.setOptions(Query.ExecuteOptions.newBuilder()
.setIncludedFields(includedFields));
for (int i = 0; i < queryList.size(); ++i) {
queries.add(i, Proto.bindQuery(checkNotNull(queryList.get(i)),
bindVarsList == null ? null : bindVarsList.get(i)));
}
Vtgate.ExecuteBatchRequest.Builder requestBuilder =
Vtgate.ExecuteBatchRequest.newBuilder()
.addAllQueries(checkNotNull(queries))
.setKeyspaceShard(keyspace)
.setTabletType(checkNotNull(tabletType))
.setAsTransaction(asTransaction)
.setOptions(Query.ExecuteOptions.newBuilder()
.setIncludedFields(includedFields));
if (ctx.getCallerId() != null) {
requestBuilder.setCallerId(ctx.getCallerId());
}
if (ctx.getCallerId() != null) {
requestBuilder.setCallerId(ctx.getCallerId());
}
return new SQLFuture<>(
transformAsync(
@ -310,13 +316,13 @@ public final class VTGateConn implements Closeable {
}
},
directExecutor()));
}
}
/**
/**
* Execute multiple keyspace ID queries as a batch.
*
* @param asTransaction If true, automatically create a transaction (per shard) that encloses all
* the batch queries.
* @param asTransaction If true, automatically create a transaction (per shard) that encloses
* all the batch queries.
*/
public SQLFuture<List<Cursor>> executeBatchShards(Context ctx,
Iterable<? extends BoundShardQuery> queries, TabletType tabletType, boolean asTransaction,
@ -352,12 +358,13 @@ public final class VTGateConn implements Closeable {
/**
* Execute multiple keyspace ID queries as a batch.
*
* @param asTransaction If true, automatically create a transaction (per shard) that encloses all
* the batch queries.
* @param asTransaction If true, automatically create a transaction (per shard) that encloses
* all the batch queries.
*/
public SQLFuture<List<Cursor>> executeBatchKeyspaceIds(Context ctx,
Iterable<? extends BoundKeyspaceIdQuery> queries, TabletType tabletType,
boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
ExecuteBatchKeyspaceIdsRequest.Builder requestBuilder =
ExecuteBatchKeyspaceIdsRequest.newBuilder()
.addAllQueries(checkNotNull(queries))
@ -386,7 +393,8 @@ public final class VTGateConn implements Closeable {
}
public Cursor streamExecute(Context ctx, String query, @Nullable Map<String, ?> bindVars,
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
StreamExecuteRequest.Builder requestBuilder =
StreamExecuteRequest.newBuilder()
.setQuery(Proto.bindQuery(checkNotNull(query), bindVars))
@ -444,7 +452,8 @@ public final class VTGateConn implements Closeable {
public Cursor streamExecuteKeyRanges(Context ctx, String query, String keyspace,
Iterable<? extends KeyRange> keyRanges, @Nullable Map<String, ?> bindVars,
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
StreamExecuteKeyRangesRequest.Builder requestBuilder = StreamExecuteKeyRangesRequest
.newBuilder()
.setQuery(Proto.bindQuery(checkNotNull(query), bindVars))

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -20,16 +20,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.util.concurrent.Futures.transformAsync;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import java.io.Closeable;
import java.io.IOException;
import java.sql.SQLDataException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
@ -47,216 +37,234 @@ import io.vitess.proto.Vtgate.SplitQueryRequest;
import io.vitess.proto.Vtgate.SplitQueryResponse;
import io.vitess.proto.Vtgate.StreamExecuteRequest;
import java.io.Closeable;
import java.io.IOException;
import java.sql.SQLDataException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
/**
* An asynchronous VTGate connection.
* <p>
* <p>All the information regarding this connection is maintained by {@code Session},
* only one operation can be in flight at a time on a given instance.
* The methods are {@code synchronized} only because the session cookie is updated asynchronously
* when the RPC response comes back.</p>
* only one operation can be in flight at a time on a given instance. The methods are {@code
* synchronized} only because the session cookie is updated asynchronously when the RPC response
* comes back.</p>
* <p>
* <p>After calling any method that returns a {@link SQLFuture}, you must wait for that future to
* complete before calling any other methods on that {@code VTGateConnection} instance.
* An {@link IllegalStateException} will be thrown if this constraint is violated.</p>
* complete before calling any other methods on that {@code VTGateConnection} instance. An {@link
* IllegalStateException} will be thrown if this constraint is violated.</p>
* <p>
* <p>All non-streaming calls on {@code VTGateConnection} are asynchronous. Use {@link VTGateBlockingConnection} if
* you want synchronous calls.</p>
* <p>All non-streaming calls on {@code VTGateConnection} are asynchronous. Use {@link
* VTGateBlockingConnection} if you want synchronous calls.</p>
*/
public class VTGateConnection implements Closeable {
private final RpcClient client;
/**
* Creates a VTGate connection with no specific parameters.
* <p>
* <p>In this mode, VTGate will use VSchema to resolve the keyspace for any unprefixed
* table names. Note that this only works if the table name is unique across all keyspaces.</p>
*
* @param client RPC connection
*/
public VTGateConnection(RpcClient client) {
this.client = checkNotNull(client);
private final RpcClient client;
/**
* Creates a VTGate connection with no specific parameters.
* <p>
* <p>In this mode, VTGate will use VSchema to resolve the keyspace for any unprefixed
* table names. Note that this only works if the table name is unique across all keyspaces.</p>
*
* @param client RPC connection
*/
public VTGateConnection(RpcClient client) {
this.client = checkNotNull(client);
}
/**
* This method calls the VTGate to execute the query.
*
* @param ctx Context on user and execution deadline if any.
* @param query Sql Query to be executed.
* @param bindVars Parameters to bind with sql.
* @param vtSession Session to be used with the call.
* @return SQL Future Cursor
* @throws SQLException If anything fails on query execution.
*/
public SQLFuture<Cursor> execute(Context ctx, String query, @Nullable Map<String, ?> bindVars,
final VTSession vtSession) throws SQLException {
synchronized (this) {
vtSession.checkCallIsAllowed("execute");
ExecuteRequest.Builder requestBuilder = ExecuteRequest.newBuilder()
.setQuery(Proto.bindQuery(checkNotNull(query), bindVars))
.setSession(vtSession.getSession());
if (ctx.getCallerId() != null) {
requestBuilder.setCallerId(ctx.getCallerId());
}
SQLFuture<Cursor> call = new SQLFuture<>(
transformAsync(client.execute(ctx, requestBuilder.build()),
new AsyncFunction<ExecuteResponse, Cursor>() {
@Override
public ListenableFuture<Cursor> apply(ExecuteResponse response) throws Exception {
vtSession.setSession(response.getSession());
Proto.checkError(response.getError());
return Futures.<Cursor>immediateFuture(new SimpleCursor(response.getResult()));
}
}, directExecutor()));
vtSession.setLastCall(call);
return call;
}
}
/**
* This method calls the VTGate to execute list of queries as a batch.
*
* @param ctx Context on user and execution deadline if any.
* @param queryList List of sql queries to be executed.
* @param bindVarsList <p>For each sql query it will provide a list of parameters to bind with. If
* provided, should match the number of sql queries.</p>
* @param vtSession Session to be used with the call.
* @return SQL Future with List of Cursors
* @throws SQLException If anything fails on query execution.
*/
public SQLFuture<List<CursorWithError>> executeBatch(Context ctx, List<String> queryList,
@Nullable List<Map<String, ?>> bindVarsList, final VTSession vtSession) throws SQLException {
return executeBatch(ctx, queryList, bindVarsList, false, vtSession);
}
/**
* This method calls the VTGate to execute list of queries as a batch.
* <p>
* <p>If asTransaction is set to <code>true</code> then query execution will not change the
* session cookie. Otherwise, query execution will become part of the session.</p>
*
* @param ctx Context on user and execution deadline if any.
* @param queryList List of sql queries to be executed.
* @param bindVarsList <p>For each sql query it will provide a list of parameters to bind with. If
* provided, should match the number of sql queries.</p>
* @param asTransaction To execute query without impacting session cookie.
* @param vtSession Session to be used with the call.
* @return SQL Future with List of Cursors
* @throws SQLException If anything fails on query execution.
*/
public SQLFuture<List<CursorWithError>> executeBatch(Context ctx, List<String> queryList,
@Nullable List<Map<String, ?>> bindVarsList, boolean asTransaction, final VTSession vtSession)
throws SQLException {
synchronized (this) {
vtSession.checkCallIsAllowed("executeBatch");
List<Query.BoundQuery> queries = new ArrayList<>();
if (null != bindVarsList && bindVarsList.size() != queryList.size()) {
throw new SQLDataException(
"Size of SQL Query list does not match the bind variables list");
}
for (int i = 0; i < queryList.size(); ++i) {
queries.add(i, Proto.bindQuery(checkNotNull(queryList.get(i)),
bindVarsList == null ? null : bindVarsList.get(i)));
}
Vtgate.ExecuteBatchRequest.Builder requestBuilder =
Vtgate.ExecuteBatchRequest.newBuilder()
.addAllQueries(checkNotNull(queries))
.setSession(vtSession.getSession())
.setAsTransaction(asTransaction);
if (ctx.getCallerId() != null) {
requestBuilder.setCallerId(ctx.getCallerId());
}
SQLFuture<List<CursorWithError>> call = new SQLFuture<>(
transformAsync(client.executeBatch(ctx, requestBuilder.build()),
new AsyncFunction<Vtgate.ExecuteBatchResponse, List<CursorWithError>>() {
@Override
public ListenableFuture<List<CursorWithError>> apply(
Vtgate.ExecuteBatchResponse response) throws Exception {
vtSession.setSession(response.getSession());
Proto.checkError(response.getError());
return Futures.immediateFuture(
Proto.fromQueryResponsesToCursorList(response.getResultsList()));
}
}, directExecutor()));
vtSession.setLastCall(call);
return call;
}
}
/**
* @param ctx Context on user and execution deadline if any.
* @param query Sql Query to be executed.
* @param bindVars Parameters to bind with sql.
* @param vtSession Session to be used with the call.
*/
public Cursor streamExecute(Context ctx, String query, @Nullable Map<String, ?> bindVars,
VTSession vtSession) throws SQLException {
StreamExecuteRequest.Builder requestBuilder =
StreamExecuteRequest.newBuilder()
.setQuery(Proto.bindQuery(checkNotNull(query), bindVars))
.setSession(vtSession.getSession());
if (ctx.getCallerId() != null) {
requestBuilder.setCallerId(ctx.getCallerId());
}
/**
* This method calls the VTGate to execute the query.
*
* @param ctx Context on user and execution deadline if any.
* @param query Sql Query to be executed.
* @param bindVars Parameters to bind with sql.
* @param vtSession Session to be used with the call.
* @return SQL Future Cursor
* @throws SQLException If anything fails on query execution.
*/
public SQLFuture<Cursor> execute(Context ctx, String query, @Nullable Map<String, ?> bindVars, final VTSession vtSession) throws SQLException {
synchronized (this) {
vtSession.checkCallIsAllowed("execute");
ExecuteRequest.Builder requestBuilder = ExecuteRequest.newBuilder()
.setQuery(Proto.bindQuery(checkNotNull(query), bindVars))
.setSession(vtSession.getSession());
return new StreamCursor(client.streamExecute(ctx, requestBuilder.build()));
}
if (ctx.getCallerId() != null) {
requestBuilder.setCallerId(ctx.getCallerId());
}
/**
* This method splits the query into small parts based on the splitColumn and Algorithm type
* provided.
*
* @param ctx Context on user and execution deadline if any.
* @param keyspace Keyspace to execute the query on.
* @param query Sql Query to be executed.
* @param bindVars Parameters to bind with sql.
* @param splitColumns Column to be used to split the data.
* @param splitCount Number of Partitions
* @param numRowsPerQueryPart Limit the number of records per query part.
* @param algorithm EQUAL_SPLITS or FULL_SCAN
* @return SQL Future with Query Parts
* @throws SQLException If anything fails on query execution.
*/
public SQLFuture<List<SplitQueryResponse.Part>> splitQuery(Context ctx, String keyspace,
String query, @Nullable Map<String, ?> bindVars, Iterable<String> splitColumns,
int splitCount, int numRowsPerQueryPart, Algorithm algorithm) throws SQLException {
SplitQueryRequest.Builder requestBuilder =
SplitQueryRequest.newBuilder()
.setKeyspace(checkNotNull(keyspace))
.setQuery(Proto.bindQuery(checkNotNull(query), bindVars))
.addAllSplitColumn(splitColumns)
.setSplitCount(splitCount)
.setNumRowsPerQueryPart(numRowsPerQueryPart)
.setAlgorithm(algorithm);
SQLFuture<Cursor> call = new SQLFuture<>(
transformAsync(client.execute(ctx, requestBuilder.build()),
new AsyncFunction<ExecuteResponse, Cursor>() {
@Override
public ListenableFuture<Cursor> apply(ExecuteResponse response) throws Exception {
vtSession.setSession(response.getSession());
Proto.checkError(response.getError());
return Futures.<Cursor>immediateFuture(new SimpleCursor(response.getResult()));
}
}, directExecutor()));
vtSession.setLastCall(call);
return call;
}
if (ctx.getCallerId() != null) {
requestBuilder.setCallerId(ctx.getCallerId());
}
/**
* This method calls the VTGate to execute list of queries as a batch.
*
* @param ctx Context on user and execution deadline if any.
* @param queryList List of sql queries to be executed.
* @param bindVarsList <p>For each sql query it will provide a list of parameters to bind with.
* If provided, should match the number of sql queries.</p>
* @param vtSession Session to be used with the call.
* @return SQL Future with List of Cursors
* @throws SQLException If anything fails on query execution.
*/
public SQLFuture<List<CursorWithError>> executeBatch(Context ctx, List<String> queryList, @Nullable List<Map<String, ?>> bindVarsList, final VTSession vtSession) throws SQLException {
return executeBatch(ctx, queryList, bindVarsList, false, vtSession);
}
return new SQLFuture<>(
transformAsync(client.splitQuery(ctx, requestBuilder.build()),
new AsyncFunction<SplitQueryResponse, List<SplitQueryResponse.Part>>() {
@Override
public ListenableFuture<List<SplitQueryResponse.Part>> apply(
SplitQueryResponse response) throws Exception {
return Futures.immediateFuture(response.getSplitsList());
}
}, directExecutor()));
}
/**
* This method calls the VTGate to execute list of queries as a batch.
* <p>
* <p>If asTransaction is set to <code>true</code> then query execution will not change the session cookie.
* Otherwise, query execution will become part of the session.</p>
*
* @param ctx Context on user and execution deadline if any.
* @param queryList List of sql queries to be executed.
* @param bindVarsList <p>For each sql query it will provide a list of parameters to bind with.
* If provided, should match the number of sql queries.</p>
* @param asTransaction To execute query without impacting session cookie.
* @param vtSession Session to be used with the call.
* @return SQL Future with List of Cursors
* @throws SQLException If anything fails on query execution.
*/
public SQLFuture<List<CursorWithError>> executeBatch(Context ctx, List<String> queryList, @Nullable List<Map<String, ?>> bindVarsList, boolean asTransaction, final VTSession vtSession) throws SQLException {
synchronized (this) {
vtSession.checkCallIsAllowed("executeBatch");
List<Query.BoundQuery> queries = new ArrayList<>();
/**
* @inheritDoc
*/
@Override
public void close() throws IOException {
client.close();
}
if (null != bindVarsList && bindVarsList.size() != queryList.size()) {
throw new SQLDataException(
"Size of SQL Query list does not match the bind variables list");
}
for (int i = 0; i < queryList.size(); ++i) {
queries.add(i, Proto.bindQuery(checkNotNull(queryList.get(i)),
bindVarsList == null ? null : bindVarsList.get(i)));
}
Vtgate.ExecuteBatchRequest.Builder requestBuilder =
Vtgate.ExecuteBatchRequest.newBuilder()
.addAllQueries(checkNotNull(queries))
.setSession(vtSession.getSession())
.setAsTransaction(asTransaction);
if (ctx.getCallerId() != null) {
requestBuilder.setCallerId(ctx.getCallerId());
}
SQLFuture<List<CursorWithError>> call = new SQLFuture<>(
transformAsync(client.executeBatch(ctx, requestBuilder.build()),
new AsyncFunction<Vtgate.ExecuteBatchResponse, List<CursorWithError>>() {
@Override
public ListenableFuture<List<CursorWithError>> apply(Vtgate.ExecuteBatchResponse response) throws Exception {
vtSession.setSession(response.getSession());
Proto.checkError(response.getError());
return Futures.immediateFuture(
Proto.fromQueryResponsesToCursorList(response.getResultsList()));
}
}, directExecutor()));
vtSession.setLastCall(call);
return call;
}
}
/**
*
* @param ctx Context on user and execution deadline if any.
* @param query Sql Query to be executed.
* @param bindVars Parameters to bind with sql.
* @param vtSession Session to be used with the call.
* @return
* @throws SQLException
*/
public Cursor streamExecute(Context ctx, String query, @Nullable Map<String, ?> bindVars, VTSession vtSession) throws SQLException {
StreamExecuteRequest.Builder requestBuilder =
StreamExecuteRequest.newBuilder()
.setQuery(Proto.bindQuery(checkNotNull(query), bindVars))
.setSession(vtSession.getSession());
if (ctx.getCallerId() != null) {
requestBuilder.setCallerId(ctx.getCallerId());
}
return new StreamCursor(client.streamExecute(ctx, requestBuilder.build()));
}
/**
* This method splits the query into small parts based on the splitColumn and Algorithm type provided.
*
* @param ctx Context on user and execution deadline if any.
* @param keyspace Keyspace to execute the query on.
* @param query Sql Query to be executed.
* @param bindVars Parameters to bind with sql.
* @param splitColumns Column to be used to split the data.
* @param splitCount Number of Partitions
* @param numRowsPerQueryPart Limit the number of records per query part.
* @param algorithm EQUAL_SPLITS or FULL_SCAN
* @return SQL Future with Query Parts
* @throws SQLException If anything fails on query execution.
*/
public SQLFuture<List<SplitQueryResponse.Part>> splitQuery(Context ctx, String keyspace, String query, @Nullable Map<String, ?> bindVars, Iterable<String> splitColumns,
int splitCount, int numRowsPerQueryPart, Algorithm algorithm) throws SQLException {
SplitQueryRequest.Builder requestBuilder =
SplitQueryRequest.newBuilder()
.setKeyspace(checkNotNull(keyspace))
.setQuery(Proto.bindQuery(checkNotNull(query), bindVars))
.addAllSplitColumn(splitColumns)
.setSplitCount(splitCount)
.setNumRowsPerQueryPart(numRowsPerQueryPart)
.setAlgorithm(algorithm);
if (ctx.getCallerId() != null) {
requestBuilder.setCallerId(ctx.getCallerId());
}
return new SQLFuture<>(
transformAsync(client.splitQuery(ctx, requestBuilder.build()),
new AsyncFunction<SplitQueryResponse, List<SplitQueryResponse.Part>>() {
@Override
public ListenableFuture<List<SplitQueryResponse.Part>> apply(SplitQueryResponse response) throws Exception {
return Futures.immediateFuture(response.getSplitsList());
}
}, directExecutor()));
}
/**
* @inheritDoc
*/
@Override
public void close() throws IOException {
client.close();
}
@Override
public String toString() {
return String.format("[VTGateConnection-%s client=%s]",
Integer.toHexString(this.hashCode()),
client.toString()
);
}
@Override
public String toString() {
return String.format("[VTGateConnection-%s client=%s]",
Integer.toHexString(this.hashCode()),
client.toString()
);
}
}

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -24,12 +24,6 @@ import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.sql.SQLDataException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import io.vitess.client.cursor.Cursor;
import io.vitess.client.cursor.CursorWithError;
@ -60,6 +54,14 @@ import io.vitess.proto.Vtgate.RollbackRequest;
import io.vitess.proto.Vtgate.RollbackResponse;
import io.vitess.proto.Vtgate.Session;
import java.sql.SQLDataException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
/**
* An asynchronous VTGate transaction session.
*
@ -82,6 +84,7 @@ import io.vitess.proto.Vtgate.Session;
*/
@Deprecated
public class VTGateTx {
private final RpcClient client;
private final String keyspace;
private Session session;
@ -94,7 +97,8 @@ public class VTGateTx {
}
public synchronized SQLFuture<Cursor> execute(Context ctx, String query, Map<String, ?> bindVars,
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
checkCallIsAllowed("execute");
ExecuteRequest.Builder requestBuilder =
ExecuteRequest.newBuilder()
@ -235,7 +239,8 @@ public class VTGateTx {
public synchronized SQLFuture<Cursor> executeEntityIds(Context ctx, String query, String keyspace,
String entityColumnName, Map<byte[], ?> entityKeyspaceIds, Map<String, ?> bindVars,
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException {
TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
checkCallIsAllowed("executeEntityIds");
ExecuteEntityIdsRequest.Builder requestBuilder = ExecuteEntityIdsRequest.newBuilder()
.setQuery(Proto.bindQuery(query, bindVars))
@ -270,34 +275,34 @@ public class VTGateTx {
return call;
}
public SQLFuture<List<CursorWithError>> executeBatch(Context ctx, List<String> queryList,
@Nullable List<Map<String, ?>> bindVarsList, TabletType tabletType,
Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
List<Query.BoundQuery> queries = new ArrayList<>();
public SQLFuture<List<CursorWithError>> executeBatch(Context ctx, List<String> queryList,
@Nullable List<Map<String, ?>> bindVarsList, TabletType tabletType,
Query.ExecuteOptions.IncludedFields includedFields)
throws SQLException {
List<Query.BoundQuery> queries = new ArrayList<>();
if (null != bindVarsList && bindVarsList.size() != queryList.size()) {
throw new SQLDataException(
"Size of SQL Query list does not match the bind variables list");
}
if (null != bindVarsList && bindVarsList.size() != queryList.size()) {
throw new SQLDataException(
"Size of SQL Query list does not match the bind variables list");
}
for (int i = 0; i < queryList.size(); ++i) {
queries.add(i, Proto.bindQuery(checkNotNull(queryList.get(i)),
bindVarsList == null ? null : bindVarsList.get(i)));
}
for (int i = 0; i < queryList.size(); ++i) {
queries.add(i, Proto.bindQuery(checkNotNull(queryList.get(i)),
bindVarsList == null ? null : bindVarsList.get(i)));
}
Vtgate.ExecuteBatchRequest.Builder requestBuilder =
Vtgate.ExecuteBatchRequest.newBuilder()
.addAllQueries(checkNotNull(queries))
.setKeyspaceShard(keyspace)
.setTabletType(checkNotNull(tabletType))
.setSession(session)
.setOptions(Query.ExecuteOptions.newBuilder()
.setIncludedFields(includedFields));
Vtgate.ExecuteBatchRequest.Builder requestBuilder =
Vtgate.ExecuteBatchRequest.newBuilder()
.addAllQueries(checkNotNull(queries))
.setKeyspaceShard(keyspace)
.setTabletType(checkNotNull(tabletType))
.setSession(session)
.setOptions(Query.ExecuteOptions.newBuilder()
.setIncludedFields(includedFields));
if (ctx.getCallerId() != null) {
requestBuilder.setCallerId(ctx.getCallerId());
}
if (ctx.getCallerId() != null) {
requestBuilder.setCallerId(ctx.getCallerId());
}
return new SQLFuture<>(
transformAsync(
@ -313,7 +318,7 @@ public class VTGateTx {
}
},
directExecutor()));
}
}
public synchronized SQLFuture<List<Cursor>> executeBatchShards(Context ctx,
Iterable<? extends BoundShardQuery> queries, TabletType tabletType,
@ -384,14 +389,14 @@ public class VTGateTx {
return call;
}
public synchronized SQLFuture<Void> commit(Context ctx) throws SQLException {
return commit(ctx, false);
}
public synchronized SQLFuture<Void> commit(Context ctx) throws SQLException {
return commit(ctx, false);
}
public synchronized SQLFuture<Void> commit(Context ctx, boolean atomic) throws SQLException {
checkCallIsAllowed("commit");
CommitRequest.Builder requestBuilder = CommitRequest.newBuilder().setSession(session)
.setAtomic(atomic);
.setAtomic(atomic);
if (ctx.getCallerId() != null) {
requestBuilder.setCallerId(ctx.getCallerId());
}

Просмотреть файл

@ -21,119 +21,122 @@ import io.vitess.proto.Vtgate;
/**
* A persistence session state for each connection.
*
*/
public class VTSession {
private Vtgate.Session session;
private SQLFuture<?> lastCall;
/**
* Create session cookie.
*
* @param target In the format keyspace@shard:tabletType. Only provide the part what needs to be set.
* @param options Additional parameters to be passed along the query to the underlying database engine.
*/
public VTSession(String target, Query.ExecuteOptions options) {
this.session = Vtgate.Session.newBuilder()
.setTargetString(null == target ? "" : target)
.setOptions(null == options ? Query.ExecuteOptions.newBuilder().build() : options)
.setAutocommit(true)
.setInTransaction(false)
.build();
}
private Vtgate.Session session;
private SQLFuture<?> lastCall;
/**
* Returns the persistent session cookie.
*
* @return Session
*/
public Vtgate.Session getSession() {
return this.session;
}
/**
* Create session cookie.
*
* @param target In the format keyspace@shard:tabletType. Only provide the part what needs to
* be set.
* @param options Additional parameters to be passed along the query to the underlying
* database engine.
*/
public VTSession(String target, Query.ExecuteOptions options) {
this.session = Vtgate.Session.newBuilder()
.setTargetString(null == target ? "" : target)
.setOptions(null == options ? Query.ExecuteOptions.newBuilder().build() : options)
.setAutocommit(true)
.setInTransaction(false)
.build();
}
/**
* This method set the session cookie returned from VTGate.
* <p>
* <p>This method is not synchronized as the callee function is synchronized.</p>
*
* @param session Updated globalSession to be set.
*/
public void setSession(Vtgate.Session session) {
this.session = session;
}
/**
* Returns the persistent session cookie.
*
* @return Session
*/
public Vtgate.Session getSession() {
return this.session;
}
/**
* Returns the current state of commit mode.
*
* @return autocommit state
*/
public boolean isAutoCommit() {
return this.session.getAutocommit();
}
/**
* This method set the session cookie returned from VTGate.
* <p>
* <p>This method is not synchronized as the callee function is synchronized.</p>
*
* @param session Updated globalSession to be set.
*/
public void setSession(Vtgate.Session session) {
this.session = session;
}
/**
* Set the auto commit state.
*
* @param autoCommit true or false
*/
public void setAutoCommit(boolean autoCommit) {
this.session = this.session.toBuilder().setAutocommit(autoCommit).build();
}
/**
* Returns the current state of commit mode.
*
* @return autocommit state
*/
public boolean isAutoCommit() {
return this.session.getAutocommit();
}
/**
* Returns whether session is maintaining any transaction or not.
*
* @return true or false based on if session cookie is maintaining any transaction.
*/
public boolean isInTransaction() {
return this.session.getShardSessionsCount() > 0;
}
/**
* Set the auto commit state.
*
* @param autoCommit true or false
*/
public void setAutoCommit(boolean autoCommit) {
this.session = this.session.toBuilder().setAutocommit(autoCommit).build();
}
/**
* Returns this session's transaction isolation level.
*
* @return Transaction Isolation Level of the Session
*/
public Query.ExecuteOptions.TransactionIsolation getTransactionIsolation() {
return this.session.getOptions().getTransactionIsolation();
}
/**
* Returns whether session is maintaining any transaction or not.
*
* @return true or false based on if session cookie is maintaining any transaction.
*/
public boolean isInTransaction() {
return this.session.getShardSessionsCount() > 0;
}
/**
* Sets this session's transaction isolation level.
*
* @param Transaction Isolation Level of the Session
*/
public void setTransactionIsolation(Query.ExecuteOptions.TransactionIsolation isolation) {
this.session = this.session.toBuilder()
.setOptions(this.session.getOptions().toBuilder()
.setTransactionIsolation(isolation)).build();
}
/**
* Returns this session's transaction isolation level.
*
* @return Transaction Isolation Level of the Session
*/
public Query.ExecuteOptions.TransactionIsolation getTransactionIsolation() {
return this.session.getOptions().getTransactionIsolation();
}
/**
* Set the last SQLFuture call made on this session.
*
* @param call - SQLFuture
*/
public void setLastCall(SQLFuture call) {
this.lastCall = call;
}
/**
* Sets this session's transaction isolation level.
*
* @param Transaction Isolation Level of the Session
*/
public void setTransactionIsolation(Query.ExecuteOptions.TransactionIsolation isolation) {
this.session = this.session.toBuilder()
.setOptions(this.session.getOptions().toBuilder()
.setTransactionIsolation(isolation)).build();
}
/**
* This method checks if the last SQLFuture call is complete or not.
* <p>
* <p>This should be called only in the start of the function
* where we modify the session cookie after the response from VTGate.
* This is to protect any possible loss of session modification like shard transaction.</p>
*
* @param call - The represents the callee function name.
* @throws IllegalStateException - Throws IllegalStateException if lastCall has not completed.
*/
public void checkCallIsAllowed(String call) throws IllegalStateException {
// Calls are not allowed to overlap.
if (lastCall != null && !lastCall.isDone()) {
throw new IllegalStateException("Can't call " + call
+ "() until the last asynchronous call is done on this transaction.");
}
/**
* Set the last SQLFuture call made on this session.
*
* @param call - SQLFuture
*/
public void setLastCall(SQLFuture call) {
this.lastCall = call;
}
/**
* This method checks if the last SQLFuture call is complete or not.
* <p>
* <p>This should be called only in the start of the function
* where we modify the session cookie after the response from VTGate. This is to protect any
* possible loss of session modification like shard transaction.</p>
*
* @param call - The represents the callee function name.
* @throws IllegalStateException - Throws IllegalStateException if lastCall has not
* completed.
*/
public void checkCallIsAllowed(String call) throws IllegalStateException {
// Calls are not allowed to overlap.
if (lastCall != null && !lastCall.isDone()) {
throw new IllegalStateException("Can't call " + call
+ "() until the last asynchronous call is done on this transaction.");
}
}
}

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -18,23 +18,23 @@ package io.vitess.client.cursor;
import static com.google.common.base.Preconditions.checkNotNull;
import io.vitess.proto.Query.Field;
import io.vitess.proto.Query.QueryResult;
import java.sql.SQLDataException;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.List;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
import io.vitess.proto.Query.Field;
import io.vitess.proto.Query.QueryResult;
/**
* Provides access to the result rows of a query.
*
* <p>{@code Cursor} wraps an underlying Vitess {@link QueryResult} object, converting column
* values from the raw result values to Java types. In the case of streaming queries, the
* {@link StreamCursor} implementation will also fetch more {@code QueryResult} objects as
* necessary.
* values from the raw result values to Java types. In the case of streaming queries, the {@link
* StreamCursor} implementation will also fetch more {@code QueryResult} objects as necessary.
*
* <p>Similar to {@link java.sql.ResultSet}, a {@code Cursor} is initially positioned before the
* first row, and the first call to {@link #next()} moves to the first row. The getter methods
@ -42,19 +42,19 @@ import io.vitess.proto.Query.QueryResult;
* should be called to free resources when done, regardless of whether all the rows were processed.
*
* <p>Each individual {@code Cursor} is not thread-safe; it must be protected if used concurrently.
* However, two cursors from the same {@link io.vitess.client.VTGateConn VTGateConn} can be
* accessed concurrently without additional synchronization.
* However, two cursors from the same {@link io.vitess.client.VTGateConn VTGateConn} can be accessed
* concurrently without additional synchronization.
*/
@NotThreadSafe
public abstract class Cursor implements AutoCloseable {
/**
* A pre-built {@link FieldMap}, shared by each {@link Row}.
*
* <p>Although {@link Cursor} is not supposed to be used by multiple threads,
* the asynchronous API makes it unavoidable that a {@code Cursor} may be created
* in one thread and then sent to another. We therefore declare {@code fieldMap}
* as {@code volatile} to guarantee the value set by the constructor is seen by
* all threads.
* the asynchronous API makes it unavoidable that a {@code Cursor} may be created in one thread
* and then sent to another. We therefore declare {@code fieldMap} as {@code volatile} to
* guarantee the value set by the constructor is seen by all threads.
*/
private volatile FieldMap fieldMap;

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -24,25 +24,25 @@ import io.vitess.proto.Vtrpc;
*/
public class CursorWithError {
private final Cursor cursor;
private final Vtrpc.RPCError error;
private final Cursor cursor;
private final Vtrpc.RPCError error;
public CursorWithError(Query.ResultWithError resultWithError) {
if (!resultWithError.hasError() ||
Vtrpc.Code.OK == resultWithError.getError().getCode()) {
this.cursor = new SimpleCursor(resultWithError.getResult());
this.error = null;
} else {
this.cursor = null;
this.error = resultWithError.getError();
}
public CursorWithError(Query.ResultWithError resultWithError) {
if (!resultWithError.hasError()
|| Vtrpc.Code.OK == resultWithError.getError().getCode()) {
this.cursor = new SimpleCursor(resultWithError.getResult());
this.error = null;
} else {
this.cursor = null;
this.error = resultWithError.getError();
}
}
public Cursor getCursor() {
return cursor;
}
public Cursor getCursor() {
return cursor;
}
public Vtrpc.RPCError getError() {
return error;
}
public Vtrpc.RPCError getError() {
return error;
}
}

Просмотреть файл

@ -20,11 +20,15 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.ImmutableList;
import io.vitess.proto.Query.Field;
import org.apache.commons.collections4.map.CaseInsensitiveMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import org.apache.commons.collections4.map.CaseInsensitiveMap;
/**
@ -37,6 +41,7 @@ import org.apache.commons.collections4.map.CaseInsensitiveMap;
* index is also used to find the value in a separate list.
*/
public class FieldMap {
private final List<Field> fields;
private final Map<String, Integer> labelMap;
private final Map<String, Integer> nameMap;

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -21,6 +21,12 @@ import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.primitives.UnsignedLong;
import com.google.protobuf.ByteString;
import io.vitess.mysql.DateTime;
import io.vitess.proto.Query;
import io.vitess.proto.Query.Field;
import io.vitess.proto.Query.Type;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
@ -33,29 +39,26 @@ import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
import io.vitess.mysql.DateTime;
import io.vitess.proto.Query;
import io.vitess.proto.Query.Field;
import io.vitess.proto.Query.Type;
import javax.annotation.concurrent.NotThreadSafe;
/**
* Type-converting wrapper around raw {@link io.vitess.proto.Query.Row} proto.
*
* <p>
* Usually you get Row objects from a {@link Cursor}, which builds them by combining
* {@link io.vitess.proto.Query.Row} with the list of {@link Field}s from the corresponding
* {@link io.vitess.proto.Query.QueryResult}.
* Usually you get Row objects from a {@link Cursor}, which builds them by combining {@link
* io.vitess.proto.Query.Row} with the list of {@link Field}s from the corresponding {@link
* io.vitess.proto.Query.QueryResult}.
*
* <p>
* Methods on {@code Row} are intended to be compatible with those on {@link java.sql.ResultSet}
* where possible. This means {@code columnIndex} values start at 1 for the first column, and
* {@code columnLabel} values are case-insensitive. If multiple columns have the same
* case-insensitive {@code columnLabel}, the earliest one will be returned.
* where possible. This means {@code columnIndex} values start at 1 for the first column, and {@code
* columnLabel} values are case-insensitive. If multiple columns have the same case-insensitive
* {@code columnLabel}, the earliest one will be returned.
*/
@NotThreadSafe
public class Row {
private final FieldMap fieldMap;
private final List<ByteString> values;
private final Query.Row rawRow;
@ -70,8 +73,8 @@ public class Row {
private volatile boolean lastGetWasNull;
/**
* Construct a Row from {@link io.vitess.proto.Query.Row} proto with a pre-built
* {@link FieldMap}.
* Construct a Row from {@link io.vitess.proto.Query.Row} proto with a pre-built {@link
* FieldMap}.
*
* <p>
* {@link Cursor} uses this to share a {@link FieldMap} among multiple rows.
@ -95,9 +98,9 @@ public class Row {
* Construct a Row manually (not from proto).
*
* <p>
* The primary purpose of this Row class is to wrap the {@link io.vitess.proto.Query.Row}
* proto, which stores values in a packed format. However, when writing tests you may want to
* create a Row from unpacked data.
* The primary purpose of this Row class is to wrap the {@link io.vitess.proto.Query.Row} proto,
* which stores values in a packed format. However, when writing tests you may want to create a
* Row from unpacked data.
*
* <p>
* Note that {@link #getRowProto()} will return null in this case, so a Row created in this way
@ -110,6 +113,102 @@ public class Row {
this.values = values;
}
private static Object convertFieldValue(Field field, ByteString value) throws SQLException {
// Note: We don't actually know the charset in which the value is encoded.
// For dates and numeric values, we just assume UTF-8 because they (hopefully) don't contain
// anything outside 7-bit ASCII, which (hopefully) is a subset of the actual charset.
// For strings, we return byte[] and the application is responsible for using the right charset.
switch (field.getType()) {
case DECIMAL:
return new BigDecimal(value.toStringUtf8());
case INT8: // fall through
case UINT8: // fall through
case INT16: // fall through
case UINT16: // fall through
case INT24: // fall through
case UINT24: // fall through
case INT32:
return Integer.valueOf(value.toStringUtf8());
case UINT32: // fall through
case INT64:
return Long.valueOf(value.toStringUtf8());
case UINT64:
return new BigInteger(value.toStringUtf8());
case FLOAT32:
return Float.valueOf(value.toStringUtf8());
case FLOAT64:
return Double.valueOf(value.toStringUtf8());
case NULL_TYPE:
return null;
case DATE:
// We don't get time zone information from the server,
// so we use the default time zone.
try {
return DateTime.parseDate(value.toStringUtf8());
} catch (ParseException exc) {
throw new SQLDataException("Can't parse DATE: " + value.toStringUtf8(), exc);
}
case TIME:
// We don't get time zone information from the server,
// so we use the default time zone.
try {
return DateTime.parseTime(value.toStringUtf8());
} catch (ParseException exc) {
throw new SQLDataException("Can't parse TIME: " + value.toStringUtf8(), exc);
}
case DATETIME: // fall through
case TIMESTAMP:
// We don't get time zone information from the server,
// so we use the default time zone.
try {
return DateTime.parseTimestamp(value.toStringUtf8());
} catch (ParseException exc) {
throw new SQLDataException("Can't parse TIMESTAMP: " + value.toStringUtf8(), exc);
}
case YEAR:
return Short.valueOf(value.toStringUtf8());
case ENUM: // fall through
case SET:
return value.toStringUtf8();
case BIT: // fall through
case TEXT: // fall through
case BLOB: // fall through
case VARCHAR: // fall through
case VARBINARY: // fall through
case CHAR: // fall through
case BINARY:
case GEOMETRY:
case JSON:
return value.toByteArray();
default:
throw new SQLDataException("unknown field type: " + field.getType());
}
}
/**
* Extract cell values from the single-buffer wire format.
*
* <p>
* See the docs for the {@code Row} message in {@code query.proto}.
*/
private static List<ByteString> extractValues(List<Long> lengths, ByteString buf) {
List<ByteString> list = new ArrayList<ByteString>(lengths.size());
int start = 0;
for (long len : lengths) {
if (len < 0) {
// This indicates a MySQL NULL value, to distinguish it from a zero-length string.
list.add((ByteString) null);
} else {
// Lengths are returned as long, but ByteString.substring() only supports int.
list.add(buf.substring(start, start + (int) len));
start += len;
}
}
return list;
}
/**
* Returns the number of columns.
*/
@ -212,8 +311,8 @@ public class Row {
* Returns the column value, or 0 if the value is SQL NULL.
*
* <p>
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or
* {@link #getObject(String,Class)}.
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link
* #getObject(String, Class)}.
*
* @param columnLabel case-insensitive column label
*/
@ -225,8 +324,8 @@ public class Row {
* Returns the column value, or 0 if the value is SQL NULL.
*
* <p>
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or
* {@link #getObject(int,Class)}.
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link #getObject(int,
* Class)}.
*
* @param columnIndex 1-based column number (0 is invalid)
*/
@ -246,8 +345,8 @@ public class Row {
* @param columnIndex 1-based column number (0 is invalid)
*/
public UnsignedLong getULong(int columnIndex) throws SQLException {
BigInteger l = getObject(columnIndex, BigInteger.class);
return l == null ? null : UnsignedLong.fromLongBits(l.longValue());
BigInteger longValue = getObject(columnIndex, BigInteger.class);
return longValue == null ? null : UnsignedLong.fromLongBits(longValue.longValue());
}
/**
@ -268,8 +367,8 @@ public class Row {
* Returns the column value, or 0 if the value is SQL NULL.
*
* <p>
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or
* {@link #getObject(String,Class)}.
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link
* #getObject(String, Class)}.
*
* @param columnLabel case-insensitive column label
*/
@ -281,8 +380,8 @@ public class Row {
* Returns the column value, or 0 if the value is SQL NULL.
*
* <p>
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or
* {@link #getObject(int,Class)}.
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link #getObject(int,
* Class)}.
*
* @param columnIndex 1-based column number (0 is invalid)
*/
@ -295,8 +394,8 @@ public class Row {
* Returns the column value, or 0 if the value is SQL NULL.
*
* <p>
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or
* {@link #getObject(String,Class)}.
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link
* #getObject(String, Class)}.
*
* @param columnLabel case-insensitive column label
*/
@ -308,8 +407,8 @@ public class Row {
* Returns the column value, or 0 if the value is SQL NULL.
*
* <p>
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or
* {@link #getObject(int,Class)}.
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link #getObject(int,
* Class)}.
*
* @param columnIndex 1-based column number (0 is invalid)
*/
@ -322,8 +421,8 @@ public class Row {
* Returns the column value, or 0 if the value is SQL NULL.
*
* <p>
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or
* {@link #getObject(String,Class)}.
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link
* #getObject(String, Class)}.
*
* @param columnLabel case-insensitive column label
*/
@ -335,8 +434,8 @@ public class Row {
* Returns the column value, or 0 if the value is SQL NULL.
*
* <p>
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or
* {@link #getObject(int,Class)}.
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link #getObject(int,
* Class)}.
*
* @param columnIndex 1-based column number (0 is invalid)
*/
@ -389,8 +488,8 @@ public class Row {
}
try {
return DateTime.parseDate(rawValue.toStringUtf8(), cal);
} catch (ParseException e) {
throw new SQLDataException("Can't parse DATE: " + rawValue.toStringUtf8(), e);
} catch (ParseException exc) {
throw new SQLDataException("Can't parse DATE: " + rawValue.toStringUtf8(), exc);
}
}
@ -438,8 +537,8 @@ public class Row {
}
try {
return DateTime.parseTime(rawValue.toStringUtf8(), cal);
} catch (ParseException e) {
throw new SQLDataException("Can't parse TIME: " + rawValue.toStringUtf8(), e);
} catch (ParseException exc) {
throw new SQLDataException("Can't parse TIME: " + rawValue.toStringUtf8(), exc);
}
}
@ -487,8 +586,8 @@ public class Row {
}
try {
return DateTime.parseTimestamp(rawValue.toStringUtf8(), cal);
} catch (ParseException e) {
throw new SQLDataException("Can't parse TIMESTAMP: " + rawValue.toStringUtf8(), e);
} catch (ParseException exc) {
throw new SQLDataException("Can't parse TIMESTAMP: " + rawValue.toStringUtf8(), exc);
}
}
@ -524,8 +623,8 @@ public class Row {
* Returns the column value, or 0 if the value is SQL NULL.
*
* <p>
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or
* {@link #getObject(String,Class)}.
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link
* #getObject(String, Class)}.
*
* @param columnLabel case-insensitive column label
*/
@ -537,8 +636,8 @@ public class Row {
* Returns the column value, or 0 if the value is SQL NULL.
*
* <p>
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or
* {@link #getObject(int,Class)}.
* To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link #getObject(int,
* Class)}.
*
* @param columnIndex 1-based column number (0 is invalid)
*/
@ -570,12 +669,15 @@ public class Row {
*/
@SuppressWarnings("unchecked") // by runtime check
public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
Object o = getObject(columnIndex);
if (o != null && !type.isInstance(o)) {
Object object = getObject(columnIndex);
if (object != null && !type.isInstance(object)) {
throw new SQLDataException(
"type mismatch, expected: " + type.getName() + ", actual: " + o.getClass().getName());
"type mismatch, expected: "
+ type.getName()
+ ", actual: "
+ object.getClass().getName());
}
return (T) o;
return (T) object;
}
/**
@ -617,11 +719,9 @@ public class Row {
* {@code wasNull()}.
*
* <p>
* As an alternative to {@code wasNull()}, you can use {@link #getObject(int,Class)} (e.g.
* {@code getObject(0, Long.class)} instead of {@code getLong(0)}) to get a wrapped {@code Long}
* value that will be {@code null} if the column value was SQL NULL.
*
* @throws SQLException
* As an alternative to {@code wasNull()}, you can use {@link #getObject(int, Class)} (e.g. {@code
* getObject(0, Long.class)} instead of {@code getLong(0)}) to get a wrapped {@code Long} value
* that will be {@code null} if the column value was SQL NULL.
*/
public boolean wasNull() throws SQLException {
// Note: lastGetWasNull is currently set only in getRawValue(),
@ -630,100 +730,4 @@ public class Row {
// checking wasNull() after each get*().
return lastGetWasNull;
}
private static Object convertFieldValue(Field field, ByteString value) throws SQLException {
// Note: We don't actually know the charset in which the value is encoded.
// For dates and numeric values, we just assume UTF-8 because they (hopefully) don't contain
// anything outside 7-bit ASCII, which (hopefully) is a subset of the actual charset.
// For strings, we return byte[] and the application is responsible for using the right charset.
switch (field.getType()) {
case DECIMAL:
return new BigDecimal(value.toStringUtf8());
case INT8: // fall through
case UINT8: // fall through
case INT16: // fall through
case UINT16: // fall through
case INT24: // fall through
case UINT24: // fall through
case INT32:
return Integer.valueOf(value.toStringUtf8());
case UINT32: // fall through
case INT64:
return Long.valueOf(value.toStringUtf8());
case UINT64:
return new BigInteger(value.toStringUtf8());
case FLOAT32:
return Float.valueOf(value.toStringUtf8());
case FLOAT64:
return Double.valueOf(value.toStringUtf8());
case NULL_TYPE:
return null;
case DATE:
// We don't get time zone information from the server,
// so we use the default time zone.
try {
return DateTime.parseDate(value.toStringUtf8());
} catch (ParseException e) {
throw new SQLDataException("Can't parse DATE: " + value.toStringUtf8(), e);
}
case TIME:
// We don't get time zone information from the server,
// so we use the default time zone.
try {
return DateTime.parseTime(value.toStringUtf8());
} catch (ParseException e) {
throw new SQLDataException("Can't parse TIME: " + value.toStringUtf8(), e);
}
case DATETIME: // fall through
case TIMESTAMP:
// We don't get time zone information from the server,
// so we use the default time zone.
try {
return DateTime.parseTimestamp(value.toStringUtf8());
} catch (ParseException e) {
throw new SQLDataException("Can't parse TIMESTAMP: " + value.toStringUtf8(), e);
}
case YEAR:
return Short.valueOf(value.toStringUtf8());
case ENUM: // fall through
case SET:
return value.toStringUtf8();
case BIT: // fall through
case TEXT: // fall through
case BLOB: // fall through
case VARCHAR: // fall through
case VARBINARY: // fall through
case CHAR: // fall through
case BINARY:
case GEOMETRY:
case JSON:
return value.toByteArray();
default:
throw new SQLDataException("unknown field type: " + field.getType());
}
}
/**
* Extract cell values from the single-buffer wire format.
*
* <p>
* See the docs for the {@code Row} message in {@code query.proto}.
*/
private static List<ByteString> extractValues(List<Long> lengths, ByteString buf) {
List<ByteString> list = new ArrayList<ByteString>(lengths.size());
int start = 0;
for (long len : lengths) {
if (len < 0) {
// This indicates a MySQL NULL value, to distinguish it from a zero-length string.
list.add((ByteString) null);
} else {
// Lengths are returned as long, but ByteString.substring() only supports int.
list.add(buf.substring(start, start + (int) len));
start += len;
}
}
return list;
}
}

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -16,20 +16,22 @@
package io.vitess.client.cursor;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
import io.vitess.proto.Query;
import io.vitess.proto.Query.Field;
import io.vitess.proto.Query.QueryResult;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
/**
* A {@link Cursor} that serves records from a single {@link QueryResult} object.
*/
@NotThreadSafe
public class SimpleCursor extends Cursor {
private final QueryResult queryResult;
private final Iterator<Query.Row> rowIterator;

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -16,24 +16,26 @@
package io.vitess.client.cursor;
import java.sql.SQLDataException;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Iterator;
import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
import io.vitess.client.StreamIterator;
import io.vitess.proto.Query;
import io.vitess.proto.Query.Field;
import io.vitess.proto.Query.QueryResult;
import java.sql.SQLDataException;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Iterator;
import java.util.List;
import javax.annotation.concurrent.NotThreadSafe;
/**
* A {@link Cursor} that serves records from the sequence of {@link QueryResult} objects
* represented by a {@link StreamIterator}.
* A {@link Cursor} that serves records from the sequence of {@link QueryResult} objects represented
* by a {@link StreamIterator}.
*/
@NotThreadSafe
public class StreamCursor extends Cursor {
private StreamIterator<QueryResult> streamIterator;
private Iterator<Query.Row> rowIterator;
@ -103,8 +105,8 @@ public class StreamCursor extends Cursor {
*
* <p>Whereas the public {@link #next()} method advances the {@link Cursor} state to the next
* {@link Row}, this method advances the internal state to the next {@link QueryResult}, which
* contains a batch of rows. Specifically, we get the next {@link QueryResult} from
* {@link #streamIterator}, and then set {@link #rowIterator} accordingly.
* contains a batch of rows. Specifically, we get the next {@link QueryResult} from {@link
* #streamIterator}, and then set {@link #rowIterator} accordingly.
*
* <p>If {@link #fields} is null, we assume the next {@link QueryResult} must contain the fields,
* and set {@link #fields} from it.

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -21,8 +21,8 @@ import java.net.InetSocketAddress;
/**
* <p>A wrapper type holding TLS-related fields for the
* {@link io.vitess.client.RpcClientFactory#createTls(InetSocketAddress, TlsOptions)} method, so that
* this method won't have an unwieldy number of direct parameters.</p>
* {@link io.vitess.client.RpcClientFactory#createTls(InetSocketAddress, TlsOptions)} method, so
* that this method won't have an unwieldy number of direct parameters.</p>
*
* <p>This path uses a builder pattern style:</p>
*
@ -39,6 +39,7 @@ import java.net.InetSocketAddress;
* </blockquote>
*/
public class TlsOptions {
private File keyStore;
private String keyStorePassword;
private String keyAlias;

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -17,6 +17,7 @@
package io.vitess.mysql;
import com.google.common.math.IntMath;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
@ -29,10 +30,11 @@ import java.util.Calendar;
* Utility methods for processing MySQL TIME, DATE, DATETIME, and TIMESTAMP.
*
* <p>These provide functionality similar to {@code valueOf()} and {@code toString()}
* in {@link java.sql.Date} et al. The difference is that these support MySQL-specific
* syntax like fractional seconds, negative times, and hours > 24 for elapsed time.
* in {@link java.sql.Date} et al. The difference is that these support MySQL-specific syntax like
* fractional seconds, negative times, and hours > 24 for elapsed time.
*/
public class DateTime {
private static final String DATE_FORMAT = "yyyy-MM-dd";
private static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
@ -139,7 +141,7 @@ public class DateTime {
}
}
}
} catch (NumberFormatException e) {
} catch (NumberFormatException exc) {
throw new ParseException("Invalid MYSQL TIME format: " + value, 0);
}
@ -165,8 +167,8 @@ public class DateTime {
* Format a {@link Time} as a MySQL TIME with the default time zone.
*
* <p>This should match {@link Time#toString()} for the values it supports.
* For MySQL-specific syntax (like fractional seconds, negative times,
* and hours > 24) the results will differ.
* For MySQL-specific syntax (like fractional seconds, negative times, and hours > 24) the results
* will differ.
*/
public static String formatTime(Time value) {
return formatTime(value, Calendar.getInstance());
@ -177,8 +179,8 @@ public class DateTime {
*
* <p>The range for TIME values is '-838:59:59.000000' to '838:59:59.000000'
* <a href="http://dev.mysql.com/doc/refman/5.6/en/time.html">[1]</a>.
* We don't enforce that range, but we do print >24 hours rather than
* wrapping around to the next day.
* We don't enforce that range, but we do print >24 hours rather than wrapping around to the next
* day.
*/
public static String formatTime(Time value, Calendar cal) {
long millis = value.getTime();
@ -243,7 +245,7 @@ public class DateTime {
}
try {
nanos = Integer.parseInt(fraction) * IntMath.pow(10, 9 - fraction.length());
} catch (NumberFormatException e) {
} catch (NumberFormatException exc) {
throw new ParseException("Invalid MySQL TIMESTAMP format: " + value, dotIndex + 1);
}
}

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -20,20 +20,23 @@ import static org.junit.Assert.assertEquals;
import com.google.common.primitives.UnsignedLong;
import com.google.protobuf.ByteString;
import io.vitess.proto.Query;
import io.vitess.proto.Query.BindVariable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import io.vitess.proto.Query;
import io.vitess.proto.Query.BindVariable;
@RunWith(value = Parameterized.class)
public class BindVarTest {
private Object input;
private BindVariable expected;
@ -50,9 +53,9 @@ public class BindVarTest {
BindVariable.newBuilder().setType(Query.Type.VARCHAR)
.setValue(ByteString.copyFromUtf8("hello world")).build()},
// Bytes
{new byte[] {1, 2, 3},
{new byte[]{1, 2, 3},
BindVariable.newBuilder().setType(Query.Type.VARBINARY)
.setValue(ByteString.copyFrom(new byte[] {1, 2, 3})).build()},
.setValue(ByteString.copyFrom(new byte[]{1, 2, 3})).build()},
// Int
{123,
BindVariable.newBuilder().setType(Query.Type.INT64)
@ -78,12 +81,12 @@ public class BindVarTest {
BindVariable.newBuilder().setType(Query.Type.FLOAT64)
.setValue(ByteString.copyFromUtf8("1.23")).build()},
// List of Bytes
{Arrays.asList(new byte[] {1, 2, 3}, new byte[] {4, 5, 6}),
{Arrays.asList(new byte[]{1, 2, 3}, new byte[]{4, 5, 6}),
BindVariable.newBuilder().setType(Query.Type.TUPLE)
.addValues(Query.Value.newBuilder().setType(Query.Type.VARBINARY)
.setValue(ByteString.copyFrom(new byte[] {1, 2, 3})).build())
.setValue(ByteString.copyFrom(new byte[]{1, 2, 3})).build())
.addValues(Query.Value.newBuilder().setType(Query.Type.VARBINARY)
.setValue(ByteString.copyFrom(new byte[] {4, 5, 6})).build())
.setValue(ByteString.copyFrom(new byte[]{4, 5, 6})).build())
.build()},
// Boolean
{true,

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -20,91 +20,95 @@ import static org.junit.Assert.assertEquals;
import com.google.common.primitives.UnsignedLong;
import com.google.protobuf.ByteString;
import io.vitess.proto.Query;
import io.vitess.proto.Vtgate.ExecuteEntityIdsRequest.EntityId;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import io.vitess.proto.Query;
import io.vitess.proto.Vtgate.ExecuteEntityIdsRequest.EntityId;
@RunWith(value = Parameterized.class)
public class EntityIdTest {
private Object input;
private EntityId expected;
private static final ByteString KEYSPACE_ID = ByteString.copyFrom(new byte[] {1, 2, 3});
private static final ByteString KEYSPACE_ID = ByteString.copyFrom(new byte[]{1, 2, 3});
@Parameters
public static Collection<Object[]> testParams() {
Object[][] params = {
// SQL NULL
{
null, EntityId.newBuilder().setKeyspaceId(KEYSPACE_ID).setType(Query.Type.NULL_TYPE).build()
},
// String
{
"hello world",
EntityId.newBuilder()
.setKeyspaceId(KEYSPACE_ID)
.setType(Query.Type.VARCHAR)
.setValue(ByteString.copyFromUtf8("hello world"))
.build()
},
// Bytes
{
new byte[] {1, 2, 3},
EntityId.newBuilder()
.setKeyspaceId(KEYSPACE_ID)
.setType(Query.Type.VARBINARY)
.setValue(ByteString.copyFrom(new byte[] {1, 2, 3}))
.build()
},
// Int
{
123,
EntityId.newBuilder()
.setKeyspaceId(KEYSPACE_ID)
.setType(Query.Type.INT64)
.setValue(ByteString.copyFromUtf8("123"))
.build()
},
{
123L,
EntityId.newBuilder()
.setKeyspaceId(KEYSPACE_ID)
.setType(Query.Type.INT64)
.setValue(ByteString.copyFromUtf8("123"))
.build()
},
// Uint
{
UnsignedLong.fromLongBits(-1),
EntityId.newBuilder()
.setKeyspaceId(KEYSPACE_ID)
.setType(Query.Type.UINT64)
.setValue(ByteString.copyFromUtf8("18446744073709551615"))
.build()
},
// Float
{
1.23f,
EntityId.newBuilder()
.setKeyspaceId(KEYSPACE_ID)
.setType(Query.Type.FLOAT64)
.setValue(ByteString.copyFromUtf8("1.23"))
.build()
},
{
1.23,
EntityId.newBuilder()
.setKeyspaceId(KEYSPACE_ID)
.setType(Query.Type.FLOAT64)
.setValue(ByteString.copyFromUtf8("1.23"))
.build()
},
// SQL NULL
{
null,
EntityId.newBuilder().setKeyspaceId(KEYSPACE_ID).setType(Query.Type.NULL_TYPE).build()
},
// String
{
"hello world",
EntityId.newBuilder()
.setKeyspaceId(KEYSPACE_ID)
.setType(Query.Type.VARCHAR)
.setValue(ByteString.copyFromUtf8("hello world"))
.build()
},
// Bytes
{
new byte[]{1, 2, 3},
EntityId.newBuilder()
.setKeyspaceId(KEYSPACE_ID)
.setType(Query.Type.VARBINARY)
.setValue(ByteString.copyFrom(new byte[]{1, 2, 3}))
.build()
},
// Int
{
123,
EntityId.newBuilder()
.setKeyspaceId(KEYSPACE_ID)
.setType(Query.Type.INT64)
.setValue(ByteString.copyFromUtf8("123"))
.build()
},
{
123L,
EntityId.newBuilder()
.setKeyspaceId(KEYSPACE_ID)
.setType(Query.Type.INT64)
.setValue(ByteString.copyFromUtf8("123"))
.build()
},
// Uint
{
UnsignedLong.fromLongBits(-1),
EntityId.newBuilder()
.setKeyspaceId(KEYSPACE_ID)
.setType(Query.Type.UINT64)
.setValue(ByteString.copyFromUtf8("18446744073709551615"))
.build()
},
// Float
{
1.23f,
EntityId.newBuilder()
.setKeyspaceId(KEYSPACE_ID)
.setType(Query.Type.FLOAT64)
.setValue(ByteString.copyFromUtf8("1.23"))
.build()
},
{
1.23,
EntityId.newBuilder()
.setKeyspaceId(KEYSPACE_ID)
.setType(Query.Type.FLOAT64)
.setValue(ByteString.copyFromUtf8("1.23"))
.build()
},
};
return Arrays.asList(params);
}

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -17,7 +17,9 @@
package io.vitess.client;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -25,6 +27,7 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class ProtoTest {
@Test
public void testGetErrno() {
final Map<String, Integer> testValues =

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -20,27 +20,6 @@ import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.protobuf.ByteString;
import java.nio.charset.StandardCharsets;
import java.sql.SQLDataException;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.sql.SQLInvalidAuthorizationSpecException;
import java.sql.SQLNonTransientException;
import java.sql.SQLRecoverableException;
import java.sql.SQLSyntaxErrorException;
import java.sql.SQLTimeoutException;
import java.sql.SQLTransientException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import io.vitess.client.cursor.Cursor;
import io.vitess.client.cursor.Row;
@ -56,6 +35,28 @@ import io.vitess.proto.Topodata.TabletType;
import io.vitess.proto.Vtgate.SplitQueryResponse;
import io.vitess.proto.Vtrpc.CallerID;
import java.nio.charset.StandardCharsets;
import java.sql.SQLDataException;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.sql.SQLInvalidAuthorizationSpecException;
import java.sql.SQLNonTransientException;
import java.sql.SQLRecoverableException;
import java.sql.SQLSyntaxErrorException;
import java.sql.SQLTimeoutException;
import java.sql.SQLTransientException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
/**
* RpcClientTest tests a given implementation of RpcClient against a mock vtgate server
* (go/cmd/vtgateclienttest).
@ -64,6 +65,7 @@ import io.vitess.proto.Vtrpc.CallerID;
* vtgateclienttest server with the necessary parameters and then set 'client'.
*/
public abstract class RpcClientTest {
protected static RpcClient client;
// ready is true when "vtgateclienttest" can accept RPCs. It is set by "waitForVtgateclienttest"
// and reset to "false" at the start of each test class by "resetReady".
@ -86,7 +88,8 @@ public abstract class RpcClientTest {
// ctx is used by all RPCs within one test method. A deadline is set to cap test execution.
// (RPCs will fail with DEADLINE_EXCEEDED if they keep using "ctx" 5 seconds from now.)
ctx = Context.getDefault().withDeadlineAfter(Duration.standardSeconds(5)).withCallerId(CALLER_ID);
ctx = Context.getDefault().withDeadlineAfter(Duration.standardSeconds(5))
.withCallerId(CALLER_ID);
}
private static final String ECHO_PREFIX = "echo://";
@ -111,20 +114,20 @@ public abstract class RpcClientTest {
private static final String SHARDS_ECHO = "[-80 80-]";
private static final List<byte[]> KEYSPACE_IDS =
Arrays.asList(new byte[] {1, 2, 3, 4}, new byte[] {5, 6, 7, 8});
Arrays.asList(new byte[]{1, 2, 3, 4}, new byte[]{5, 6, 7, 8});
private static final String KEYSPACE_IDS_ECHO = "[[1 2 3 4] [5 6 7 8]]";
private static final List<KeyRange> KEY_RANGES =
Arrays.asList(KeyRange.newBuilder().setStart(ByteString.copyFrom(new byte[] {1, 2, 3, 4}))
.setEnd(ByteString.copyFrom(new byte[] {5, 6, 7, 8})).build());
Arrays.asList(KeyRange.newBuilder().setStart(ByteString.copyFrom(new byte[]{1, 2, 3, 4}))
.setEnd(ByteString.copyFrom(new byte[]{5, 6, 7, 8})).build());
private static final String KEY_RANGES_ECHO =
"[start:\"\\001\\002\\003\\004\" end:\"\\005\\006\\007\\010\" ]";
private static final ImmutableMap<byte[], Object> ENTITY_KEYSPACE_IDS =
new ImmutableMap.Builder<byte[], Object>()
.put(new byte[] {1, 2, 3}, 123)
.put(new byte[] {4, 5, 6}, 2.5)
.put(new byte[] {7, 8, 9}, new byte[] {1, 2, 3})
.put(new byte[]{1, 2, 3}, 123)
.put(new byte[]{4, 5, 6}, 2.5)
.put(new byte[]{7, 8, 9}, new byte[]{1, 2, 3})
.build();
private static final String ENTITY_KEYSPACE_IDS_ECHO =
"[type:INT64 value:\"123\" keyspace_id:\"\\001\\002\\003\" type:FLOAT64 value:\"2.5\" keyspace_id:\"\\004\\005\\006\" type:VARBINARY value:\"\\001\\002\\003\" keyspace_id:\"\\007\\010\\t\" ]";
@ -132,12 +135,13 @@ public abstract class RpcClientTest {
private static final TabletType TABLET_TYPE = TabletType.REPLICA;
private static final String TABLET_TYPE_ECHO = TABLET_TYPE.toString();
private static final Query.ExecuteOptions.IncludedFields ALL_FIELDS = Query.ExecuteOptions.IncludedFields.ALL;
private static final String OPTIONS_ALL_FIELDS_ECHO = "included_fields:" + ALL_FIELDS.toString() + " ";
private static final String OPTIONS_ALL_FIELDS_ECHO =
"included_fields:" + ALL_FIELDS.toString() + " ";
private static final ImmutableMap<String, Object> BIND_VARS = new ImmutableMap.Builder<String, Object>()
.put("int", 123)
.put("float", 2.5)
.put("bytes", new byte[] {1, 2, 3})
.put("bytes", new byte[]{1, 2, 3})
.build();
private static final String BIND_VARS_ECHO =
"map[bytes:type:VARBINARY value:\"\\001\\002\\003\" float:type:FLOAT64 value:\"2.5\" int:type:INT64 value:\"123\" ]";
@ -187,9 +191,6 @@ public abstract class RpcClientTest {
*
* We will constantly execute the "GetSrvKeyspace" RPC and return when the binary responded
* successfully.
*
* @throws SQLException
* @throws InterruptedException
*/
private void waitForVtgateclienttest() throws SQLException, InterruptedException {
if (ready) {
@ -213,7 +214,9 @@ public abstract class RpcClientTest {
throw e;
}
System.out.format("Waiting until vtgateclienttest is ready and responds (got exception: %s)\n", rootCause);
System.out
.format("Waiting until vtgateclienttest is ready and responds (got exception: %s)\n",
rootCause);
Thread.sleep(100 /* milliseconds */);
waited = true;
}
@ -221,7 +224,8 @@ public abstract class RpcClientTest {
if (waited) {
double waitTimeSeconds = (DateTime.now().getMillis() - start.getMillis()) / 1000.0;
System.out.format("Had to wait %.1f second(s) until vtgateclienttest was ready.\n", waitTimeSeconds);
System.out.format("Had to wait %.1f second(s) until vtgateclienttest was ready.\n",
waitTimeSeconds);
}
ready = true;
}
@ -237,7 +241,8 @@ public abstract class RpcClientTest {
Assert.assertEquals(NONTX_V3_SESSION_ECHO, echo.get("session"));
echo = getEcho(
conn.executeShards(ctx, ECHO_PREFIX + QUERY, KEYSPACE, SHARDS, BIND_VARS, TABLET_TYPE, ALL_FIELDS));
conn.executeShards(ctx, ECHO_PREFIX + QUERY, KEYSPACE, SHARDS, BIND_VARS, TABLET_TYPE,
ALL_FIELDS));
Assert.assertEquals(CALLER_ID_ECHO, echo.get("callerId"));
Assert.assertEquals(ECHO_PREFIX + QUERY, echo.get("query"));
Assert.assertEquals(KEYSPACE, echo.get("keyspace"));
@ -307,7 +312,8 @@ public abstract class RpcClientTest {
public void testEchoStreamExecute() throws Exception {
Map<String, String> echo;
echo = getEcho(conn.streamExecute(ctx, ECHO_PREFIX + QUERY, BIND_VARS, TABLET_TYPE, ALL_FIELDS));
echo = getEcho(
conn.streamExecute(ctx, ECHO_PREFIX + QUERY, BIND_VARS, TABLET_TYPE, ALL_FIELDS));
Assert.assertEquals(CALLER_ID_ECHO, echo.get("callerId"));
Assert.assertEquals(ECHO_PREFIX + QUERY, echo.get("query"));
Assert.assertEquals(BIND_VARS_ECHO, echo.get("bindVars"));
@ -363,7 +369,8 @@ public abstract class RpcClientTest {
tx = conn.begin(ctx);
echo = getEcho(
tx.executeShards(ctx, ECHO_PREFIX + QUERY, KEYSPACE, SHARDS, BIND_VARS, TABLET_TYPE, ALL_FIELDS));
tx.executeShards(ctx, ECHO_PREFIX + QUERY, KEYSPACE, SHARDS, BIND_VARS, TABLET_TYPE,
ALL_FIELDS));
Assert.assertEquals(CALLER_ID_ECHO, echo.get("callerId"));
Assert.assertEquals(ECHO_PREFIX + QUERY, echo.get("query"));
Assert.assertEquals(KEYSPACE, echo.get("keyspace"));
@ -462,7 +469,7 @@ public abstract class RpcClientTest {
123,
1000,
Algorithm.FULL_SCAN)
.get(0);
.get(0);
Assert.assertEquals(expected, actual);
}
@ -471,8 +478,8 @@ public abstract class RpcClientTest {
SrvKeyspace expected = SrvKeyspace.newBuilder()
.addPartitions(KeyspacePartition.newBuilder().setServedType(TabletType.REPLICA)
.addShardReferences(ShardReference.newBuilder().setName("shard0").setKeyRange(KeyRange
.newBuilder().setStart(ByteString.copyFrom(new byte[] {0x40, 0, 0, 0, 0, 0, 0, 0}))
.setEnd(ByteString.copyFrom(new byte[] {(byte) 0x80, 0, 0, 0, 0, 0, 0, 0})).build())
.newBuilder().setStart(ByteString.copyFrom(new byte[]{0x40, 0, 0, 0, 0, 0, 0, 0}))
.setEnd(ByteString.copyFrom(new byte[]{(byte) 0x80, 0, 0, 0, 0, 0, 0, 0})).build())
.build())
.build())
.setShardingColumnName("sharding_column_name")
@ -484,6 +491,7 @@ public abstract class RpcClientTest {
}
abstract static class Executable {
abstract void execute(String query) throws Exception;
}
@ -521,6 +529,7 @@ public abstract class RpcClientTest {
}
abstract static class TransactionExecutable {
abstract void execute(VTGateBlockingTx tx, String query) throws Exception;
}
@ -602,7 +611,8 @@ public abstract class RpcClientTest {
checkExecuteErrors(new Executable() {
@Override
void execute(String query) throws Exception {
conn.executeKeyspaceIds(ctx, query, KEYSPACE, KEYSPACE_IDS, BIND_VARS, TABLET_TYPE, ALL_FIELDS);
conn.executeKeyspaceIds(ctx, query, KEYSPACE, KEYSPACE_IDS, BIND_VARS, TABLET_TYPE,
ALL_FIELDS);
}
});
checkExecuteErrors(new Executable() {
@ -647,20 +657,23 @@ public abstract class RpcClientTest {
checkStreamExecuteErrors(new Executable() {
@Override
void execute(String query) throws Exception {
conn.streamExecuteShards(ctx, query, KEYSPACE, SHARDS, BIND_VARS, TABLET_TYPE, ALL_FIELDS).next();
}
});
checkStreamExecuteErrors(new Executable() {
@Override
void execute(String query) throws Exception {
conn.streamExecuteKeyspaceIds(ctx, query, KEYSPACE, KEYSPACE_IDS, BIND_VARS, TABLET_TYPE, ALL_FIELDS)
conn.streamExecuteShards(ctx, query, KEYSPACE, SHARDS, BIND_VARS, TABLET_TYPE, ALL_FIELDS)
.next();
}
});
checkStreamExecuteErrors(new Executable() {
@Override
void execute(String query) throws Exception {
conn.streamExecuteKeyRanges(ctx, query, KEYSPACE, KEY_RANGES, BIND_VARS, TABLET_TYPE, ALL_FIELDS)
conn.streamExecuteKeyspaceIds(ctx, query, KEYSPACE, KEYSPACE_IDS, BIND_VARS, TABLET_TYPE,
ALL_FIELDS)
.next();
}
});
checkStreamExecuteErrors(new Executable() {
@Override
void execute(String query) throws Exception {
conn.streamExecuteKeyRanges(ctx, query, KEYSPACE, KEY_RANGES, BIND_VARS, TABLET_TYPE,
ALL_FIELDS)
.next();
}
});
@ -683,7 +696,8 @@ public abstract class RpcClientTest {
checkTransactionExecuteErrors(new TransactionExecutable() {
@Override
void execute(VTGateBlockingTx tx, String query) throws Exception {
tx.executeKeyspaceIds(ctx, query, KEYSPACE, KEYSPACE_IDS, BIND_VARS, TABLET_TYPE, ALL_FIELDS);
tx.executeKeyspaceIds(ctx, query, KEYSPACE, KEYSPACE_IDS, BIND_VARS, TABLET_TYPE,
ALL_FIELDS);
}
});
checkTransactionExecuteErrors(new TransactionExecutable() {
@ -703,7 +717,8 @@ public abstract class RpcClientTest {
@Override
void execute(VTGateBlockingTx tx, String query) throws Exception {
tx.executeBatchShards(ctx,
Arrays.asList(Proto.bindShardQuery(KEYSPACE, SHARDS, query, BIND_VARS)), TABLET_TYPE, ALL_FIELDS);
Arrays.asList(Proto.bindShardQuery(KEYSPACE, SHARDS, query, BIND_VARS)), TABLET_TYPE,
ALL_FIELDS);
}
});
checkTransactionExecuteErrors(new TransactionExecutable() {

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -21,6 +21,7 @@ import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.FileUtils;
import vttest.Vttest.VTTestTopology;
@ -28,6 +29,7 @@ import vttest.Vttest.VTTestTopology;
* Helper class to hold the configurations for VtGate setup used in integration tests
*/
public class TestEnv {
private VTTestTopology topology;
private String keyspace;
private String outputPath;

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -19,22 +19,25 @@ package io.vitess.client;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import io.vitess.proto.Query;
import io.vitess.proto.Topodata.TabletType;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.joda.time.Duration;
import org.junit.Assert;
import vttest.Vttest.VTTestTopology;
import io.vitess.proto.Query;
import io.vitess.proto.Topodata.TabletType;
public class TestUtil {
static final Logger logger = LogManager.getLogger(TestUtil.class.getName());
public static final String PROPERTY_KEY_CLIENT_TEST_ENV = "vitess.client.testEnv";
public static final String PROPERTY_KEY_CLIENT_TEST_PORT = "vitess.client.testEnv.portName";
@ -60,10 +63,12 @@ public class TestUtil {
continue;
}
try {
Type mapType = new TypeToken<Map<String, Object>>() {}.getType();
Type mapType = new TypeToken<Map<String, Object>>() {
}.getType();
Map<String, Object> map = new Gson().fromJson(line, mapType);
testEnv.setPythonScriptProcess(p);
testEnv.setPort(((Double)map.get(System.getProperty(PROPERTY_KEY_CLIENT_TEST_PORT))).intValue());
testEnv.setPort(
((Double) map.get(System.getProperty(PROPERTY_KEY_CLIENT_TEST_PORT))).intValue());
return;
} catch (JsonSyntaxException e) {
logger.error("JsonSyntaxException parsing setup command output: " + line, e);
@ -114,7 +119,7 @@ public class TestUtil {
// Dial timeout
Context ctx = Context.getDefault().withDeadlineAfter(Duration.millis(5000));
return new VTGateBlockingConn(
getRpcClientFactory().create(ctx, "localhost:" + testEnv.getPort()),
getRpcClientFactory().create(ctx, "localhost:" + testEnv.getPort()),
testEnv.getKeyspace());
}
@ -132,7 +137,8 @@ public class TestUtil {
bindVars.put("name", "name_" + id);
bindVars.put("age", id % 10);
bindVars.put("percent", id / 100.0);
tx.execute(ctx, insertSql, bindVars, TabletType.MASTER, Query.ExecuteOptions.IncludedFields.ALL);
tx.execute(ctx, insertSql, bindVars, TabletType.MASTER,
Query.ExecuteOptions.IncludedFields.ALL);
}
tx.commit(ctx);
}

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -18,6 +18,11 @@ package io.vitess.client.cursor;
import com.google.common.primitives.UnsignedLong;
import com.google.protobuf.ByteString;
import io.vitess.proto.Query;
import io.vitess.proto.Query.Field;
import io.vitess.proto.Query.QueryResult;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Date;
@ -28,17 +33,15 @@ import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.TimeZone;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import io.vitess.proto.Query;
import io.vitess.proto.Query.Field;
import io.vitess.proto.Query.QueryResult;
@RunWith(JUnit4.class)
public class CursorTest {
private static final Calendar GMT = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
@Test
@ -58,16 +61,20 @@ public class CursorTest {
@Test
public void testFindColumnAlternateIndexes() throws Exception {
try (Cursor cursor = new SimpleCursor(
QueryResult.newBuilder().addFields(Field.newBuilder().setName("col1").setTable("Table1").build())
.addFields(Field.newBuilder().setName("myAlias").setOrgName("boringColName").setTable("Table2").build())
.build())) {
QueryResult.newBuilder()
.addFields(Field.newBuilder().setName("col1").setTable("Table1").build())
.addFields(
Field.newBuilder().setName("myAlias").setOrgName("boringColName").setTable("Table2")
.build())
.build())) {
Assert.assertEquals(1, cursor.findColumn("Table1.col1"));
Assert.assertEquals(1, cursor.findColumn("Table1.Col1"));
Assert.assertEquals(2, cursor.findColumn("myAlias"));
Assert.assertEquals(2, cursor.findColumn("Table2.myAlias"));
Assert.assertEquals(2, cursor.findColumn("boringColName"));
try {
int idx = cursor.findColumn("Table2.boringColName"); // don't do what mysql-connector-j doesn't do
int idx = cursor
.findColumn("Table2.boringColName"); // don't do what mysql-connector-j doesn't do
Assert.fail("no exception thrown for findColumn(\"Table2.boringColName\")");
} catch (Exception ex) {
Assert.assertEquals(SQLDataException.class, ex.getClass());
@ -103,9 +110,10 @@ public class CursorTest {
try (Cursor cursor = new SimpleCursor(QueryResult.newBuilder()
.addFields(Field.newBuilder().setName("col1").setType(Query.Type.UINT64).build())
.addFields(Field.newBuilder().setName("null").setType(Query.Type.UINT64).build())
.addRows(Query.Row.newBuilder().addLengths("18446744073709551615".length()).addLengths(-1) // SQL
// NULL
.setValues(ByteString.copyFromUtf8("18446744073709551615")))
.addRows(
Query.Row.newBuilder().addLengths("18446744073709551615".length()).addLengths(-1) // SQL
// NULL
.setValues(ByteString.copyFromUtf8("18446744073709551615")))
.build())) {
Row row = cursor.next();
Assert.assertNotNull(row);
@ -121,9 +129,10 @@ public class CursorTest {
try (Cursor cursor = new SimpleCursor(QueryResult.newBuilder()
.addFields(Field.newBuilder().setName("col1").setType(Query.Type.UINT64).build())
.addFields(Field.newBuilder().setName("null").setType(Query.Type.UINT64).build())
.addRows(Query.Row.newBuilder().addLengths("18446744073709551615".length()).addLengths(-1) // SQL
// NULL
.setValues(ByteString.copyFromUtf8("18446744073709551615")))
.addRows(
Query.Row.newBuilder().addLengths("18446744073709551615".length()).addLengths(-1) // SQL
// NULL
.setValues(ByteString.copyFromUtf8("18446744073709551615")))
.build())) {
Row row = cursor.next();
Assert.assertNotNull(row);
@ -222,7 +231,7 @@ public class CursorTest {
.addFields(Field.newBuilder().setName("col1").setType(type).build())
.addFields(Field.newBuilder().setName("null").setType(type).build())
.addRows(Query.Row.newBuilder().addLengths("2008-01-02".length()).addLengths(-1) // SQL
// NULL
// NULL
.setValues(ByteString.copyFromUtf8("2008-01-02")))
.build())) {
Row row = cursor.next();
@ -291,7 +300,7 @@ public class CursorTest {
.addFields(Field.newBuilder().setName("col1").setType(type).build())
.addFields(Field.newBuilder().setName("null").setType(type).build())
.addRows(Query.Row.newBuilder().addLengths("hello world".length()).addLengths(-1) // SQL
// NULL
// NULL
.setValues(ByteString.copyFromUtf8("hello world")))
.build())) {
Row row = cursor.next();
@ -312,7 +321,7 @@ public class CursorTest {
.addFields(Field.newBuilder().setName("col1").setType(type).build())
.addFields(Field.newBuilder().setName("null").setType(type).build())
.addRows(Query.Row.newBuilder().addLengths("1234.56789".length()).addLengths(-1) // SQL
// NULL
// NULL
.setValues(ByteString.copyFromUtf8("1234.56789")))
.build())) {
Row row = cursor.next();
@ -376,9 +385,9 @@ public class CursorTest {
public void testGetBinaryInputStream() throws Exception {
ByteString travel = ByteString.copyFromUtf8("მოგზაურობა");
try (Cursor cursor = new SimpleCursor(QueryResult.newBuilder()
.addFields(Field.newBuilder().setName("col1").setType(Query.Type.INT32).build())
.addRows(Query.Row.newBuilder().addLengths(travel.size()).setValues(travel))
.build())) {
.addFields(Field.newBuilder().setName("col1").setType(Query.Type.INT32).build())
.addRows(Query.Row.newBuilder().addLengths(travel.size()).setValues(travel))
.build())) {
Row row = cursor.next();
Assert.assertNotNull(row);

Просмотреть файл

@ -1,12 +1,12 @@
/*
* Copyright 2017 Google 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.
@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
@ -27,12 +28,14 @@ import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class DateTimeTest {
private static final Calendar GMT = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
private static final Calendar PST = Calendar.getInstance(TimeZone.getTimeZone("GMT-8"));
private static final Calendar IST = Calendar.getInstance(TimeZone.getTimeZone("GMT+0530"));

Просмотреть файл

@ -70,6 +70,7 @@
<grpc.version>1.16.0</grpc.version>
<protobuf.java.version>3.6.1</protobuf.java.version>
<protobuf.protoc.version>3.6.1</protobuf.protoc.version>
<checkstyle.plugin.version>3.0.0</checkstyle.plugin.version>
</properties>
<!-- Add new dependencies here and then add it below or in your module. -->
@ -253,6 +254,28 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>${checkstyle.plugin.version}</version>
<configuration>
<configLocation>google_checks.xml</configLocation>
<suppressionsLocation>checkstyle-suppression.xml</suppressionsLocation>
<consoleOutput>true</consoleOutput>
<failsOnError>false</failsOnError>
<failOnViolation>true</failOnViolation>
<violationSeverity>warning</violationSeverity>
</configuration>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>